aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--AUTHORS6
-rw-r--r--NEWS19
-rw-r--r--README2
-rw-r--r--audio/adlib.cpp (renamed from audio/softsynth/adlib.cpp)50
-rw-r--r--audio/alsa_opl.cpp349
-rw-r--r--audio/decoders/3do.cpp343
-rw-r--r--audio/decoders/3do.h158
-rw-r--r--audio/decoders/aiff.cpp212
-rw-r--r--audio/decoders/aiff.h16
-rw-r--r--audio/decoders/wave.h10
-rw-r--r--audio/fmopl.cpp178
-rw-r--r--audio/fmopl.h154
-rw-r--r--audio/midiparser.h3
-rw-r--r--audio/midiparser_xmidi.cpp49
-rw-r--r--audio/miles.h83
-rw-r--r--audio/miles_adlib.cpp1274
-rw-r--r--audio/miles_mt32.cpp912
-rw-r--r--audio/module.mk10
-rw-r--r--audio/softsynth/opl/dosbox.cpp12
-rw-r--r--audio/softsynth/opl/dosbox.h8
-rw-r--r--audio/softsynth/opl/mame.cpp14
-rw-r--r--audio/softsynth/opl/mame.h8
-rw-r--r--common/dcl.cpp221
-rw-r--r--common/dcl.h17
-rw-r--r--common/fft.cpp4
-rwxr-xr-xconfigure901
-rw-r--r--devtools/create_project/create_project.cpp19
-rw-r--r--devtools/create_project/xcode.cpp443
-rw-r--r--devtools/create_project/xcode.h42
-rwxr-xr-xdevtools/credits.pl6
-rw-r--r--devtools/scumm-md5.txt10
-rw-r--r--doc/cz/PrectiMe426
-rw-r--r--doc/de/Liesmich412
-rw-r--r--doc/de/Neues96
-rw-r--r--doc/de/Spieletitel Original-Deutsch Deutsch-Original61
-rw-r--r--engines/access/access.cpp72
-rw-r--r--engines/access/access.h32
-rw-r--r--engines/access/amazon/amazon_game.cpp27
-rw-r--r--engines/access/amazon/amazon_logic.cpp17
-rw-r--r--engines/access/amazon/amazon_player.cpp18
-rw-r--r--engines/access/amazon/amazon_resources.cpp22
-rw-r--r--engines/access/amazon/amazon_resources.h19
-rw-r--r--engines/access/amazon/amazon_scripts.cpp10
-rw-r--r--engines/access/amazon/amazon_scripts.h2
-rw-r--r--engines/access/asurface.cpp21
-rw-r--r--engines/access/asurface.h6
-rw-r--r--engines/access/bubble_box.cpp532
-rw-r--r--engines/access/bubble_box.h34
-rw-r--r--engines/access/char.cpp38
-rw-r--r--engines/access/char.h2
-rw-r--r--engines/access/decompress.cpp44
-rw-r--r--engines/access/decompress.h3
-rw-r--r--engines/access/detection_tables.h17
-rw-r--r--engines/access/inventory.cpp52
-rw-r--r--engines/access/inventory.h1
-rw-r--r--engines/access/martian/martian_game.cpp340
-rw-r--r--engines/access/martian/martian_game.h29
-rw-r--r--engines/access/martian/martian_player.cpp67
-rw-r--r--engines/access/martian/martian_player.h47
-rw-r--r--engines/access/martian/martian_resources.cpp388
-rw-r--r--engines/access/martian/martian_resources.h32
-rw-r--r--engines/access/martian/martian_room.cpp90
-rw-r--r--engines/access/martian/martian_room.h5
-rw-r--r--engines/access/martian/martian_scripts.cpp293
-rw-r--r--engines/access/martian/martian_scripts.h9
-rw-r--r--engines/access/module.mk1
-rw-r--r--engines/access/player.cpp113
-rw-r--r--engines/access/player.h31
-rw-r--r--engines/access/resources.cpp38
-rw-r--r--engines/access/resources.h15
-rw-r--r--engines/access/room.cpp241
-rw-r--r--engines/access/room.h5
-rw-r--r--engines/access/screen.cpp25
-rw-r--r--engines/access/screen.h11
-rw-r--r--engines/access/scripts.cpp412
-rw-r--r--engines/access/scripts.h24
-rw-r--r--engines/access/sound.cpp113
-rw-r--r--engines/access/sound.h8
-rw-r--r--engines/access/video.cpp20
-rw-r--r--engines/access/video.h2
-rw-r--r--engines/agi/detection_tables.h1
-rw-r--r--engines/agi/graphics.cpp5
-rw-r--r--engines/agi/preagi_mickey.cpp2
-rw-r--r--engines/agos/agos.cpp4
-rw-r--r--engines/agos/detection_tables.h8
-rw-r--r--engines/agos/drivers/accolade/adlib.cpp883
-rw-r--r--engines/agos/drivers/accolade/driverfile.cpp166
-rw-r--r--engines/agos/drivers/accolade/mididriver.h44
-rw-r--r--engines/agos/drivers/accolade/mt32.cpp278
-rw-r--r--engines/agos/drivers/simon1/adlib.cpp516
-rw-r--r--engines/agos/drivers/simon1/adlib.h118
-rw-r--r--engines/agos/gfx.cpp7
-rw-r--r--engines/agos/input.cpp1
-rw-r--r--engines/agos/midi.cpp436
-rw-r--r--engines/agos/midi.h23
-rw-r--r--engines/agos/midiparser_s1d.cpp39
-rw-r--r--engines/agos/module.mk4
-rw-r--r--engines/agos/res_snd.cpp5
-rw-r--r--engines/agos/sound.cpp4
-rw-r--r--engines/agos/zones.cpp3
-rw-r--r--engines/bbvs/sound.h2
-rw-r--r--engines/cine/sound.cpp127
-rw-r--r--engines/cruise/sound.cpp114
-rw-r--r--engines/fullpipe/motion.cpp2
-rw-r--r--engines/gob/gob.cpp3
-rw-r--r--engines/gob/map_v2.cpp4
-rw-r--r--engines/gob/sound/adlib.cpp133
-rw-r--r--engines/gob/sound/adlib.h32
-rw-r--r--engines/gob/sound/adlplayer.cpp11
-rw-r--r--engines/gob/sound/adlplayer.h4
-rw-r--r--engines/gob/sound/musplayer.cpp22
-rw-r--r--engines/gob/sound/musplayer.h3
-rw-r--r--engines/gob/sound/sound.cpp18
-rw-r--r--engines/gob/sound/sound.h1
-rw-r--r--engines/groovie/music.cpp57
-rw-r--r--engines/groovie/music.h2
-rw-r--r--engines/kyra/sound_adlib.cpp57
-rw-r--r--engines/lure/res.h1
-rw-r--r--engines/made/made.cpp2
-rw-r--r--engines/made/music.cpp52
-rw-r--r--engines/made/music.h3
-rw-r--r--engines/made/pmvplayer.cpp5
-rw-r--r--engines/made/screenfx.cpp2
-rw-r--r--engines/made/sound.cpp26
-rw-r--r--engines/made/sound.h17
-rw-r--r--engines/mads/hotspots.cpp5
-rw-r--r--engines/mads/nebular/sound_nebular.cpp62
-rw-r--r--engines/mads/nebular/sound_nebular.h60
-rw-r--r--engines/mads/phantom/game_phantom.cpp90
-rw-r--r--engines/mads/phantom/globals_phantom.h96
-rw-r--r--engines/mads/phantom/phantom_scenes.cpp2
-rw-r--r--engines/mads/phantom/phantom_scenes.h40
-rw-r--r--engines/mads/phantom/phantom_scenes1.cpp104
-rw-r--r--engines/mads/phantom/phantom_scenes1.h15
-rw-r--r--engines/mads/sound.cpp3
-rw-r--r--engines/mads/sound.h2
-rw-r--r--engines/mohawk/console.cpp31
-rw-r--r--engines/mohawk/detection_tables.h16
-rw-r--r--engines/mohawk/livingbooks.cpp87
-rw-r--r--engines/mohawk/livingbooks_code.cpp55
-rw-r--r--engines/mohawk/livingbooks_code.h5
-rw-r--r--engines/mohawk/myst_areas.cpp24
-rw-r--r--engines/mohawk/myst_stacks/channelwood.cpp34
-rw-r--r--engines/mohawk/myst_stacks/dni.cpp56
-rw-r--r--engines/mohawk/myst_stacks/intro.cpp23
-rw-r--r--engines/mohawk/myst_stacks/mechanical.cpp64
-rw-r--r--engines/mohawk/myst_stacks/myst.cpp238
-rw-r--r--engines/mohawk/myst_stacks/stoneship.cpp62
-rw-r--r--engines/mohawk/riven.cpp22
-rw-r--r--engines/mohawk/riven_external.cpp85
-rw-r--r--engines/mohawk/riven_scripts.cpp8
-rw-r--r--engines/mohawk/video.cpp553
-rw-r--r--engines/mohawk/video.h313
-rw-r--r--engines/mortevielle/detection_tables.h17
-rw-r--r--engines/mortevielle/menu.cpp9
-rw-r--r--engines/parallaction/adlib.cpp38
-rw-r--r--engines/pegasus/sound.cpp10
-rw-r--r--engines/queen/midiadlib.cpp139
-rw-r--r--engines/queen/midiadlib.h128
-rw-r--r--engines/queen/music.cpp8
-rw-r--r--engines/saga/detection_tables.h33
-rw-r--r--engines/saga/introproc_ihnm.cpp4
-rw-r--r--engines/saga/introproc_ite.cpp70
-rw-r--r--engines/saga/music.cpp48
-rw-r--r--engines/saga/music.h3
-rw-r--r--engines/saga/saga.cpp6
-rw-r--r--engines/saga/saga.h4
-rw-r--r--engines/saga/scene.cpp13
-rw-r--r--engines/saga/scene.h2
-rw-r--r--engines/saga/script.cpp6
-rw-r--r--engines/saga/sndres.cpp15
-rw-r--r--engines/sci/detection.cpp4
-rw-r--r--engines/sci/detection_tables.h10
-rw-r--r--engines/sci/engine/kfile.cpp5
-rw-r--r--engines/sci/engine/script.cpp13
-rw-r--r--engines/sci/graphics/transitions.cpp62
-rw-r--r--engines/sci/graphics/transitions.h1
-rw-r--r--engines/sci/sound/audio.cpp17
-rw-r--r--engines/sci/sound/drivers/adlib.cpp53
-rw-r--r--engines/scumm/detection_tables.h2
-rw-r--r--engines/scumm/players/player_ad.cpp48
-rw-r--r--engines/scumm/players/player_ad.h20
-rw-r--r--engines/scumm/scumm-md5.h12
-rw-r--r--engines/scumm/scumm.cpp3
-rw-r--r--engines/scumm/scumm.h1
-rw-r--r--engines/scumm/string.cpp7
-rw-r--r--engines/sherlock/animation.cpp152
-rw-r--r--engines/sherlock/animation.h7
-rw-r--r--engines/sherlock/debugger.cpp111
-rw-r--r--engines/sherlock/debugger.h37
-rw-r--r--engines/sherlock/detection.cpp15
-rw-r--r--engines/sherlock/detection_tables.h75
-rw-r--r--engines/sherlock/events.cpp177
-rw-r--r--engines/sherlock/events.h57
-rw-r--r--engines/sherlock/fixed_text.cpp38
-rw-r--r--engines/sherlock/fixed_text.h66
-rw-r--r--engines/sherlock/fonts.cpp211
-rw-r--r--engines/sherlock/fonts.h105
-rw-r--r--engines/sherlock/image_file.cpp1098
-rw-r--r--engines/sherlock/image_file.h208
-rw-r--r--engines/sherlock/inventory.cpp291
-rw-r--r--engines/sherlock/inventory.h61
-rw-r--r--engines/sherlock/journal.cpp1244
-rw-r--r--engines/sherlock/journal.h77
-rw-r--r--engines/sherlock/map.cpp543
-rw-r--r--engines/sherlock/map.h135
-rw-r--r--engines/sherlock/module.mk38
-rw-r--r--engines/sherlock/music.cpp476
-rw-r--r--engines/sherlock/music.h62
-rw-r--r--engines/sherlock/objects.cpp1630
-rw-r--r--engines/sherlock/objects.h333
-rw-r--r--engines/sherlock/people.cpp624
-rw-r--r--engines/sherlock/people.h135
-rw-r--r--engines/sherlock/resources.cpp326
-rw-r--r--engines/sherlock/resources.h63
-rw-r--r--engines/sherlock/saveload.cpp266
-rw-r--r--engines/sherlock/saveload.h45
-rw-r--r--engines/sherlock/scalpel/3do/movie_decoder.cpp510
-rw-r--r--engines/sherlock/scalpel/3do/movie_decoder.h127
-rw-r--r--engines/sherlock/scalpel/drivers/adlib.cpp161
-rw-r--r--engines/sherlock/scalpel/drivers/mididriver.h16
-rw-r--r--engines/sherlock/scalpel/drivers/mt32.cpp282
-rw-r--r--engines/sherlock/scalpel/scalpel.cpp1002
-rw-r--r--engines/sherlock/scalpel/scalpel.h30
-rw-r--r--engines/sherlock/scalpel/scalpel_darts.cpp (renamed from engines/sherlock/scalpel/darts.cpp)35
-rw-r--r--engines/sherlock/scalpel/scalpel_darts.h (renamed from engines/sherlock/scalpel/darts.h)14
-rw-r--r--engines/sherlock/scalpel/scalpel_debugger.cpp91
-rw-r--r--engines/sherlock/scalpel/scalpel_debugger.h54
-rw-r--r--engines/sherlock/scalpel/scalpel_fixed_text.cpp377
-rw-r--r--engines/sherlock/scalpel/scalpel_fixed_text.h108
-rw-r--r--engines/sherlock/scalpel/scalpel_inventory.cpp296
-rw-r--r--engines/sherlock/scalpel/scalpel_inventory.h74
-rw-r--r--engines/sherlock/scalpel/scalpel_journal.cpp636
-rw-r--r--engines/sherlock/scalpel/scalpel_journal.h99
-rw-r--r--engines/sherlock/scalpel/scalpel_map.cpp596
-rw-r--r--engines/sherlock/scalpel/scalpel_map.h173
-rw-r--r--engines/sherlock/scalpel/scalpel_people.cpp567
-rw-r--r--engines/sherlock/scalpel/scalpel_people.h130
-rw-r--r--engines/sherlock/scalpel/scalpel_saveload.cpp261
-rw-r--r--engines/sherlock/scalpel/scalpel_saveload.h71
-rw-r--r--engines/sherlock/scalpel/scalpel_scene.cpp445
-rw-r--r--engines/sherlock/scalpel/scalpel_scene.h43
-rw-r--r--engines/sherlock/scalpel/scalpel_screen.cpp93
-rw-r--r--engines/sherlock/scalpel/scalpel_screen.h66
-rw-r--r--engines/sherlock/scalpel/scalpel_talk.cpp935
-rw-r--r--engines/sherlock/scalpel/scalpel_talk.h143
-rw-r--r--engines/sherlock/scalpel/scalpel_user_interface.cpp324
-rw-r--r--engines/sherlock/scalpel/scalpel_user_interface.h14
-rw-r--r--engines/sherlock/scalpel/settings.cpp6
-rw-r--r--engines/sherlock/scalpel/tsage/logo.cpp226
-rw-r--r--engines/sherlock/scalpel/tsage/logo.h29
-rw-r--r--engines/sherlock/scene.cpp1375
-rw-r--r--engines/sherlock/scene.h116
-rw-r--r--engines/sherlock/screen.cpp334
-rw-r--r--engines/sherlock/screen.h94
-rw-r--r--engines/sherlock/sherlock.cpp52
-rw-r--r--engines/sherlock/sherlock.h42
-rw-r--r--engines/sherlock/sound.cpp211
-rw-r--r--engines/sherlock/sound.h46
-rw-r--r--engines/sherlock/surface.cpp130
-rw-r--r--engines/sherlock/surface.h48
-rw-r--r--engines/sherlock/talk.cpp1451
-rw-r--r--engines/sherlock/talk.h281
-rw-r--r--engines/sherlock/tattoo/tattoo.cpp152
-rw-r--r--engines/sherlock/tattoo/tattoo.h56
-rw-r--r--engines/sherlock/tattoo/tattoo_darts.cpp1000
-rw-r--r--engines/sherlock/tattoo/tattoo_darts.h173
-rw-r--r--engines/sherlock/tattoo/tattoo_debugger.cpp (renamed from engines/zvision/detection.h)24
-rw-r--r--engines/sherlock/tattoo/tattoo_debugger.h44
-rw-r--r--engines/sherlock/tattoo/tattoo_fixed_text.cpp211
-rw-r--r--engines/sherlock/tattoo/tattoo_fixed_text.h134
-rw-r--r--engines/sherlock/tattoo/tattoo_inventory.cpp63
-rw-r--r--engines/sherlock/tattoo/tattoo_inventory.h48
-rw-r--r--engines/sherlock/tattoo/tattoo_journal.cpp939
-rw-r--r--engines/sherlock/tattoo/tattoo_journal.h114
-rw-r--r--engines/sherlock/tattoo/tattoo_map.cpp434
-rw-r--r--engines/sherlock/tattoo/tattoo_map.h93
-rw-r--r--engines/sherlock/tattoo/tattoo_people.cpp1503
-rw-r--r--engines/sherlock/tattoo/tattoo_people.h281
-rw-r--r--engines/sherlock/tattoo/tattoo_resources.cpp329
-rw-r--r--engines/sherlock/tattoo/tattoo_resources.h42
-rw-r--r--engines/sherlock/tattoo/tattoo_scene.cpp876
-rw-r--r--engines/sherlock/tattoo/tattoo_scene.h96
-rw-r--r--engines/sherlock/tattoo/tattoo_talk.cpp1013
-rw-r--r--engines/sherlock/tattoo/tattoo_talk.h143
-rw-r--r--engines/sherlock/tattoo/tattoo_user_interface.cpp965
-rw-r--r--engines/sherlock/tattoo/tattoo_user_interface.h210
-rw-r--r--engines/sherlock/tattoo/widget_base.cpp375
-rw-r--r--engines/sherlock/tattoo/widget_base.h147
-rw-r--r--engines/sherlock/tattoo/widget_credits.cpp215
-rw-r--r--engines/sherlock/tattoo/widget_credits.h89
-rw-r--r--engines/sherlock/tattoo/widget_files.cpp428
-rw-r--r--engines/sherlock/tattoo/widget_files.h87
-rw-r--r--engines/sherlock/tattoo/widget_foolscap.cpp299
-rw-r--r--engines/sherlock/tattoo/widget_foolscap.h82
-rw-r--r--engines/sherlock/tattoo/widget_inventory.cpp789
-rw-r--r--engines/sherlock/tattoo/widget_inventory.h158
-rw-r--r--engines/sherlock/tattoo/widget_lab.cpp198
-rw-r--r--engines/sherlock/tattoo/widget_lab.h66
-rw-r--r--engines/sherlock/tattoo/widget_options.cpp388
-rw-r--r--engines/sherlock/tattoo/widget_options.h69
-rw-r--r--engines/sherlock/tattoo/widget_password.cpp210
-rw-r--r--engines/sherlock/tattoo/widget_password.h68
-rw-r--r--engines/sherlock/tattoo/widget_quit.cpp155
-rw-r--r--engines/sherlock/tattoo/widget_quit.h57
-rw-r--r--engines/sherlock/tattoo/widget_talk.cpp470
-rw-r--r--engines/sherlock/tattoo/widget_talk.h95
-rw-r--r--engines/sherlock/tattoo/widget_text.cpp228
-rw-r--r--engines/sherlock/tattoo/widget_text.h80
-rw-r--r--engines/sherlock/tattoo/widget_tooltip.cpp223
-rw-r--r--engines/sherlock/tattoo/widget_tooltip.h89
-rw-r--r--engines/sherlock/tattoo/widget_verbs.cpp314
-rw-r--r--engines/sherlock/tattoo/widget_verbs.h72
-rw-r--r--engines/sherlock/user_interface.cpp155
-rw-r--r--engines/sherlock/user_interface.h28
-rw-r--r--engines/sky/music/adlibchannel.cpp12
-rw-r--r--engines/sky/music/adlibchannel.h5
-rw-r--r--engines/sky/music/adlibmusic.cpp56
-rw-r--r--engines/sky/music/adlibmusic.h18
-rw-r--r--engines/sword25/fmv/movieplayer.cpp2
-rw-r--r--engines/tinsel/music.cpp81
-rw-r--r--engines/tinsel/music.h4
-rw-r--r--engines/tinsel/tinsel.cpp5
-rw-r--r--engines/toltecs/music.cpp38
-rw-r--r--engines/toltecs/music.h1
-rw-r--r--engines/tony/window.cpp2
-rw-r--r--engines/tsage/detection_tables.h3
-rw-r--r--engines/tsage/globals.cpp5
-rw-r--r--engines/tsage/sherlock/sherlock_logo.cpp11
-rw-r--r--engines/tsage/sherlock/sherlock_logo.h2
-rw-r--r--engines/tsage/sound.cpp42
-rw-r--r--engines/tsage/sound.h24
-rw-r--r--engines/tsage/tsage.cpp2
-rw-r--r--engines/wintermute/base/base_script_holder.cpp2
-rw-r--r--engines/zvision/configure.engine2
-rw-r--r--engines/zvision/core/clock.h10
-rw-r--r--engines/zvision/core/console.cpp2
-rw-r--r--engines/zvision/detection.cpp271
-rw-r--r--engines/zvision/detection_tables.h277
-rw-r--r--engines/zvision/file/save_manager.cpp2
-rw-r--r--engines/zvision/graphics/render_manager.cpp2
-rw-r--r--engines/zvision/scripting/actions.cpp137
-rw-r--r--engines/zvision/scripting/actions.h1
-rw-r--r--engines/zvision/scripting/controls/input_control.cpp1
-rw-r--r--engines/zvision/scripting/controls/input_control.h3
-rw-r--r--engines/zvision/scripting/menu.cpp74
-rw-r--r--engines/zvision/scripting/menu.h16
-rw-r--r--engines/zvision/sound/zork_raw.cpp7
-rw-r--r--engines/zvision/text/string_manager.h1
-rw-r--r--engines/zvision/text/text.h3
-rw-r--r--engines/zvision/zvision.cpp13
-rw-r--r--engines/zvision/zvision.h30
-rw-r--r--gui/credits.h5
-rw-r--r--gui/debugger.cpp54
-rw-r--r--gui/debugger.h5
-rw-r--r--gui/launcher.cpp4
-rw-r--r--gui/options.cpp6
-rw-r--r--gui/themes/translations.datbin470115 -> 468738 bytes
-rw-r--r--image/codecs/cinepak.cpp6
-rw-r--r--image/codecs/cinepak.h4
-rw-r--r--po/POTFILES1
-rw-r--r--po/be_BY.po566
-rw-r--r--po/ca_ES.po567
-rw-r--r--po/cs_CZ.po621
-rw-r--r--po/da_DA.po566
-rw-r--r--po/de_DE.po696
-rw-r--r--po/es_ES.po567
-rw-r--r--po/eu.po563
-rw-r--r--po/fi_FI.po564
-rw-r--r--po/fr_FR.po565
-rw-r--r--po/gl_ES.po567
-rw-r--r--po/hu_HU.po565
-rw-r--r--po/it_IT.po566
-rw-r--r--po/nb_NO.po565
-rw-r--r--po/nl_NL.po547
-rw-r--r--po/nn_NO.po554
-rw-r--r--po/pl_PL.po566
-rw-r--r--po/pt_BR.po563
-rw-r--r--po/ru_RU.po566
-rw-r--r--po/scummvm.pot544
-rw-r--r--po/se_SE.po566
-rw-r--r--po/uk_UA.po567
382 files changed, 48924 insertions, 15905 deletions
diff --git a/AUTHORS b/AUTHORS
index 370f4e9401..e2cad187fe 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -259,7 +259,7 @@ ScummVM Team
Einar Johan T. Somaaen
Tobia Tesan
- ZVision:
+ Z-Vision:
Adrian Astley
Filippos Karapetis
Anton Yarcev
@@ -485,7 +485,7 @@ Other contributions
German:
Simon Sawatzki
- Lothar Serra Mari - (retired)
+ Lothar Serra Mari
Hungarian:
Alex Bevilacqua
@@ -670,7 +670,7 @@ Special thanks to
Jimmi Thogersen - For ScummRev, and much obscure code/documentation
Tristan - For additional work on the original MT-32 emulator
James Woodcock - Soundtrack enhancements
- Anton Yartsev - For the original re-implementation of the ZVision
+ Anton Yartsev - For the original re-implementation of the Z-Vision
engine
Tony Warriner and everyone at Revolution Software Ltd. for sharing with us
diff --git a/NEWS b/NEWS
index 1422ec2818..f9aac42b6e 100644
--- a/NEWS
+++ b/NEWS
@@ -11,6 +11,9 @@ For a more comprehensive changelog of the latest experimental code, see:
General:
- Updated Munt MT-32 emulation code to version 1.5.0.
+ 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).
@@ -19,14 +22,25 @@ For a more comprehensive changelog of the latest experimental code, see:
AGOS:
- Fixed arpeggio effect used in music of Amiga version of Elvira 1.
- Fixed loading and saving progress in the PC version of Waxworks.
+ - Fixed verb area been removed in Amiga versions of Simon the Sorcerer 1.
+ - Added Accolade AdLib & MT-32 music drivers for the games:
+ Elvira 1, Elvira 2, Waxworks and Simon the Sorcerer 1 demo.
+ - Added Simon the Sorcerer 1 AdLib output. This vastly improves the AdLib
+ output and makes it closer to the original.
Broken Sword 1:
- - Fix speech endianness detection on big endian systems for the mac
+ - 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.
+ MADE:
+ - Improved AdLib music support in Return to Zork.
+
+ SAGA:
+ - Improved AdLib music support.
+
SCI:
- Handling of music priority has been greatly improved.
- A lot of fixes for original game script bugs that also occurred when
@@ -39,6 +53,9 @@ For a more comprehensive changelog of the latest experimental code, see:
- It is now possible to play Maniac Mansion from within Day of the
Tentacle, with a few caveats. See README for details.
+ Tinsel:
+ - Improved AdLib music support in Discworld 1.
+
1.7.0 (2014-07-21)
New Games:
- Added support for Chivalry is Not Dead.
diff --git a/README b/README
index 7116536222..2a1d7c390e 100644
--- a/README
+++ b/README
@@ -373,7 +373,7 @@ SCI Games by Sierra Entertainment:
Wintermute Games:
Chivalry is Not Dead [chivalry]
-ZVISION Games by Activision:
+Z-Vision Games by Activision:
Zork Nemesis: The Forbidden Lands [znemesis]
Zork: Grand Inquisitor [zgi]
diff --git a/audio/softsynth/adlib.cpp b/audio/adlib.cpp
index 98519343b4..f609164495 100644
--- a/audio/softsynth/adlib.cpp
+++ b/audio/adlib.cpp
@@ -927,18 +927,20 @@ static void createLookupTable() {
//
////////////////////////////////////////
-class MidiDriver_ADLIB : public MidiDriver_Emulated {
+class MidiDriver_ADLIB : public MidiDriver {
friend class AdLibPart;
friend class AdLibPercussionChannel;
public:
- MidiDriver_ADLIB(Audio::Mixer *mixer);
+ MidiDriver_ADLIB();
int open();
void close();
void send(uint32 b);
void send(byte channel, uint32 b); // Supports higher than channel 15
uint32 property(int prop, uint32 param);
+ bool isOpen() const { return _isOpen; }
+ uint32 getBaseTempo() { return 1000000 / OPL::OPL::kDefaultCallbackFrequency; }
void setPitchBendRange(byte channel, uint range);
void sysEx_customInstrument(byte channel, uint32 type, const byte *instr);
@@ -946,10 +948,7 @@ public:
MidiChannel *allocateChannel();
MidiChannel *getPercussionChannel() { return &_percussion; } // Percussion partially supported
-
- // AudioStream API
- bool isStereo() const { return _opl->isStereo(); }
- int getRate() const { return _mixer->getOutputRate(); }
+ virtual void setTimerCallback(void *timerParam, Common::TimerManager::TimerProc timerProc);
private:
bool _scummSmallHeader; // FIXME: This flag controls a special mode for SCUMM V3 games
@@ -963,6 +962,9 @@ private:
byte *_regCacheSecondary;
#endif
+ Common::TimerManager::TimerProc _adlibTimerProc;
+ void *_adlibTimerParam;
+
int _timerCounter;
uint16 _channelTable2[9];
@@ -974,7 +976,8 @@ private:
AdLibPart _parts[32];
AdLibPercussionChannel _percussion;
- void generateSamples(int16 *buf, int len);
+ bool _isOpen;
+
void onTimer();
void partKeyOn(AdLibPart *part, const AdLibInstrument *instr, byte note, byte velocity, const AdLibInstrument *second, byte pan);
void partKeyOff(AdLibPart *part, byte note);
@@ -1376,8 +1379,7 @@ void AdLibPercussionChannel::sysEx_customInstrument(uint32 type, const byte *ins
// MidiDriver method implementations
-MidiDriver_ADLIB::MidiDriver_ADLIB(Audio::Mixer *mixer)
- : MidiDriver_Emulated(mixer) {
+MidiDriver_ADLIB::MidiDriver_ADLIB() {
uint i;
_scummSmallHeader = false;
@@ -1403,13 +1405,16 @@ MidiDriver_ADLIB::MidiDriver_ADLIB(Audio::Mixer *mixer)
_timerIncrease = 0xD69;
_timerThreshold = 0x411B;
_opl = 0;
+ _adlibTimerProc = 0;
+ _adlibTimerParam = 0;
+ _isOpen = false;
}
int MidiDriver_ADLIB::open() {
if (_isOpen)
return MERR_ALREADY_OPEN;
- MidiDriver_Emulated::open();
+ _isOpen = true;
int i;
AdLibVoice *voice;
@@ -1434,7 +1439,7 @@ int MidiDriver_ADLIB::open() {
_opl3Mode = false;
}
#endif
- _opl->init(getRate());
+ _opl->init();
_regCache = (byte *)calloc(256, 1);
@@ -1452,8 +1457,7 @@ int MidiDriver_ADLIB::open() {
}
#endif
- _mixer->playStream(Audio::Mixer::kPlainSoundType, &_mixerSoundHandle, this, -1, Audio::Mixer::kMaxChannelVolume, 0, DisposeAfterUse::NO, true);
-
+ _opl->start(new Common::Functor0Mem<void, MidiDriver_ADLIB>(this, &MidiDriver_ADLIB::onTimer));
return 0;
}
@@ -1462,7 +1466,8 @@ void MidiDriver_ADLIB::close() {
return;
_isOpen = false;
- _mixer->stopHandle(_mixerSoundHandle);
+ // Stop the OPL timer
+ _opl->stop();
uint i;
for (i = 0; i < ARRAYSIZE(_voices); ++i) {
@@ -1616,14 +1621,10 @@ void MidiDriver_ADLIB::adlibWriteSecondary(byte reg, byte value) {
}
#endif
-void MidiDriver_ADLIB::generateSamples(int16 *data, int len) {
- if (_opl->isStereo()) {
- len *= 2;
- }
- _opl->readBuffer(data, len);
-}
-
void MidiDriver_ADLIB::onTimer() {
+ if (_adlibTimerProc)
+ (*_adlibTimerProc)(_adlibTimerParam);
+
_timerCounter += _timerIncrease;
while (_timerCounter >= _timerThreshold) {
_timerCounter -= _timerThreshold;
@@ -1655,6 +1656,11 @@ void MidiDriver_ADLIB::onTimer() {
}
}
+void MidiDriver_ADLIB::setTimerCallback(void *timerParam, Common::TimerManager::TimerProc timerProc) {
+ _adlibTimerProc = timerProc;
+ _adlibTimerParam = timerParam;
+}
+
void MidiDriver_ADLIB::mcOff(AdLibVoice *voice) {
AdLibVoice *tmp;
@@ -2300,7 +2306,7 @@ MusicDevices AdLibEmuMusicPlugin::getDevices() const {
}
Common::Error AdLibEmuMusicPlugin::createInstance(MidiDriver **mididriver, MidiDriver::DeviceHandle) const {
- *mididriver = new MidiDriver_ADLIB(g_system->getMixer());
+ *mididriver = new MidiDriver_ADLIB();
return Common::kNoError;
}
diff --git a/audio/alsa_opl.cpp b/audio/alsa_opl.cpp
new file mode 100644
index 0000000000..6b9e48e987
--- /dev/null
+++ b/audio/alsa_opl.cpp
@@ -0,0 +1,349 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+/* OPL implementation for hardware OPL using ALSA Direct FM API.
+ *
+ * Caveats and limitations:
+ * - Pretends to be a softsynth (emitting silence).
+ * - Dual OPL2 mode requires OPL3 hardware.
+ * - Every register write leads to a series of register writes on the hardware,
+ * due to the lack of direct register access in the ALSA Direct FM API.
+ * - No timers
+ */
+
+#define FORBIDDEN_SYMBOL_ALLOW_ALL
+#include "common/scummsys.h"
+
+#include "common/debug.h"
+#include "common/str.h"
+#include "audio/fmopl.h"
+
+#include <sys/ioctl.h>
+#include <alsa/asoundlib.h>
+#include <sound/asound_fm.h>
+
+namespace OPL {
+namespace ALSA {
+
+class OPL : public ::OPL::RealOPL {
+private:
+ enum {
+ kOpl2Voices = 9,
+ kVoices = 18,
+ kOpl2Operators = 18,
+ kOperators = 36
+ };
+
+ Config::OplType _type;
+ int _iface;
+ snd_hwdep_t *_opl;
+ snd_dm_fm_voice _oper[kOperators];
+ snd_dm_fm_note _voice[kVoices];
+ snd_dm_fm_params _params;
+ int index[2];
+ static const int voiceToOper0[kVoices];
+ static const int regOffsetToOper[0x20];
+
+ void writeOplReg(int c, int r, int v);
+ void clear();
+
+public:
+ OPL(Config::OplType type);
+ ~OPL();
+
+ bool init();
+ void reset();
+
+ void write(int a, int v);
+ byte read(int a);
+
+ void writeReg(int r, int v);
+};
+
+const int OPL::voiceToOper0[OPL::kVoices] =
+ { 0, 1, 2, 6, 7, 8, 12, 13, 14, 18, 19, 20, 24, 25, 26, 30, 31, 32 };
+
+const int OPL::regOffsetToOper[0x20] =
+ { 0, 1, 2, 3, 4, 5, -1, -1, 6, 7, 8, 9, 10, 11, -1, -1,
+ 12, 13, 14, 15, 16, 17, -1, -1, -1, -1, -1, -1, -1, -1, -1 };
+
+OPL::OPL(Config::OplType type) : _type(type), _opl(nullptr), _iface(0) {
+}
+
+OPL::~OPL() {
+ stop();
+
+ if (_opl) {
+ snd_hwdep_ioctl(_opl, SNDRV_DM_FM_IOCTL_RESET, nullptr);
+ snd_hwdep_close(_opl);
+ }
+}
+
+void OPL::clear() {
+ index[0] = index[1] = 0;
+
+ memset(_oper, 0, sizeof(_oper));
+ memset(_voice, 0, sizeof(_voice));
+ memset(&_params, 0, sizeof(_params));
+
+ for (int i = 0; i < kOperators; ++i) {
+ _oper[i].op = (i / 3) % 2;
+ _oper[i].voice = (i / 6) * 3 + (i % 3);
+ }
+
+ for (int i = 0; i < kVoices; ++i)
+ _voice[i].voice = i;
+
+ // For OPL3 hardware we need to set up the panning in OPL2 modes
+ if (_iface == SND_HWDEP_IFACE_OPL3) {
+ if (_type == Config::kDualOpl2) {
+ for (int i = 0; i < kOpl2Operators; ++i)
+ _oper[i].left = 1; // FIXME below
+ for (int i = kOpl2Operators; i < kOperators; ++i)
+ _oper[i].right = 1;
+ } else if (_type == Config::kOpl2) {
+ for (int i = 0; i < kOpl2Operators; ++i) {
+ _oper[i].left = 1;
+ _oper[i].right = 1;
+ }
+ }
+ }
+}
+
+bool OPL::init() {
+ clear();
+
+ int card = -1;
+ snd_ctl_t *ctl;
+ snd_hwdep_info_t *info;
+ snd_hwdep_info_alloca(&info);
+
+ int iface = SND_HWDEP_IFACE_OPL3;
+ if (_type == Config::kOpl2)
+ iface = SND_HWDEP_IFACE_OPL2;
+
+ // Look for OPL hwdep interface
+ while (!snd_card_next(&card) && card >= 0) {
+ int dev = -1;
+ Common::String name = Common::String::format("hw:%d", card);
+
+ if (snd_ctl_open(&ctl, name.c_str(), 0) < 0)
+ continue;
+
+ while (!snd_ctl_hwdep_next_device(ctl, &dev) && dev >= 0) {
+ name = Common::String::format("hw:%d,%d", card, dev);
+
+ if (snd_hwdep_open(&_opl, name.c_str(), SND_HWDEP_OPEN_WRITE) < 0)
+ continue;
+
+ if (!snd_hwdep_info(_opl, info)) {
+ int found = snd_hwdep_info_get_iface(info);
+ // OPL3 can be used for (Dual) OPL2 mode
+ if (found == iface || found == SND_HWDEP_IFACE_OPL3) {
+ snd_ctl_close(ctl);
+ _iface = found;
+ reset();
+ return true;
+ }
+ }
+
+ // Wrong interface, try next device
+ snd_hwdep_close(_opl);
+ _opl = nullptr;
+ }
+
+ snd_ctl_close(ctl);
+ }
+
+ return false;
+}
+
+void OPL::reset() {
+ snd_hwdep_ioctl(_opl, SNDRV_DM_FM_IOCTL_RESET, nullptr);
+ if (_iface == SND_HWDEP_IFACE_OPL3)
+ snd_hwdep_ioctl(_opl, SNDRV_DM_FM_IOCTL_SET_MODE, (void *)SNDRV_DM_FM_MODE_OPL3);
+
+ clear();
+
+ // Sync up with the hardware
+ snd_hwdep_ioctl(_opl, SNDRV_DM_FM_IOCTL_SET_PARAMS, (void *)&_params);
+ for (uint i = 0; i < (_iface == SND_HWDEP_IFACE_OPL3 ? kVoices : kOpl2Voices); ++i)
+ snd_hwdep_ioctl(_opl, SNDRV_DM_FM_IOCTL_PLAY_NOTE, (void *)&_voice[i]);
+ for (uint i = 0; i < (_iface == SND_HWDEP_IFACE_OPL3 ? kOperators : kOpl2Operators); ++i)
+ snd_hwdep_ioctl(_opl, SNDRV_DM_FM_IOCTL_SET_VOICE, (void *)&_oper[i]);
+}
+
+void OPL::write(int port, int val) {
+ val &= 0xff;
+ int chip = (port & 2) >> 1;
+
+ if (port & 1) {
+ switch(_type) {
+ case Config::kOpl2:
+ writeOplReg(0, index[0], val);
+ break;
+ case Config::kDualOpl2:
+ if (port & 8) {
+ writeOplReg(0, index[0], val);
+ writeOplReg(1, index[1], val);
+ } else
+ writeOplReg(chip, index[chip], val);
+ break;
+ case Config::kOpl3:
+ writeOplReg(chip, index[chip], val);
+ }
+ } else {
+ switch(_type) {
+ case Config::kOpl2:
+ index[0] = val;
+ break;
+ case Config::kDualOpl2:
+ if (port & 8) {
+ index[0] = val;
+ index[1] = val;
+ } else
+ index[chip] = val;
+ break;
+ case Config::kOpl3:
+ index[chip] = val;
+ }
+ }
+}
+
+byte OPL::read(int port) {
+ return 0;
+}
+
+void OPL::writeReg(int r, int v) {
+ switch (_type) {
+ case Config::kOpl2:
+ writeOplReg(0, r, v);
+ break;
+ case Config::kDualOpl2:
+ writeOplReg(0, r, v);
+ writeOplReg(1, r, v);
+ break;
+ case Config::kOpl3:
+ writeOplReg(r >= 0x100, r & 0xff, v);
+ }
+}
+
+void OPL::writeOplReg(int c, int r, int v) {
+ if (r == 0x04 && c == 1 && _type == Config::kOpl3) {
+ snd_hwdep_ioctl(_opl, SNDRV_DM_FM_IOCTL_SET_CONNECTION, reinterpret_cast<void *>(v & 0x3f));
+ } else if (r == 0x08 && c == 0) {
+ _params.kbd_split = (v >> 6) & 0x1;
+ snd_hwdep_ioctl(_opl, SNDRV_DM_FM_IOCTL_SET_PARAMS, (void *)&_params);
+ } else if (r == 0xbd && c == 0) {
+ _params.hihat = v & 0x1;
+ _params.cymbal = (v >> 1) & 0x1;
+ _params.tomtom = (v >> 2) & 0x1;
+ _params.snare = (v >> 3) & 0x1;
+ _params.bass = (v >> 4) & 0x1;
+ _params.rhythm = (v >> 5) & 0x1;
+ _params.vib_depth = (v >> 6) & 0x1;
+ _params.am_depth = (v >> 7) & 0x1;
+ snd_hwdep_ioctl(_opl, SNDRV_DM_FM_IOCTL_SET_PARAMS, (void *)&_params);
+ } else if (r < 0xa0 || r >= 0xe0) {
+ // Operator
+ int idx = regOffsetToOper[r & 0x1f];
+
+ if (idx == -1)
+ return;
+
+ if (c == 1)
+ idx += kOpl2Operators;
+
+ switch (r & 0xf0) {
+ case 0x20:
+ case 0x30:
+ _oper[idx].harmonic = v & 0xf;
+ _oper[idx].kbd_scale = (v >> 4) & 0x1;
+ _oper[idx].do_sustain = (v >> 5) & 0x1;
+ _oper[idx].vibrato = (v >> 6) & 0x1;
+ _oper[idx].am = (v >> 7) & 0x1;
+ snd_hwdep_ioctl(_opl, SNDRV_DM_FM_IOCTL_SET_VOICE, (void *)&_oper[idx]);
+ break;
+ case 0x40:
+ case 0x50:
+ _oper[idx].volume = ~v & 0x3f;
+ _oper[idx].scale_level = (v >> 6) & 0x3;
+ snd_hwdep_ioctl(_opl, SNDRV_DM_FM_IOCTL_SET_VOICE, (void *)&_oper[idx]);
+ break;
+ case 0x60:
+ case 0x70:
+ _oper[idx].decay = v & 0xf;
+ _oper[idx].attack = (v >> 4) & 0xf;
+ snd_hwdep_ioctl(_opl, SNDRV_DM_FM_IOCTL_SET_VOICE, (void *)&_oper[idx]);
+ break;
+ case 0x80:
+ case 0x90:
+ _oper[idx].release = v & 0xf;
+ _oper[idx].sustain = (v >> 4) & 0xf;
+ snd_hwdep_ioctl(_opl, SNDRV_DM_FM_IOCTL_SET_VOICE, (void *)&_oper[idx]);
+ break;
+ case 0xe0:
+ case 0xf0:
+ _oper[idx].waveform = v & (_type == Config::kOpl3 ? 0x7 : 0x3);
+ snd_hwdep_ioctl(_opl, SNDRV_DM_FM_IOCTL_SET_VOICE, (void *)&_oper[idx]);
+ }
+ } else {
+ // Voice
+ int idx = r & 0xf;
+
+ if (idx >= kOpl2Voices)
+ return;
+
+ if (c == 1)
+ idx += kOpl2Voices;
+
+ int opIdx = voiceToOper0[idx];
+
+ switch (r & 0xf0) {
+ case 0xa0:
+ _voice[idx].fnum = (_voice[idx].fnum & 0x300) | (v & 0xff);
+ snd_hwdep_ioctl(_opl, SNDRV_DM_FM_IOCTL_PLAY_NOTE, (void *)&_voice[idx]);
+ break;
+ case 0xb0:
+ _voice[idx].fnum = ((v << 8) & 0x300) | (_voice[idx].fnum & 0xff);
+ _voice[idx].octave = (v >> 2) & 0x7;
+ _voice[idx].key_on = (v >> 5) & 0x1;
+ snd_hwdep_ioctl(_opl, SNDRV_DM_FM_IOCTL_PLAY_NOTE, (void *)&_voice[idx]);
+ break;
+ case 0xc0:
+ _oper[opIdx].connection = _oper[opIdx + 3].connection = v & 0x1;
+ _oper[opIdx].feedback = _oper[opIdx + 3].feedback = (v >> 1) & 0x7;
+ if (_type == Config::kOpl3) {
+ _oper[opIdx].left = _oper[opIdx + 3].left = (v >> 4) & 0x1;
+ _oper[opIdx].right = _oper[opIdx + 3].right = (v >> 5) & 0x1;
+ }
+ snd_hwdep_ioctl(_opl, SNDRV_DM_FM_IOCTL_SET_VOICE, (void *)&_oper[opIdx]);
+ }
+ }
+}
+
+OPL *create(Config::OplType type) {
+ return new OPL(type);
+}
+
+} // End of namespace ALSA
+} // End of namespace OPL
diff --git a/audio/decoders/3do.cpp b/audio/decoders/3do.cpp
new file mode 100644
index 0000000000..6d558d4c8c
--- /dev/null
+++ b/audio/decoders/3do.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.
+ *
+ */
+
+#include "common/textconsole.h"
+#include "common/stream.h"
+#include "common/util.h"
+
+#include "audio/decoders/3do.h"
+#include "audio/decoders/raw.h"
+#include "audio/decoders/adpcm_intern.h"
+
+namespace Audio {
+
+// Reuses ADPCM table
+#define audio_3DO_ADP4_stepSizeTable Ima_ADPCMStream::_imaTable
+#define audio_3DO_ADP4_stepSizeIndex ADPCMStream::_stepAdjustTable
+
+RewindableAudioStream *make3DO_ADP4AudioStream(Common::SeekableReadStream *stream, uint16 sampleRate, bool stereo, uint32 *audioLengthMSecsPtr, DisposeAfterUse::Flag disposeAfterUse, audio_3DO_ADP4_PersistentSpace *persistentSpace) {
+ if (stereo) {
+ warning("make3DO_ADP4Stream(): stereo currently not supported");
+ return 0;
+ }
+
+ if (audioLengthMSecsPtr) {
+ // Caller requires the milliseconds of audio
+ uint32 audioLengthMSecs = stream->size() * 2 * 1000 / sampleRate; // 1 byte == 2 16-bit sample
+ if (stereo) {
+ audioLengthMSecs /= 2;
+ }
+ *audioLengthMSecsPtr = audioLengthMSecs;
+ }
+
+ return new Audio3DO_ADP4_Stream(stream, sampleRate, stereo, disposeAfterUse, persistentSpace);
+}
+
+Audio3DO_ADP4_Stream::Audio3DO_ADP4_Stream(Common::SeekableReadStream *stream, uint16 sampleRate, bool stereo, DisposeAfterUse::Flag disposeAfterUse, audio_3DO_ADP4_PersistentSpace *persistentSpace)
+ : _sampleRate(sampleRate), _stereo(stereo),
+ _stream(stream, disposeAfterUse) {
+
+ _callerDecoderData = persistentSpace;
+ memset(&_initialDecoderData, 0, sizeof(_initialDecoderData));
+ _initialRead = true;
+
+ reset();
+}
+
+void Audio3DO_ADP4_Stream::reset() {
+ memcpy(&_curDecoderData, &_initialDecoderData, sizeof(_curDecoderData));
+ _streamBytesLeft = _stream->size();
+ _stream->seek(0);
+}
+
+bool Audio3DO_ADP4_Stream::rewind() {
+ reset();
+ return true;
+}
+
+int16 Audio3DO_ADP4_Stream::decodeSample(byte compressedNibble) {
+ int16 currentStep = audio_3DO_ADP4_stepSizeTable[_curDecoderData.stepIndex];
+ int32 decodedSample = _curDecoderData.lastSample;
+ int16 delta = currentStep >> 3;
+
+ if (compressedNibble & 1)
+ delta += currentStep >> 2;
+
+ if (compressedNibble & 2)
+ delta += currentStep >> 1;
+
+ if (compressedNibble & 4)
+ delta += currentStep;
+
+ if (compressedNibble & 8) {
+ decodedSample -= delta;
+ } else {
+ decodedSample += delta;
+ }
+
+ _curDecoderData.lastSample = CLIP<int32>(decodedSample, -32768, 32767);
+
+ _curDecoderData.stepIndex += audio_3DO_ADP4_stepSizeIndex[compressedNibble & 0x07];
+ _curDecoderData.stepIndex = CLIP<int16>(_curDecoderData.stepIndex, 0, ARRAYSIZE(audio_3DO_ADP4_stepSizeTable) - 1);
+
+ return _curDecoderData.lastSample;
+}
+
+// Writes the requested amount (or less) of samples into buffer and returns the amount of samples, that got written
+int Audio3DO_ADP4_Stream::readBuffer(int16 *buffer, const int numSamples) {
+ int8 byteCache[AUDIO_3DO_CACHE_SIZE];
+ int8 *byteCachePtr = NULL;
+ int byteCacheSize = 0;
+ int requestedBytesLeft = 0;
+ int decodedSamplesCount = 0;
+
+ int8 compressedByte = 0;
+
+ if (endOfData())
+ return 0; // no more bytes left
+
+ if (_callerDecoderData) {
+ // copy caller decoder data over
+ memcpy(&_curDecoderData, _callerDecoderData, sizeof(_curDecoderData));
+ if (_initialRead) {
+ _initialRead = false;
+ memcpy(&_initialDecoderData, &_curDecoderData, sizeof(_initialDecoderData));
+ }
+ }
+
+ requestedBytesLeft = numSamples >> 1; // 1 byte for 2 16-bit sample
+ if (requestedBytesLeft > _streamBytesLeft)
+ requestedBytesLeft = _streamBytesLeft; // not enough bytes left
+
+ // in case caller requests an uneven amount of samples, we will return an even amount
+
+ // buffering, so that direct decoding of files and such runs way faster
+ while (requestedBytesLeft) {
+ if (requestedBytesLeft > AUDIO_3DO_CACHE_SIZE) {
+ byteCacheSize = AUDIO_3DO_CACHE_SIZE;
+ } else {
+ byteCacheSize = requestedBytesLeft;
+ }
+
+ requestedBytesLeft -= byteCacheSize;
+ _streamBytesLeft -= byteCacheSize;
+
+ // Fill our byte cache
+ _stream->read(byteCache, byteCacheSize);
+
+ byteCachePtr = byteCache;
+
+ // Mono
+ while (byteCacheSize) {
+ compressedByte = *byteCachePtr++;
+ byteCacheSize--;
+
+ buffer[decodedSamplesCount] = decodeSample(compressedByte >> 4);
+ decodedSamplesCount++;
+ buffer[decodedSamplesCount] = decodeSample(compressedByte & 0x0f);
+ decodedSamplesCount++;
+ }
+ }
+
+ if (_callerDecoderData) {
+ // copy caller decoder data back
+ memcpy(_callerDecoderData, &_curDecoderData, sizeof(_curDecoderData));
+ }
+
+ return decodedSamplesCount;
+}
+
+// ============================================================================
+static int16 audio_3DO_SDX2_SquareTable[256] = {
+ -32768,-32258,-31752,-31250,-30752,-30258,-29768,-29282,-28800,-28322,
+ -27848,-27378,-26912,-26450,-25992,-25538,-25088,-24642,-24200,-23762,
+ -23328,-22898,-22472,-22050,-21632,-21218,-20808,-20402,-20000,-19602,
+ -19208,-18818,-18432,-18050,-17672,-17298,-16928,-16562,-16200,-15842,
+ -15488,-15138,-14792,-14450,-14112,-13778,-13448,-13122,-12800,-12482,
+ -12168,-11858,-11552,-11250,-10952,-10658,-10368,-10082, -9800, -9522,
+ -9248, -8978, -8712, -8450, -8192, -7938, -7688, -7442, -7200, -6962,
+ -6728, -6498, -6272, -6050, -5832, -5618, -5408, -5202, -5000, -4802,
+ -4608, -4418, -4232, -4050, -3872, -3698, -3528, -3362, -3200, -3042,
+ -2888, -2738, -2592, -2450, -2312, -2178, -2048, -1922, -1800, -1682,
+ -1568, -1458, -1352, -1250, -1152, -1058, -968, -882, -800, -722,
+ -648, -578, -512, -450, -392, -338, -288, -242, -200, -162,
+ -128, -98, -72, -50, -32, -18, -8, -2, 0, 2,
+ 8, 18, 32, 50, 72, 98, 128, 162, 200, 242,
+ 288, 338, 392, 450, 512, 578, 648, 722, 800, 882,
+ 968, 1058, 1152, 1250, 1352, 1458, 1568, 1682, 1800, 1922,
+ 2048, 2178, 2312, 2450, 2592, 2738, 2888, 3042, 3200, 3362,
+ 3528, 3698, 3872, 4050, 4232, 4418, 4608, 4802, 5000, 5202,
+ 5408, 5618, 5832, 6050, 6272, 6498, 6728, 6962, 7200, 7442,
+ 7688, 7938, 8192, 8450, 8712, 8978, 9248, 9522, 9800, 10082,
+ 10368, 10658, 10952, 11250, 11552, 11858, 12168, 12482, 12800, 13122,
+ 13448, 13778, 14112, 14450, 14792, 15138, 15488, 15842, 16200, 16562,
+ 16928, 17298, 17672, 18050, 18432, 18818, 19208, 19602, 20000, 20402,
+ 20808, 21218, 21632, 22050, 22472, 22898, 23328, 23762, 24200, 24642,
+ 25088, 25538, 25992, 26450, 26912, 27378, 27848, 28322, 28800, 29282,
+ 29768, 30258, 30752, 31250, 31752, 32258
+};
+
+Audio3DO_SDX2_Stream::Audio3DO_SDX2_Stream(Common::SeekableReadStream *stream, uint16 sampleRate, bool stereo, DisposeAfterUse::Flag disposeAfterUse, audio_3DO_SDX2_PersistentSpace *persistentSpace)
+ : _sampleRate(sampleRate), _stereo(stereo),
+ _stream(stream, disposeAfterUse) {
+
+ _callerDecoderData = persistentSpace;
+ memset(&_initialDecoderData, 0, sizeof(_initialDecoderData));
+ _initialRead = true;
+
+ reset();
+}
+
+void Audio3DO_SDX2_Stream::reset() {
+ memcpy(&_curDecoderData, &_initialDecoderData, sizeof(_curDecoderData));
+ _streamBytesLeft = _stream->size();
+ _stream->seek(0);
+}
+
+bool Audio3DO_SDX2_Stream::rewind() {
+ reset();
+ return true;
+}
+
+// Writes the requested amount (or less) of samples into buffer and returns the amount of samples, that got written
+int Audio3DO_SDX2_Stream::readBuffer(int16 *buffer, const int numSamples) {
+ int8 byteCache[AUDIO_3DO_CACHE_SIZE];
+ int8 *byteCachePtr = NULL;
+ int byteCacheSize = 0;
+ int requestedBytesLeft = numSamples; // 1 byte per 16-bit sample
+ int decodedSamplesCount = 0;
+
+ int8 compressedByte = 0;
+ uint8 squareTableOffset = 0;
+ int16 decodedSample = 0;
+
+ if (endOfData())
+ return 0; // no more bytes left
+
+ if (_stereo) {
+ // We expect numSamples to be even in case of Stereo audio
+ assert((numSamples & 1) == 0);
+ }
+
+ if (_callerDecoderData) {
+ // copy caller decoder data over
+ memcpy(&_curDecoderData, _callerDecoderData, sizeof(_curDecoderData));
+ if (_initialRead) {
+ _initialRead = false;
+ memcpy(&_initialDecoderData, &_curDecoderData, sizeof(_initialDecoderData));
+ }
+ }
+
+ requestedBytesLeft = numSamples;
+ if (requestedBytesLeft > _streamBytesLeft)
+ requestedBytesLeft = _streamBytesLeft; // not enough bytes left
+
+ // buffering, so that direct decoding of files and such runs way faster
+ while (requestedBytesLeft) {
+ if (requestedBytesLeft > AUDIO_3DO_CACHE_SIZE) {
+ byteCacheSize = AUDIO_3DO_CACHE_SIZE;
+ } else {
+ byteCacheSize = requestedBytesLeft;
+ }
+
+ requestedBytesLeft -= byteCacheSize;
+ _streamBytesLeft -= byteCacheSize;
+
+ // Fill our byte cache
+ _stream->read(byteCache, byteCacheSize);
+
+ byteCachePtr = byteCache;
+
+ if (!_stereo) {
+ // Mono
+ while (byteCacheSize) {
+ compressedByte = *byteCachePtr++;
+ byteCacheSize--;
+ squareTableOffset = compressedByte + 128;
+
+ if (!(compressedByte & 1))
+ _curDecoderData.lastSample1 = 0;
+
+ decodedSample = _curDecoderData.lastSample1 + audio_3DO_SDX2_SquareTable[squareTableOffset];
+ _curDecoderData.lastSample1 = decodedSample;
+
+ buffer[decodedSamplesCount] = decodedSample;
+ decodedSamplesCount++;
+ }
+ } else {
+ // Stereo
+ while (byteCacheSize) {
+ compressedByte = *byteCachePtr++;
+ byteCacheSize--;
+ squareTableOffset = compressedByte + 128;
+
+ if (!(decodedSamplesCount & 1)) {
+ // First channel
+ if (!(compressedByte & 1))
+ _curDecoderData.lastSample1 = 0;
+
+ decodedSample = _curDecoderData.lastSample1 + audio_3DO_SDX2_SquareTable[squareTableOffset];
+ _curDecoderData.lastSample1 = decodedSample;
+ } else {
+ // Second channel
+ if (!(compressedByte & 1))
+ _curDecoderData.lastSample2 = 0;
+
+ decodedSample = _curDecoderData.lastSample2 + audio_3DO_SDX2_SquareTable[squareTableOffset];
+ _curDecoderData.lastSample2 = decodedSample;
+ }
+
+ buffer[decodedSamplesCount] = decodedSample;
+ decodedSamplesCount++;
+ }
+ }
+ }
+
+ if (_callerDecoderData) {
+ // copy caller decoder data back
+ memcpy(_callerDecoderData, &_curDecoderData, sizeof(_curDecoderData));
+ }
+
+ return decodedSamplesCount;
+}
+
+RewindableAudioStream *make3DO_SDX2AudioStream(Common::SeekableReadStream *stream, uint16 sampleRate, bool stereo, uint32 *audioLengthMSecsPtr, DisposeAfterUse::Flag disposeAfterUse, audio_3DO_SDX2_PersistentSpace *persistentSpace) {
+ if (stereo) {
+ if (stream->size() & 1) {
+ warning("make3DO_SDX2Stream(): stereo data is uneven size");
+ return 0;
+ }
+ }
+
+ if (audioLengthMSecsPtr) {
+ // Caller requires the milliseconds of audio
+ uint32 audioLengthMSecs = stream->size() * 1000 / sampleRate; // 1 byte == 1 16-bit sample
+ if (stereo) {
+ audioLengthMSecs /= 2;
+ }
+ *audioLengthMSecsPtr = audioLengthMSecs;
+ }
+
+ return new Audio3DO_SDX2_Stream(stream, sampleRate, stereo, disposeAfterUse, persistentSpace);
+}
+
+} // End of namespace Audio
diff --git a/audio/decoders/3do.h b/audio/decoders/3do.h
new file mode 100644
index 0000000000..7524358543
--- /dev/null
+++ b/audio/decoders/3do.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.
+ *
+ */
+
+/**
+ * @file
+ * Sound decoder used in engines:
+ * - sherlock (3DO version of Serrated Scalpel)
+ */
+
+#ifndef AUDIO_3DO_SDX2_H
+#define AUDIO_3DO_SDX2_H
+
+#include "common/scummsys.h"
+#include "common/types.h"
+#include "common/substream.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
+
+// persistent spaces
+struct audio_3DO_ADP4_PersistentSpace {
+ int16 lastSample;
+ int16 stepIndex;
+};
+
+struct audio_3DO_SDX2_PersistentSpace {
+ int16 lastSample1;
+ int16 lastSample2;
+};
+
+class Audio3DO_ADP4_Stream : public RewindableAudioStream {
+public:
+ Audio3DO_ADP4_Stream(Common::SeekableReadStream *stream, uint16 sampleRate, bool stereo, DisposeAfterUse::Flag disposeAfterUse, audio_3DO_ADP4_PersistentSpace *persistentSpace);
+
+protected:
+ const uint16 _sampleRate;
+ const bool _stereo;
+
+ Common::DisposablePtr<Common::SeekableReadStream> _stream;
+ int32 _streamBytesLeft;
+
+ void reset();
+ bool rewind();
+ bool endOfData() const { return (_stream->pos() >= _stream->size()); }
+ bool isStereo() const { return _stereo; }
+ int getRate() const { return _sampleRate; }
+
+ int readBuffer(int16 *buffer, const int numSamples);
+
+ bool _initialRead;
+ audio_3DO_ADP4_PersistentSpace *_callerDecoderData;
+ audio_3DO_ADP4_PersistentSpace _initialDecoderData;
+ audio_3DO_ADP4_PersistentSpace _curDecoderData;
+
+private:
+ int16 decodeSample(byte compressedNibble);
+};
+
+class Audio3DO_SDX2_Stream : public RewindableAudioStream {
+public:
+ Audio3DO_SDX2_Stream(Common::SeekableReadStream *stream, uint16 sampleRate, bool stereo, DisposeAfterUse::Flag disposeAfterUse, audio_3DO_SDX2_PersistentSpace *persistentSpacePtr);
+
+protected:
+ const uint16 _sampleRate;
+ const bool _stereo;
+
+ Common::DisposablePtr<Common::SeekableReadStream> _stream;
+ int32 _streamBytesLeft;
+
+ void reset();
+ bool rewind();
+ bool endOfData() const { return (_stream->pos() >= _stream->size()); }
+ bool isStereo() const { return _stereo; }
+ int getRate() const { return _sampleRate; }
+
+ int readBuffer(int16 *buffer, const int numSamples);
+
+ bool _initialRead;
+ audio_3DO_SDX2_PersistentSpace *_callerDecoderData;
+ audio_3DO_SDX2_PersistentSpace _initialDecoderData;
+ audio_3DO_SDX2_PersistentSpace _curDecoderData;
+};
+
+/**
+ * Try to decode 3DO ADP4 data from the given seekable stream and create a SeekableAudioStream
+ * from that data.
+ *
+ * @param stream the SeekableReadStream from which to read the 3DO SDX2 data
+ * @sampleRate sample rate
+ * @stereo if it's stereo or mono
+ * @audioLengthMSecsPtr pointer to a uint32 variable, that is supposed to get the length of the audio in milliseconds
+ * @disposeAfterUse disposeAfterUse whether to delete the stream after use
+ * @persistentSpacePtr pointer to the persistent space structure
+ * @return a new SeekableAudioStream, or NULL, if an error occurred
+ */
+RewindableAudioStream *make3DO_ADP4AudioStream(
+ Common::SeekableReadStream *stream,
+ uint16 sampleRate,
+ bool stereo,
+ uint32 *audioLengthMSecsPtr = NULL, // returns the audio length in milliseconds
+ DisposeAfterUse::Flag disposeAfterUse = DisposeAfterUse::YES,
+ audio_3DO_ADP4_PersistentSpace *persistentSpacePtr = NULL
+);
+
+/**
+ * Try to decode 3DO SDX2 data from the given seekable stream and create a SeekableAudioStream
+ * from that data.
+ *
+ * @param stream the SeekableReadStream from which to read the 3DO SDX2 data
+ * @sampleRate sample rate
+ * @stereo if it's stereo or mono
+ * @audioLengthMSecsPtr pointer to a uint32 variable, that is supposed to get the length of the audio in milliseconds
+ * @disposeAfterUse disposeAfterUse whether to delete the stream after use
+ * @persistentSpacePtr pointer to the persistent space structure
+ * @return a new SeekableAudioStream, or NULL, if an error occurred
+ */
+RewindableAudioStream *make3DO_SDX2AudioStream(
+ Common::SeekableReadStream *stream,
+ uint16 sampleRate,
+ bool stereo,
+ uint32 *audioLengthMSecsPtr = NULL, // returns the audio length in milliseconds
+ DisposeAfterUse::Flag disposeAfterUse = DisposeAfterUse::YES,
+ audio_3DO_SDX2_PersistentSpace *persistentSpacePtr = NULL
+);
+
+} // End of namespace Audio
+
+#endif
diff --git a/audio/decoders/aiff.cpp b/audio/decoders/aiff.cpp
index b714721c02..72baf84582 100644
--- a/audio/decoders/aiff.cpp
+++ b/audio/decoders/aiff.cpp
@@ -24,16 +24,19 @@
* The code in this file is based on information found at
* http://www.borg.com/~jglatt/tech/aiff.htm
*
- * We currently only implement uncompressed AIFF. If we ever need AIFF-C, SoX
- * (http://sox.sourceforge.net) may be a good place to start from.
+ * Also partially based on libav's aiffdec.c
*/
+#include "common/debug.h"
#include "common/endian.h"
#include "common/stream.h"
+#include "common/substream.h"
#include "common/textconsole.h"
+#include "audio/audiostream.h"
#include "audio/decoders/aiff.h"
#include "audio/decoders/raw.h"
+#include "audio/decoders/3do.h"
namespace Audio {
@@ -62,23 +65,34 @@ uint32 readExtended(Common::SeekableReadStream &stream) {
return mantissa;
}
-bool loadAIFFFromStream(Common::SeekableReadStream &stream, int &size, int &rate, byte &flags) {
- byte buf[4];
+// AIFF versions
+static const uint32 kVersionAIFF = MKTAG('A', 'I', 'F', 'F');
+static const uint32 kVersionAIFC = MKTAG('A', 'I', 'F', 'C');
- stream.read(buf, 4);
- if (memcmp(buf, "FORM", 4) != 0) {
- warning("loadAIFFFromStream: No 'FORM' header");
- return false;
+// Codecs
+static const uint32 kCodecPCM = MKTAG('N', 'O', 'N', 'E'); // very original
+
+RewindableAudioStream *makeAIFFStream(Common::SeekableReadStream *stream, DisposeAfterUse::Flag disposeAfterUse) {
+ if (stream->readUint32BE() != MKTAG('F', 'O', 'R', 'M')) {
+ warning("makeAIFFStream: No 'FORM' header");
+
+ if (disposeAfterUse == DisposeAfterUse::YES)
+ delete stream;
+
+ return 0;
}
- stream.readUint32BE();
+ stream->readUint32BE(); // file size
+
+ uint32 version = stream->readUint32BE();
- // This could be AIFC, but we don't handle that case.
+ if (version != kVersionAIFF && version != kVersionAIFC) {
+ warning("makeAIFFStream: No 'AIFF' or 'AIFC' header");
+
+ if (disposeAfterUse == DisposeAfterUse::YES)
+ delete stream;
- stream.read(buf, 4);
- if (memcmp(buf, "AIFF", 4) != 0) {
- warning("loadAIFFFromStream: No 'AIFF' header");
- return false;
+ return 0;
}
// From here on, we only care about the COMM and SSND chunks, which are
@@ -87,95 +101,131 @@ bool loadAIFFFromStream(Common::SeekableReadStream &stream, int &size, int &rate
bool foundCOMM = false;
bool foundSSND = false;
- uint16 numChannels = 0, bitsPerSample = 0;
- uint32 numSampleFrames = 0, offset = 0, blockSize = 0, soundOffset = 0;
+ uint16 channels = 0, bitsPerSample = 0;
+ uint32 blockAlign = 0, rate = 0;
+ uint32 codec = kCodecPCM; // AIFF default
+ Common::SeekableReadStream *dataStream = 0;
- while (!(foundCOMM && foundSSND) && !stream.err() && !stream.eos()) {
- uint32 length, pos;
+ while (!(foundCOMM && foundSSND) && !stream->err() && !stream->eos()) {
+ uint32 tag = stream->readUint32BE();
+ uint32 length = stream->readUint32BE();
+ uint32 pos = stream->pos();
- stream.read(buf, 4);
- length = stream.readUint32BE();
- pos = stream.pos();
+ if (stream->eos() || stream->err())
+ break;
- if (memcmp(buf, "COMM", 4) == 0) {
+ switch (tag) {
+ case MKTAG('C', 'O', 'M', 'M'):
foundCOMM = true;
- numChannels = stream.readUint16BE();
- numSampleFrames = stream.readUint32BE();
- bitsPerSample = stream.readUint16BE();
- rate = readExtended(stream);
- size = numSampleFrames * numChannels * (bitsPerSample / 8);
- } else if (memcmp(buf, "SSND", 4) == 0) {
+ channels = stream->readUint16BE();
+ /* frameCount = */ stream->readUint32BE();
+ bitsPerSample = stream->readUint16BE();
+ rate = readExtended(*stream);
+
+ if (version == kVersionAIFC)
+ codec = stream->readUint32BE();
+ break;
+ case MKTAG('S', 'S', 'N', 'D'):
foundSSND = true;
- offset = stream.readUint32BE();
- blockSize = stream.readUint32BE();
- soundOffset = stream.pos();
+ /* uint32 offset = */ stream->readUint32BE();
+ blockAlign = stream->readUint32BE();
+ dataStream = new Common::SeekableSubReadStream(stream, stream->pos(), stream->pos() + length - 8, disposeAfterUse);
+ break;
+ case MKTAG('F', 'V', 'E', 'R'):
+ switch (stream->readUint32BE()) {
+ case 0:
+ version = kVersionAIFF;
+ break;
+ case 0xA2805140:
+ version = kVersionAIFC;
+ break;
+ default:
+ warning("Unknown AIFF version chunk version");
+ break;
+ }
+ break;
+ case MKTAG('w', 'a', 'v', 'e'):
+ warning("Found unhandled AIFF-C extra data chunk");
+
+ if (!dataStream && disposeAfterUse == DisposeAfterUse::YES)
+ delete stream;
+
+ delete dataStream;
+ return 0;
+ default:
+ debug(1, "Skipping AIFF '%s' chunk", tag2str(tag));
+ break;
}
- stream.seek(pos + length);
+ stream->seek(pos + length + (length & 1)); // ensure we're also word-aligned
}
if (!foundCOMM) {
- warning("loadAIFFFromStream: Cound not find 'COMM' chunk");
- return false;
- }
-
- if (!foundSSND) {
- warning("loadAIFFFromStream: Cound not find 'SSND' chunk");
- return false;
- }
-
- // We only implement a subset of the AIFF standard.
-
- if (numChannels < 1 || numChannels > 2) {
- warning("loadAIFFFromStream: Only 1 or 2 channels are supported, not %d", numChannels);
- return false;
- }
+ warning("makeAIFFStream: Cound not find 'COMM' chunk");
- if (bitsPerSample != 8 && bitsPerSample != 16) {
- warning("loadAIFFFromStream: Only 8 or 16 bits per sample are supported, not %d", bitsPerSample);
- return false;
- }
+ if (!dataStream && disposeAfterUse == DisposeAfterUse::YES)
+ delete stream;
- if (offset != 0 || blockSize != 0) {
- warning("loadAIFFFromStream: Block-aligned data is not supported");
- return false;
+ delete dataStream;
+ return 0;
}
- // Samples are always signed, and big endian.
-
- flags = 0;
- if (bitsPerSample == 16)
- flags |= Audio::FLAG_16BITS;
- if (numChannels == 2)
- flags |= Audio::FLAG_STEREO;
-
- stream.seek(soundOffset);
-
- // Stream now points at the sample data
-
- return true;
-}
-
-SeekableAudioStream *makeAIFFStream(Common::SeekableReadStream *stream,
- DisposeAfterUse::Flag disposeAfterUse) {
- int size, rate;
- byte *data, flags;
+ if (!foundSSND) {
+ warning("makeAIFFStream: Cound not find 'SSND' chunk");
- if (!loadAIFFFromStream(*stream, size, rate, flags)) {
if (disposeAfterUse == DisposeAfterUse::YES)
delete stream;
+
return 0;
}
- data = (byte *)malloc(size);
- assert(data);
- stream->read(data, size);
+ // We only implement a subset of the AIFF standard.
- if (disposeAfterUse == DisposeAfterUse::YES)
- delete stream;
+ if (channels < 1 || channels > 2) {
+ warning("makeAIFFStream: Only 1 or 2 channels are supported, not %d", channels);
+ delete dataStream;
+ return 0;
+ }
+
+ // Seek to the start of dataStream, required for at least FileStream
+ dataStream->seek(0);
+
+ switch (codec) {
+ case kCodecPCM:
+ case MKTAG('t', 'w', 'o', 's'):
+ case MKTAG('s', 'o', 'w', 't'): {
+ // PCM samples are always signed.
+ byte rawFlags = 0;
+ if (bitsPerSample == 16)
+ rawFlags |= Audio::FLAG_16BITS;
+ if (channels == 2)
+ rawFlags |= Audio::FLAG_STEREO;
+ if (codec == MKTAG('s', 'o', 'w', 't'))
+ rawFlags |= Audio::FLAG_LITTLE_ENDIAN;
+
+ return makeRawStream(dataStream, rate, rawFlags);
+ }
+ case MKTAG('i', 'm', 'a', '4'):
+ // TODO: Use QT IMA ADPCM
+ warning("Unhandled AIFF-C QT IMA ADPCM compression");
+ break;
+ 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");
+ break;
+ case MKTAG('A', 'D', 'P', '4'):
+ // ADP4 on 3DO
+ return make3DO_ADP4AudioStream(dataStream, rate, channels == 2);
+ case MKTAG('S', 'D', 'X', '2'):
+ // SDX2 on 3DO
+ return make3DO_SDX2AudioStream(dataStream, rate, channels == 2);
+ default:
+ warning("Unhandled AIFF-C compression tag '%s'", tag2str(codec));
+ }
- // Since we allocated our own buffer for the data, we must specify DisposeAfterUse::YES.
- return makeRawStream(data, size, rate, flags);
+ delete dataStream;
+ return 0;
}
} // End of namespace Audio
diff --git a/audio/decoders/aiff.h b/audio/decoders/aiff.h
index afb0342cfd..3af2efb4c9 100644
--- a/audio/decoders/aiff.h
+++ b/audio/decoders/aiff.h
@@ -23,6 +23,7 @@
/**
* @file
* Sound decoder used in engines:
+ * - bbvs
* - pegasus
* - saga
* - sci
@@ -41,28 +42,17 @@ class SeekableReadStream;
namespace Audio {
-class SeekableAudioStream;
-
-/**
- * Try to load an AIFF from the given seekable stream. Returns true if
- * successful. In that case, the stream's seek position will be set to the
- * start of the audio data, and size, rate and flags contain information
- * necessary for playback. Currently this function only supports uncompressed
- * raw PCM.
- */
-extern bool loadAIFFFromStream(Common::SeekableReadStream &stream, int &size, int &rate, byte &flags);
+class RewindableAudioStream;
/**
* Try to load an AIFF from the given seekable stream and create an AudioStream
* from that data.
*
- * This function uses loadAIFFFromStream() internally.
- *
* @param stream the SeekableReadStream from which to read the AIFF data
* @param disposeAfterUse whether to delete the stream after use
* @return a new SeekableAudioStream, or NULL, if an error occurred
*/
-SeekableAudioStream *makeAIFFStream(
+RewindableAudioStream *makeAIFFStream(
Common::SeekableReadStream *stream,
DisposeAfterUse::Flag disposeAfterUse);
diff --git a/audio/decoders/wave.h b/audio/decoders/wave.h
index 1dcaefd845..6bc9f72101 100644
--- a/audio/decoders/wave.h
+++ b/audio/decoders/wave.h
@@ -23,15 +23,25 @@
/**
* @file
* Sound decoder used in engines:
+ * - access
* - agos
+ * - cge
+ * - cge2
+ * - fullpipe
* - gob
+ * - hopkins
* - mohawk
+ * - prince
* - saga
* - sci
* - scumm
+ * - sherlock
* - sword1
* - sword2
+ * - tony
* - tucker
+ * - wintermute
+ * - zvision
*/
#ifndef AUDIO_WAVE_H
diff --git a/audio/fmopl.cpp b/audio/fmopl.cpp
index 30229ea6bf..cc00ace264 100644
--- a/audio/fmopl.cpp
+++ b/audio/fmopl.cpp
@@ -22,21 +22,33 @@
#include "audio/fmopl.h"
+#include "audio/mixer.h"
#include "audio/softsynth/opl/dosbox.h"
#include "audio/softsynth/opl/mame.h"
#include "common/config-manager.h"
+#include "common/system.h"
#include "common/textconsole.h"
+#include "common/timer.h"
#include "common/translation.h"
namespace OPL {
+// Factory functions
+
+#ifdef USE_ALSA
+namespace ALSA {
+ OPL *create(Config::OplType type);
+} // End of namespace ALSA
+#endif // USE_ALSA
+
// Config implementation
enum OplEmulator {
kAuto = 0,
kMame = 1,
- kDOSBox = 2
+ kDOSBox = 2,
+ kALSA = 3
};
OPL::OPL() {
@@ -51,6 +63,9 @@ const Config::EmulatorDescription Config::_drivers[] = {
#ifndef DISABLE_DOSBOX_OPL
{ "db", _s("DOSBox OPL emulator"), kDOSBox, kFlagOpl2 | kFlagDualOpl2 | kFlagOpl3 },
#endif
+#ifdef USE_ALSA
+ { "alsa", _s("ALSA Direct FM"), kALSA, kFlagOpl2 | kFlagDualOpl2 | kFlagOpl3 },
+#endif
{ 0, 0, 0, 0 }
};
@@ -63,6 +78,15 @@ Config::DriverId Config::parse(const Common::String &name) {
return -1;
}
+const Config::EmulatorDescription *Config::findDriver(DriverId id) {
+ for (int i = 0; _drivers[i].name; ++i) {
+ if (_drivers[i].id == id)
+ return &_drivers[i];
+ }
+
+ return 0;
+}
+
Config::DriverId Config::detect(OplType type) {
uint32 flags = 0;
switch (type) {
@@ -90,8 +114,11 @@ Config::DriverId Config::detect(OplType type) {
// When a valid driver is selected, check whether it supports
// the requested OPL chip.
if (drv != -1 && drv != kAuto) {
+ const EmulatorDescription *driverDesc = findDriver(drv);
// If the chip is supported, just use the driver.
- if ((flags & _drivers[drv].flags)) {
+ if (!driverDesc) {
+ warning("The selected OPL driver %d could not be found", drv);
+ } else if ((flags & driverDesc->flags)) {
return drv;
} else {
// Else we will output a warning and just
@@ -151,6 +178,11 @@ OPL *Config::create(DriverId driver, OplType type) {
return new DOSBox::OPL(type);
#endif
+#ifdef USE_ALSA
+ case kALSA:
+ return ALSA::create(type);
+#endif
+
default:
warning("Unsupported OPL emulator %d", driver);
// TODO: Maybe we should add some dummy emulator too, which just outputs
@@ -159,43 +191,143 @@ OPL *Config::create(DriverId driver, OplType type) {
}
}
+void OPL::start(TimerCallback *callback, int timerFrequency) {
+ _callback.reset(callback);
+ startCallbacks(timerFrequency);
+}
+
+void OPL::stop() {
+ stopCallbacks();
+ _callback.reset();
+}
+
bool OPL::_hasInstance = false;
-} // End of namespace OPL
+RealOPL::RealOPL() : _baseFreq(0), _remainingTicks(0) {
+}
+
+RealOPL::~RealOPL() {
+ // Stop callbacks, just in case. If it's still playing at this
+ // point, there's probably a bigger issue, though. The subclass
+ // needs to call stop() or the pointer can still use be used in
+ // the mixer thread at the same time.
+ stop();
+}
+
+void RealOPL::setCallbackFrequency(int timerFrequency) {
+ stopCallbacks();
+ startCallbacks(timerFrequency);
+}
+
+void RealOPL::startCallbacks(int timerFrequency) {
+ _baseFreq = timerFrequency;
+ assert(_baseFreq > 0);
+
+ // We can't request more a timer faster than 100Hz. We'll handle this by calling
+ // the proc multiple times in onTimer() later on.
+ if (timerFrequency > kMaxFreq)
+ timerFrequency = kMaxFreq;
-void OPLDestroy(FM_OPL *OPL) {
- delete OPL;
+ _remainingTicks = 0;
+ g_system->getTimerManager()->installTimerProc(timerProc, 1000000 / timerFrequency, this, "RealOPL");
}
-void OPLResetChip(FM_OPL *OPL) {
- OPL->reset();
+void RealOPL::stopCallbacks() {
+ g_system->getTimerManager()->removeTimerProc(timerProc);
+ _baseFreq = 0;
+ _remainingTicks = 0;
}
-void OPLWrite(FM_OPL *OPL, int a, int v) {
- OPL->write(a, v);
+void RealOPL::timerProc(void *refCon) {
+ static_cast<RealOPL *>(refCon)->onTimer();
}
-unsigned char OPLRead(FM_OPL *OPL, int a) {
- return OPL->read(a);
+void RealOPL::onTimer() {
+ uint callbacks = 1;
+
+ if (_baseFreq > kMaxFreq) {
+ // We run faster than our max, so run the callback multiple
+ // times to approximate the actual timer callback frequency.
+ uint totalTicks = _baseFreq + _remainingTicks;
+ callbacks = totalTicks / kMaxFreq;
+ _remainingTicks = totalTicks % kMaxFreq;
+ }
+
+ // Call the callback multiple times. The if is on the inside of the
+ // loop in case the callback removes itself.
+ for (uint i = 0; i < callbacks; i++)
+ if (_callback && _callback->isValid())
+ (*_callback)();
}
-void OPLWriteReg(FM_OPL *OPL, int r, int v) {
- OPL->writeReg(r, v);
+EmulatedOPL::EmulatedOPL() :
+ _nextTick(0),
+ _samplesPerTick(0),
+ _baseFreq(0),
+ _handle(new Audio::SoundHandle()) {
}
-void YM3812UpdateOne(FM_OPL *OPL, int16 *buffer, int length) {
- OPL->readBuffer(buffer, length);
+EmulatedOPL::~EmulatedOPL() {
+ // Stop callbacks, just in case. If it's still playing at this
+ // point, there's probably a bigger issue, though. The subclass
+ // needs to call stop() or the pointer can still use be used in
+ // the mixer thread at the same time.
+ stop();
+
+ delete _handle;
}
-FM_OPL *makeAdLibOPL(int rate) {
- FM_OPL *opl = OPL::Config::create();
+int EmulatedOPL::readBuffer(int16 *buffer, const int numSamples) {
+ const int stereoFactor = isStereo() ? 2 : 1;
+ int len = numSamples / stereoFactor;
+ int step;
+
+ do {
+ step = len;
+ if (step > (_nextTick >> FIXP_SHIFT))
+ step = (_nextTick >> FIXP_SHIFT);
+
+ generateSamples(buffer, step * stereoFactor);
- if (opl) {
- if (!opl->init(rate)) {
- delete opl;
- opl = 0;
+ _nextTick -= step << FIXP_SHIFT;
+ if (!(_nextTick >> FIXP_SHIFT)) {
+ if (_callback && _callback->isValid())
+ (*_callback)();
+
+ _nextTick += _samplesPerTick;
}
- }
- return opl;
+ buffer += step * stereoFactor;
+ len -= step;
+ } while (len);
+
+ return numSamples;
+}
+
+int EmulatedOPL::getRate() const {
+ return g_system->getMixer()->getOutputRate();
}
+
+void EmulatedOPL::startCallbacks(int timerFrequency) {
+ setCallbackFrequency(timerFrequency);
+ g_system->getMixer()->playStream(Audio::Mixer::kPlainSoundType, _handle, this, -1, Audio::Mixer::kMaxChannelVolume, 0, DisposeAfterUse::NO, true);
+}
+
+void EmulatedOPL::stopCallbacks() {
+ g_system->getMixer()->stopHandle(*_handle);
+}
+
+void EmulatedOPL::setCallbackFrequency(int timerFrequency) {
+ _baseFreq = timerFrequency;
+ assert(_baseFreq != 0);
+
+ int d = getRate() / _baseFreq;
+ int r = getRate() % _baseFreq;
+
+ // This is equivalent to (getRate() << FIXP_SHIFT) / BASE_FREQ
+ // but less prone to arithmetic overflow.
+
+ _samplesPerTick = (d << FIXP_SHIFT) + (r << FIXP_SHIFT) / _baseFreq;
+}
+
+} // End of namespace OPL
diff --git a/audio/fmopl.h b/audio/fmopl.h
index 85ac606c7a..ba0872d87b 100644
--- a/audio/fmopl.h
+++ b/audio/fmopl.h
@@ -23,8 +23,16 @@
#ifndef AUDIO_FMOPL_H
#define AUDIO_FMOPL_H
+#include "audio/audiostream.h"
+
+#include "common/func.h"
+#include "common/ptr.h"
#include "common/scummsys.h"
+namespace Audio {
+class SoundHandle;
+}
+
namespace Common {
class String;
}
@@ -71,6 +79,12 @@ public:
static DriverId parse(const Common::String &name);
/**
+ * @return The driver description for the given id or 0 in case it is not
+ * available.
+ */
+ static const EmulatorDescription *findDriver(DriverId id);
+
+ /**
* Detects a driver for the specific type.
*
* @return Returns a valid driver id on success, -1 otherwise.
@@ -92,6 +106,14 @@ private:
static const EmulatorDescription _drivers[];
};
+/**
+ * The type of the OPL timer callback functor.
+ */
+typedef Common::Functor0<void> TimerCallback;
+
+/**
+ * A representation of a Yamaha OPL chip.
+ */
class OPL {
private:
static bool _hasInstance;
@@ -102,10 +124,9 @@ public:
/**
* Initializes the OPL emulator.
*
- * @param rate output sample rate
* @return true on success, false on failure
*/
- virtual bool init(int rate) = 0;
+ virtual bool init() = 0;
/**
* Reinitializes the OPL emulator
@@ -140,6 +161,101 @@ public:
virtual void writeReg(int r, int v) = 0;
/**
+ * Start the OPL with callbacks.
+ */
+ void start(TimerCallback *callback, int timerFrequency = kDefaultCallbackFrequency);
+
+ /**
+ * Stop the OPL
+ */
+ void stop();
+
+ /**
+ * Change the callback frequency. This must only be called from a
+ * timer proc.
+ */
+ virtual void setCallbackFrequency(int timerFrequency) = 0;
+
+ enum {
+ /**
+ * The default callback frequency that start() uses
+ */
+ kDefaultCallbackFrequency = 250
+ };
+
+protected:
+ /**
+ * Start the callbacks.
+ */
+ virtual void startCallbacks(int timerFrequency) = 0;
+
+ /**
+ * Stop the callbacks.
+ */
+ virtual void stopCallbacks() = 0;
+
+ /**
+ * The functor for callbacks.
+ */
+ Common::ScopedPtr<TimerCallback> _callback;
+};
+
+/**
+ * An OPL that represents a real OPL, as opposed to an emulated one.
+ *
+ * This will use an actual timer instead of using one calculated from
+ * the number of samples in an AudioStream::readBuffer call.
+ */
+class RealOPL : public OPL {
+public:
+ RealOPL();
+ virtual ~RealOPL();
+
+ // OPL API
+ void setCallbackFrequency(int timerFrequency);
+
+protected:
+ // OPL API
+ void startCallbacks(int timerFrequency);
+ void stopCallbacks();
+
+private:
+ static void timerProc(void *refCon);
+ void onTimer();
+
+ uint _baseFreq;
+ uint _remainingTicks;
+
+ enum {
+ kMaxFreq = 100
+ };
+};
+
+/**
+ * An OPL that represents an emulated OPL.
+ *
+ * This will send callbacks based on the number of samples
+ * decoded in readBuffer().
+ */
+class EmulatedOPL : public OPL, protected Audio::AudioStream {
+public:
+ EmulatedOPL();
+ virtual ~EmulatedOPL();
+
+ // OPL API
+ void setCallbackFrequency(int timerFrequency);
+
+ // AudioStream API
+ int readBuffer(int16 *buffer, const int numSamples);
+ int getRate() const;
+ bool endOfData() const { return false; }
+
+protected:
+ // OPL API
+ void startCallbacks(int timerFrequency);
+ void stopCallbacks();
+
+ /**
* Read up to 'length' samples.
*
* Data will be in native endianess, 16 bit per sample, signed.
@@ -149,33 +265,21 @@ public:
* So if you request 4 samples from a stereo OPL, you will get
* a total of two left channel and two right channel samples.
*/
- virtual void readBuffer(int16 *buffer, int length) = 0;
-
- /**
- * Returns whether the setup OPL mode is stereo or not
- */
- virtual bool isStereo() const = 0;
-};
+ virtual void generateSamples(int16 *buffer, int numSamples) = 0;
-} // End of namespace OPL
+private:
+ int _baseFreq;
-// Legacy API
-// !You should not write any new code using the legacy API!
-typedef OPL::OPL FM_OPL;
+ enum {
+ FIXP_SHIFT = 16
+ };
-void OPLDestroy(FM_OPL *OPL);
+ int _nextTick;
+ int _samplesPerTick;
-void OPLResetChip(FM_OPL *OPL);
-void OPLWrite(FM_OPL *OPL, int a, int v);
-unsigned char OPLRead(FM_OPL *OPL, int a);
-void OPLWriteReg(FM_OPL *OPL, int r, int v);
-void YM3812UpdateOne(FM_OPL *OPL, int16 *buffer, int length);
+ Audio::SoundHandle *_handle;
+};
-/**
- * Legacy factory to create an AdLib (OPL2) chip.
- *
- * !You should not write any new code using the legacy API!
- */
-FM_OPL *makeAdLibOPL(int rate);
+} // End of namespace OPL
#endif
diff --git a/audio/midiparser.h b/audio/midiparser.h
index 9c10462cd7..2cca56b14c 100644
--- a/audio/midiparser.h
+++ b/audio/midiparser.h
@@ -370,6 +370,7 @@ public:
public:
typedef void (*XMidiCallbackProc)(byte eventData, void *refCon);
+ typedef void (*XMidiNewTimbreListProc)(MidiDriver_BASE *driver, const byte *timbreListPtr, uint32 timbreListSize);
MidiParser();
virtual ~MidiParser() { allNotesOff(); }
@@ -395,7 +396,7 @@ public:
static void defaultXMidiCallback(byte eventData, void *refCon);
static MidiParser *createParser_SMF();
- static MidiParser *createParser_XMIDI(XMidiCallbackProc proc = defaultXMidiCallback, void *refCon = 0);
+ static MidiParser *createParser_XMIDI(XMidiCallbackProc proc = defaultXMidiCallback, void *refCon = 0, XMidiNewTimbreListProc newTimbreListProc = NULL, MidiDriver_BASE *newTimbreListDriver = NULL);
static MidiParser *createParser_QT();
static void timerCallback(void *data) { ((MidiParser *) data)->onTimer(); }
};
diff --git a/audio/midiparser_xmidi.cpp b/audio/midiparser_xmidi.cpp
index 95aa5d72f3..8742d7aad1 100644
--- a/audio/midiparser_xmidi.cpp
+++ b/audio/midiparser_xmidi.cpp
@@ -43,6 +43,22 @@ protected:
XMidiCallbackProc _callbackProc;
void *_callbackData;
+ // TODO:
+ // This should possibly get cleaned up at some point, but it's very tricks.
+ // We need to support XMIDI TIMB for 7th guest, which uses
+ // Miles Audio drivers. The MT32 driver needs to get the TIMB chunk, so that it
+ // can install all required timbres before the song starts playing.
+ // But we can't easily implement this directly like for example creating
+ // a special Miles Audio class for usage in this XMIDI-class, because other engines use this
+ // XMIDI-parser but w/o using Miles Audio drivers.
+ XMidiNewTimbreListProc _newTimbreListProc;
+ MidiDriver_BASE *_newTimbreListDriver;
+
+ byte *_tracksTimbreList[120]; ///< Timbre-List for each track.
+ uint32 _tracksTimbreListSize[120]; ///< Size of the Timbre-List for each track.
+ byte *_activeTrackTimbreList;
+ uint32 _activeTrackTimbreListSize;
+
protected:
uint32 readVLQ2(byte * &data);
void parseNextEvent(EventInfo &info);
@@ -53,7 +69,17 @@ protected:
}
public:
- MidiParser_XMIDI(XMidiCallbackProc proc, void *data) : _callbackProc(proc), _callbackData(data), _loopCount(-1) {}
+ MidiParser_XMIDI(XMidiCallbackProc proc, void *data, XMidiNewTimbreListProc newTimbreListProc, MidiDriver_BASE *newTimbreListDriver) {
+ _callbackProc = proc;
+ _callbackData = data;
+ _loopCount = -1;
+ _newTimbreListProc = newTimbreListProc;
+ _newTimbreListDriver = newTimbreListDriver;
+ memset(_tracksTimbreList, 0, sizeof(_tracksTimbreList));
+ memset(_tracksTimbreListSize, 0, sizeof(_tracksTimbreListSize));
+ _activeTrackTimbreList = NULL;
+ _activeTrackTimbreListSize = 0;
+ }
~MidiParser_XMIDI() { }
bool loadMusic(byte *data, uint32 size);
@@ -322,11 +348,16 @@ bool MidiParser_XMIDI::loadMusic(byte *data, uint32 size) {
// Skip this.
pos += 4;
} else if (!memcmp(pos, "TIMB", 4)) {
- // Custom timbres?
- // We don't support them.
- // Read the length, skip it, and hope there was nothing there.
+ // Custom timbres
+ // chunk data is as follows:
+ // UINT16LE timbre count (amount of custom timbres used by this track)
+ // BYTE patchId
+ // BYTE bankId
+ // * timbre count
pos += 4;
len = read4high(pos);
+ _tracksTimbreList[tracksRead] = pos; // Skip the length bytes
+ _tracksTimbreListSize[tracksRead] = len;
pos += (len + 1) & ~1;
} else if (!memcmp(pos, "EVNT", 4)) {
// Ahh! What we're looking for at last.
@@ -350,6 +381,12 @@ bool MidiParser_XMIDI::loadMusic(byte *data, uint32 size) {
resetTracking();
setTempo(500000);
setTrack(0);
+ _activeTrackTimbreList = _tracksTimbreList[0];
+ _activeTrackTimbreListSize = _tracksTimbreListSize[0];
+
+ if (_newTimbreListProc)
+ _newTimbreListProc(_newTimbreListDriver, _activeTrackTimbreList, _activeTrackTimbreListSize);
+
return true;
}
@@ -360,6 +397,6 @@ void MidiParser::defaultXMidiCallback(byte eventData, void *data) {
warning("MidiParser: defaultXMidiCallback(%d)", eventData);
}
-MidiParser *MidiParser::createParser_XMIDI(XMidiCallbackProc proc, void *data) {
- return new MidiParser_XMIDI(proc, data);
+MidiParser *MidiParser::createParser_XMIDI(XMidiCallbackProc proc, void *data, XMidiNewTimbreListProc newTimbreListProc, MidiDriver_BASE *newTimbreListDriver) {
+ return new MidiParser_XMIDI(proc, data, newTimbreListProc, newTimbreListDriver);
}
diff --git a/audio/miles.h b/audio/miles.h
new file mode 100644
index 0000000000..23d5998fba
--- /dev/null
+++ b/audio/miles.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.
+ *
+ */
+
+#ifndef AUDIO_MILES_MIDIDRIVER_H
+#define AUDIO_MILES_MIDIDRIVER_H
+
+#include "audio/mididrv.h"
+#include "common/error.h"
+#include "common/stream.h"
+
+namespace Audio {
+
+#define MILES_MIDI_CHANNEL_COUNT 16
+
+// Miles Audio supported controllers for control change messages
+#define MILES_CONTROLLER_SELECT_PATCH_BANK 114
+#define MILES_CONTROLLER_PROTECT_VOICE 112
+#define MILES_CONTROLLER_PROTECT_TIMBRE 113
+#define MILES_CONTROLLER_MODULATION 1
+#define MILES_CONTROLLER_VOLUME 7
+#define MILES_CONTROLLER_EXPRESSION 11
+#define MILES_CONTROLLER_PANNING 10
+#define MILES_CONTROLLER_SUSTAIN 64
+#define MILES_CONTROLLER_PITCH_RANGE 6
+#define MILES_CONTROLLER_RESET_ALL 121
+#define MILES_CONTROLLER_ALL_NOTES_OFF 123
+#define MILES_CONTROLLER_PATCH_REVERB 59
+#define MILES_CONTROLLER_PATCH_BENDER 60
+#define MILES_CONTROLLER_REVERB_MODE 61
+#define MILES_CONTROLLER_REVERB_TIME 62
+#define MILES_CONTROLLER_REVERB_LEVEL 63
+#define MILES_CONTROLLER_RHYTHM_KEY_TIMBRE 58
+
+// 3 SysEx controllers, each range 5
+// 32-36 for 1st queue
+// 37-41 for 2nd queue
+// 42-46 for 3rd queue
+#define MILES_CONTROLLER_SYSEX_RANGE_BEGIN 32
+#define MILES_CONTROLLER_SYSEX_RANGE_END 46
+
+#define MILES_CONTROLLER_SYSEX_QUEUE_COUNT 3
+#define MILES_CONTROLLER_SYSEX_QUEUE_SIZE 32
+
+#define MILES_CONTROLLER_SYSEX_COMMAND_ADDRESS1 0
+#define MILES_CONTROLLER_SYSEX_COMMAND_ADDRESS2 1
+#define MILES_CONTROLLER_SYSEX_COMMAND_ADDRESS3 2
+#define MILES_CONTROLLER_SYSEX_COMMAND_DATA 3
+#define MILES_CONTROLLER_SYSEX_COMMAND_SEND 4
+
+#define MILES_CONTROLLER_XMIDI_RANGE_BEGIN 110
+#define MILES_CONTROLLER_XMIDI_RANGE_END 120
+
+// Miles Audio actually used 0x4000, because they didn't shift the 2 bytes properly
+#define MILES_PITCHBENDER_DEFAULT 0x2000
+
+extern MidiDriver *MidiDriver_Miles_AdLib_create(const Common::String &filenameAdLib, const Common::String &filenameOPL3, Common::SeekableReadStream *streamAdLib = nullptr, Common::SeekableReadStream *streamOPL3 = nullptr);
+
+extern MidiDriver *MidiDriver_Miles_MT32_create(const Common::String &instrumentDataFilename);
+
+extern void MidiDriver_Miles_MT32_processXMIDITimbreChunk(MidiDriver_BASE *driver, const byte *timbreListPtr, uint32 timbreListSize);
+
+} // End of namespace Audio
+
+#endif // AUDIO_MILES_MIDIDRIVER_H
diff --git a/audio/miles_adlib.cpp b/audio/miles_adlib.cpp
new file mode 100644
index 0000000000..bf5c9d4a73
--- /dev/null
+++ b/audio/miles_adlib.cpp
@@ -0,0 +1,1274 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public 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/miles.h"
+
+#include "common/file.h"
+#include "common/system.h"
+#include "common/textconsole.h"
+
+#include "audio/fmopl.h"
+#include "audio/softsynth/emumidi.h"
+
+namespace Audio {
+
+// Miles Audio AdLib/OPL3 driver
+//
+// TODO: currently missing: OPL3 4-op voices
+//
+// Special cases (great for testing):
+// - sustain feature is used by Return To Zork (demo) right at the start
+// - sherlock holmes 2 does lots of priority sorts right at the start of the intro
+
+#define MILES_ADLIB_VIRTUAL_FMVOICES_COUNT_MAX 20
+#define MILES_ADLIB_PHYSICAL_FMVOICES_COUNT_MAX 18
+
+#define MILES_ADLIB_PERCUSSION_BANK 127
+
+#define MILES_ADLIB_STEREO_PANNING_THRESHOLD_LEFT 27
+#define MILES_ADLIB_STEREO_PANNING_THRESHOLD_RIGHT 100
+
+enum kMilesAdLibUpdateFlags {
+ kMilesAdLibUpdateFlags_None = 0,
+ kMilesAdLibUpdateFlags_Reg_20 = 1 << 0,
+ kMilesAdLibUpdateFlags_Reg_40 = 1 << 1,
+ kMilesAdLibUpdateFlags_Reg_60 = 1 << 2, // register 0x6x + 0x8x
+ kMilesAdLibUpdateFlags_Reg_C0 = 1 << 3,
+ kMilesAdLibUpdateFlags_Reg_E0 = 1 << 4,
+ kMilesAdLibUpdateFlags_Reg_A0 = 1 << 5, // register 0xAx + 0xBx
+ kMilesAdLibUpdateFlags_Reg_All = 0x3F
+};
+
+uint16 milesAdLibOperator1Register[MILES_ADLIB_PHYSICAL_FMVOICES_COUNT_MAX] = {
+ 0x0000, 0x0001, 0x0002, 0x0008, 0x0009, 0x000A, 0x0010, 0x0011, 0x0012,
+ 0x0100, 0x0101, 0x0102, 0x0108, 0x0109, 0x010A, 0x0110, 0x0111, 0x0112
+};
+
+uint16 milesAdLibOperator2Register[MILES_ADLIB_PHYSICAL_FMVOICES_COUNT_MAX] = {
+ 0x0003, 0x0004, 0x0005, 0x000B, 0x000C, 0x000D, 0x0013, 0x0014, 0x0015,
+ 0x0103, 0x0104, 0x0105, 0x010B, 0x010C, 0x010D, 0x0113, 0x0114, 0x0115
+};
+
+uint16 milesAdLibChannelRegister[MILES_ADLIB_PHYSICAL_FMVOICES_COUNT_MAX] = {
+ 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008,
+ 0x0100, 0x0101, 0x0102, 0x0103, 0x0104, 0x0105, 0x0106, 0x0107, 0x0108
+};
+
+struct InstrumentEntry {
+ byte bankId;
+ byte patchId;
+ int16 transposition;
+ byte reg20op1;
+ byte reg40op1;
+ byte reg60op1;
+ byte reg80op1;
+ byte regE0op1;
+ byte reg20op2;
+ byte reg40op2;
+ byte reg60op2;
+ byte reg80op2;
+ byte regE0op2;
+ byte regC0;
+};
+
+// hardcoded, dumped from ADLIB.MDI
+uint16 milesAdLibFrequencyLookUpTable[] = {
+ 0x02B2, 0x02B4, 0x02B7, 0x02B9, 0x02BC, 0x02BE, 0x02C1, 0x02C3, 0x02C6, 0x02C9, 0x02CB, 0x02CE,
+ 0x02D0, 0x02D3, 0x02D6, 0x02D8, 0x02DB, 0x02DD, 0x02E0, 0x02E3, 0x02E5, 0x02E8, 0x02EB, 0x02ED,
+ 0x02F0, 0x02F3, 0x02F6, 0x02F8, 0x02FB, 0x02FE, 0x0301, 0x0303, 0x0306, 0x0309, 0x030C, 0x030F,
+ 0x0311, 0x0314, 0x0317, 0x031A, 0x031D, 0x0320, 0x0323, 0x0326, 0x0329, 0x032B, 0x032E, 0x0331,
+ 0x0334, 0x0337, 0x033A, 0x033D, 0x0340, 0x0343, 0x0346, 0x0349, 0x034C, 0x034F, 0x0352, 0x0356,
+ 0x0359, 0x035C, 0x035F, 0x0362, 0x0365, 0x0368, 0x036B, 0x036F, 0x0372, 0x0375, 0x0378, 0x037B,
+ 0x037F, 0x0382, 0x0385, 0x0388, 0x038C, 0x038F, 0x0392, 0x0395, 0x0399, 0x039C, 0x039F, 0x03A3,
+ 0x03A6, 0x03A9, 0x03AD, 0x03B0, 0x03B4, 0x03B7, 0x03BB, 0x03BE, 0x03C1, 0x03C5, 0x03C8, 0x03CC,
+ 0x03CF, 0x03D3, 0x03D7, 0x03DA, 0x03DE, 0x03E1, 0x03E5, 0x03E8, 0x03EC, 0x03F0, 0x03F3, 0x03F7,
+ 0x03FB, 0x03FE, 0xFE01, 0xFE03, 0xFE05, 0xFE07, 0xFE08, 0xFE0A, 0xFE0C, 0xFE0E, 0xFE10, 0xFE12,
+ 0xFE14, 0xFE16, 0xFE18, 0xFE1A, 0xFE1C, 0xFE1E, 0xFE20, 0xFE21, 0xFE23, 0xFE25, 0xFE27, 0xFE29,
+ 0xFE2B, 0xFE2D, 0xFE2F, 0xFE31, 0xFE34, 0xFE36, 0xFE38, 0xFE3A, 0xFE3C, 0xFE3E, 0xFE40, 0xFE42,
+ 0xFE44, 0xFE46, 0xFE48, 0xFE4A, 0xFE4C, 0xFE4F, 0xFE51, 0xFE53, 0xFE55, 0xFE57, 0xFE59, 0xFE5C,
+ 0xFE5E, 0xFE60, 0xFE62, 0xFE64, 0xFE67, 0xFE69, 0xFE6B, 0xFE6D, 0xFE6F, 0xFE72, 0xFE74, 0xFE76,
+ 0xFE79, 0xFE7B, 0xFE7D, 0xFE7F, 0xFE82, 0xFE84, 0xFE86, 0xFE89, 0xFE8B, 0xFE8D, 0xFE90, 0xFE92,
+ 0xFE95, 0xFE97, 0xFE99, 0xFE9C, 0xFE9E, 0xFEA1, 0xFEA3, 0xFEA5, 0xFEA8, 0xFEAA, 0xFEAD, 0xFEAF
+};
+
+// hardcoded, dumped from ADLIB.MDI
+uint16 milesAdLibVolumeSensitivityTable[] = {
+ 82, 85, 88, 91, 94, 97, 100, 103, 106, 109, 112, 115, 118, 121, 124, 127
+};
+
+
+class MidiDriver_Miles_AdLib : public MidiDriver {
+public:
+ MidiDriver_Miles_AdLib(InstrumentEntry *instrumentTablePtr, uint16 instrumentTableCount);
+ virtual ~MidiDriver_Miles_AdLib();
+
+ // MidiDriver
+ int open();
+ void close();
+ void send(uint32 b);
+ MidiChannel *allocateChannel() { return NULL; }
+ MidiChannel *getPercussionChannel() { return NULL; }
+
+ bool isOpen() const { return _isOpen; }
+ uint32 getBaseTempo() { return 1000000 / OPL::OPL::kDefaultCallbackFrequency; }
+
+ void setVolume(byte volume);
+ virtual uint32 property(int prop, uint32 param);
+
+ void setTimerCallback(void *timerParam, Common::TimerManager::TimerProc timerProc);
+
+private:
+ bool _modeOPL3;
+ byte _modePhysicalFmVoicesCount;
+ byte _modeVirtualFmVoicesCount;
+ bool _modeStereo;
+
+ // Structure to hold information about current status of MIDI Channels
+ struct MidiChannelEntry {
+ byte currentPatchBank;
+ const InstrumentEntry *currentInstrumentPtr;
+ uint16 currentPitchBender;
+ byte currentPitchRange;
+ byte currentVoiceProtection;
+
+ byte currentVolume;
+ byte currentVolumeExpression;
+
+ byte currentPanning;
+
+ byte currentModulation;
+ byte currentSustain;
+
+ byte currentActiveVoicesCount;
+
+ MidiChannelEntry() : currentPatchBank(0),
+ currentInstrumentPtr(NULL),
+ currentPitchBender(MILES_PITCHBENDER_DEFAULT),
+ currentPitchRange(0),
+ currentVoiceProtection(0),
+ currentVolume(0), currentVolumeExpression(0),
+ currentPanning(0),
+ currentModulation(0),
+ currentSustain(0),
+ currentActiveVoicesCount(0) { }
+ };
+
+ // Structure to hold information about current status of virtual FM Voices
+ struct VirtualFmVoiceEntry {
+ bool inUse;
+ byte actualMidiChannel;
+
+ const InstrumentEntry *currentInstrumentPtr;
+
+ bool isPhysical;
+ byte physicalFmVoice;
+
+ uint16 currentPriority;
+
+ byte currentOriginalMidiNote;
+ byte currentNote;
+ int16 currentTransposition;
+ byte currentVelocity;
+
+ bool sustained;
+
+ VirtualFmVoiceEntry(): inUse(false),
+ actualMidiChannel(0),
+ currentInstrumentPtr(NULL),
+ isPhysical(false), physicalFmVoice(0),
+ currentPriority(0),
+ currentOriginalMidiNote(0),
+ currentNote(0),
+ currentTransposition(0),
+ currentVelocity(0),
+ sustained(false) { }
+ };
+
+ // Structure to hold information about current status of physical FM Voices
+ struct PhysicalFmVoiceEntry {
+ bool inUse;
+ byte virtualFmVoice;
+
+ byte currentB0hReg;
+
+ PhysicalFmVoiceEntry(): inUse(false),
+ virtualFmVoice(0),
+ currentB0hReg(0) { }
+ };
+
+ OPL::OPL *_opl;
+ int _masterVolume;
+
+ Common::TimerManager::TimerProc _adlibTimerProc;
+ void *_adlibTimerParam;
+
+ bool _isOpen;
+
+ // stores information about all MIDI channels (not the actual OPL FM voice channels!)
+ MidiChannelEntry _midiChannels[MILES_MIDI_CHANNEL_COUNT];
+
+ // stores information about all virtual OPL FM voices
+ VirtualFmVoiceEntry _virtualFmVoices[MILES_ADLIB_VIRTUAL_FMVOICES_COUNT_MAX];
+
+ // stores information about all physical OPL FM voices
+ PhysicalFmVoiceEntry _physicalFmVoices[MILES_ADLIB_PHYSICAL_FMVOICES_COUNT_MAX];
+
+ // holds all instruments
+ InstrumentEntry *_instrumentTablePtr;
+ uint16 _instrumentTableCount;
+
+ bool circularPhysicalAssignment;
+ byte circularPhysicalAssignmentFmVoice;
+
+ void onTimer();
+
+ void resetData();
+ void resetAdLib();
+ void resetAdLibOperatorRegisters(byte baseRegister, byte value);
+ void resetAdLibFMVoiceChannelRegisters(byte baseRegister, byte value);
+
+ void setRegister(int reg, int value);
+
+ int16 searchFreeVirtualFmVoiceChannel();
+ int16 searchFreePhysicalFmVoiceChannel();
+
+ void noteOn(byte midiChannel, byte note, byte velocity);
+ void noteOff(byte midiChannel, byte note);
+
+ void prioritySort();
+
+ void releaseFmVoice(byte virtualFmVoice);
+
+ void releaseSustain(byte midiChannel);
+
+ void updatePhysicalFmVoice(byte virtualFmVoice, bool keyOn, uint16 registerUpdateFlags);
+
+ void controlChange(byte midiChannel, byte controllerNumber, byte controllerValue);
+ void programChange(byte midiChannel, byte patchId);
+
+ const InstrumentEntry *searchInstrument(byte bankId, byte patchId);
+
+ void pitchBendChange(byte MIDIchannel, byte parameter1, byte parameter2);
+};
+
+MidiDriver_Miles_AdLib::MidiDriver_Miles_AdLib(InstrumentEntry *instrumentTablePtr, uint16 instrumentTableCount)
+ : _masterVolume(15), _opl(0),
+ _adlibTimerProc(0), _adlibTimerParam(0), _isOpen(false) {
+
+ _instrumentTablePtr = instrumentTablePtr;
+ _instrumentTableCount = instrumentTableCount;
+
+ // Set up for OPL3, we will downgrade in case we can't create OPL3 emulator
+ // regular AdLib (OPL2) card
+ _modeOPL3 = true;
+ _modeVirtualFmVoicesCount = 20;
+ _modePhysicalFmVoicesCount = 18;
+ _modeStereo = true;
+
+ // Older Miles Audio drivers did not do a circular assign for physical FM-voices
+ // Sherlock Holmes 2 used the circular assign
+ circularPhysicalAssignment = true;
+ // this way the first circular physical FM-voice search will start at FM-voice 0
+ circularPhysicalAssignmentFmVoice = MILES_ADLIB_PHYSICAL_FMVOICES_COUNT_MAX;
+
+ resetData();
+}
+
+MidiDriver_Miles_AdLib::~MidiDriver_Miles_AdLib() {
+ delete[] _instrumentTablePtr; // is created in factory MidiDriver_Miles_AdLib_create()
+}
+
+int MidiDriver_Miles_AdLib::open() {
+ if (_modeOPL3) {
+ // Try to create OPL3 first
+ _opl = OPL::Config::create(OPL::Config::kOpl3);
+ }
+ if (!_opl) {
+ // not created yet, downgrade to OPL2
+ _modeOPL3 = false;
+ _modeVirtualFmVoicesCount = 16;
+ _modePhysicalFmVoicesCount = 9;
+ _modeStereo = false;
+
+ _opl = OPL::Config::create(OPL::Config::kOpl2);
+ }
+
+ if (!_opl) {
+ // We still got nothing -> can't do anything anymore
+ return -1;
+ }
+
+ _opl->init();
+
+ _isOpen = true;
+
+ _opl->start(new Common::Functor0Mem<void, MidiDriver_Miles_AdLib>(this, &MidiDriver_Miles_AdLib::onTimer));
+
+ resetAdLib();
+
+ return 0;
+}
+
+void MidiDriver_Miles_AdLib::close() {
+ delete _opl;
+ _isOpen = false;
+}
+
+void MidiDriver_Miles_AdLib::setVolume(byte volume) {
+ _masterVolume = volume;
+ //renewNotes(-1, true);
+}
+
+void MidiDriver_Miles_AdLib::onTimer() {
+ if (_adlibTimerProc)
+ (*_adlibTimerProc)(_adlibTimerParam);
+}
+
+void MidiDriver_Miles_AdLib::resetData() {
+ memset(_midiChannels, 0, sizeof(_midiChannels));
+ memset(_virtualFmVoices, 0, sizeof(_virtualFmVoices));
+ memset(_physicalFmVoices, 0, sizeof(_physicalFmVoices));
+
+ for (byte midiChannel = 0; midiChannel < MILES_MIDI_CHANNEL_COUNT; midiChannel++) {
+ // defaults, were sent to driver during driver initialization
+ _midiChannels[midiChannel].currentVolume = 0x7F;
+ _midiChannels[midiChannel].currentPanning = 0x40; // center
+ _midiChannels[midiChannel].currentVolumeExpression = 127;
+
+ // Miles Audio 2: hardcoded pitch range as a global (not channel specific), set to 12
+ // Miles Audio 3: pitch range per MIDI channel
+ _midiChannels[midiChannel].currentPitchBender = MILES_PITCHBENDER_DEFAULT;
+ _midiChannels[midiChannel].currentPitchRange = 12;
+ }
+
+}
+
+void MidiDriver_Miles_AdLib::resetAdLib() {
+ if (_modeOPL3) {
+ setRegister(0x105, 1); // enable OPL3
+ setRegister(0x104, 0); // activate 18 2-operator FM-voices
+ }
+
+ setRegister(0x01, 0x20); // enable waveform control on both operators
+ setRegister(0x04, 0xE0); // Timer control
+
+ setRegister(0x08, 0); // select FM music mode
+ setRegister(0xBD, 0); // disable Rhythm
+
+ // reset FM voice instrument data
+ resetAdLibOperatorRegisters(0x20, 0);
+ resetAdLibOperatorRegisters(0x60, 0);
+ resetAdLibOperatorRegisters(0x80, 0);
+ resetAdLibFMVoiceChannelRegisters(0xA0, 0);
+ resetAdLibFMVoiceChannelRegisters(0xB0, 0);
+ resetAdLibFMVoiceChannelRegisters(0xC0, 0);
+ resetAdLibOperatorRegisters(0xE0, 0);
+ resetAdLibOperatorRegisters(0x40, 0x3F);
+}
+
+void MidiDriver_Miles_AdLib::resetAdLibOperatorRegisters(byte baseRegister, byte value) {
+ byte physicalFmVoice = 0;
+
+ for (physicalFmVoice = 0; physicalFmVoice < _modePhysicalFmVoicesCount; physicalFmVoice++) {
+ setRegister(baseRegister + milesAdLibOperator1Register[physicalFmVoice], value);
+ setRegister(baseRegister + milesAdLibOperator2Register[physicalFmVoice], value);
+ }
+}
+
+void MidiDriver_Miles_AdLib::resetAdLibFMVoiceChannelRegisters(byte baseRegister, byte value) {
+ byte physicalFmVoice = 0;
+
+ for (physicalFmVoice = 0; physicalFmVoice < _modePhysicalFmVoicesCount; physicalFmVoice++) {
+ setRegister(baseRegister + milesAdLibChannelRegister[physicalFmVoice], value);
+ }
+}
+
+// MIDI messages can be found at http://www.midi.org/techspecs/midimessages.php
+void MidiDriver_Miles_AdLib::send(uint32 b) {
+ byte command = b & 0xf0;
+ byte channel = b & 0xf;
+ byte op1 = (b >> 8) & 0xff;
+ byte op2 = (b >> 16) & 0xff;
+
+ switch (command) {
+ case 0x80:
+ noteOff(channel, op1);
+ break;
+ case 0x90:
+ noteOn(channel, op1, op2);
+ break;
+ case 0xb0: // Control change
+ controlChange(channel, op1, op2);
+ break;
+ case 0xc0: // Program Change
+ programChange(channel, op1);
+ break;
+ case 0xa0: // Polyphonic key pressure (aftertouch)
+ case 0xd0: // Channel pressure (aftertouch)
+ // Aftertouch doesn't seem to be implemented in the Miles Audio AdLib driver
+ break;
+ case 0xe0:
+ pitchBendChange(channel, op1, op2);
+ break;
+ case 0xf0: // SysEx
+ warning("MILES-ADLIB: SysEx: %x", b);
+ break;
+ default:
+ warning("MILES-ADLIB: Unknown event %02x", command);
+ }
+}
+
+void MidiDriver_Miles_AdLib::setTimerCallback(void *timerParam, Common::TimerManager::TimerProc timerProc) {
+ _adlibTimerProc = timerProc;
+ _adlibTimerParam = timerParam;
+}
+
+int16 MidiDriver_Miles_AdLib::searchFreeVirtualFmVoiceChannel() {
+ for (byte virtualFmVoice = 0; virtualFmVoice < _modeVirtualFmVoicesCount; virtualFmVoice++) {
+ if (!_virtualFmVoices[virtualFmVoice].inUse)
+ return virtualFmVoice;
+ }
+ return -1;
+}
+
+int16 MidiDriver_Miles_AdLib::searchFreePhysicalFmVoiceChannel() {
+ if (!circularPhysicalAssignment) {
+ // Older assign logic
+ for (byte physicalFmVoice = 0; physicalFmVoice < _modePhysicalFmVoicesCount; physicalFmVoice++) {
+ if (!_physicalFmVoices[physicalFmVoice].inUse)
+ return physicalFmVoice;
+ }
+ } else {
+ // Newer one
+ // Remembers last physical FM-voice and searches from that spot
+ byte physicalFmVoice = circularPhysicalAssignmentFmVoice;
+ for (byte physicalFmVoiceCount = 0; physicalFmVoiceCount < _modePhysicalFmVoicesCount; physicalFmVoiceCount++) {
+ physicalFmVoice++;
+ if (physicalFmVoice >= _modePhysicalFmVoicesCount)
+ physicalFmVoice = 0;
+ if (!_physicalFmVoices[physicalFmVoice].inUse) {
+ circularPhysicalAssignmentFmVoice = physicalFmVoice;
+ return physicalFmVoice;
+ }
+ }
+ }
+ return -1;
+}
+
+void MidiDriver_Miles_AdLib::noteOn(byte midiChannel, byte note, byte velocity) {
+ const InstrumentEntry *instrumentPtr = NULL;
+
+ if (velocity == 0) {
+ noteOff(midiChannel, note);
+ return;
+ }
+
+ if (midiChannel == 9) {
+ // percussion channel
+ // search for instrument according to given note
+ instrumentPtr = searchInstrument(MILES_ADLIB_PERCUSSION_BANK, note);
+ } else {
+ // directly get instrument of channel
+ instrumentPtr = _midiChannels[midiChannel].currentInstrumentPtr;
+ }
+ if (!instrumentPtr) {
+ warning("MILES-ADLIB: noteOn: invalid instrument");
+ return;
+ }
+
+ //warning("Note On: channel %d, note %d, velocity %d, instrument %d/%d", midiChannel, note, velocity, instrumentPtr->bankId, instrumentPtr->patchId);
+
+ // look for free virtual FM voice
+ int16 virtualFmVoice = searchFreeVirtualFmVoiceChannel();
+
+ if (virtualFmVoice == -1) {
+ // Out of virtual voices, can't do anything about it
+ return;
+ }
+
+ // Scale back velocity
+ velocity = (velocity & 0x7F) >> 3;
+ velocity = milesAdLibVolumeSensitivityTable[velocity];
+
+ if (midiChannel != 9) {
+ _virtualFmVoices[virtualFmVoice].currentNote = note;
+ _virtualFmVoices[virtualFmVoice].currentTransposition = instrumentPtr->transposition;
+ } else {
+ // Percussion channel
+ _virtualFmVoices[virtualFmVoice].currentNote = instrumentPtr->transposition;
+ _virtualFmVoices[virtualFmVoice].currentTransposition = 0;
+ }
+
+ _virtualFmVoices[virtualFmVoice].inUse = true;
+ _virtualFmVoices[virtualFmVoice].actualMidiChannel = midiChannel;
+ _virtualFmVoices[virtualFmVoice].currentOriginalMidiNote = note;
+ _virtualFmVoices[virtualFmVoice].currentInstrumentPtr = instrumentPtr;
+ _virtualFmVoices[virtualFmVoice].currentVelocity = velocity;
+ _virtualFmVoices[virtualFmVoice].isPhysical = false;
+ _virtualFmVoices[virtualFmVoice].sustained = false;
+ _virtualFmVoices[virtualFmVoice].currentPriority = 32767;
+
+ int16 physicalFmVoice = searchFreePhysicalFmVoiceChannel();
+ if (physicalFmVoice == -1) {
+ // None found
+ // go through priorities and reshuffle voices
+ prioritySort();
+ return;
+ }
+
+ // Another voice active on this MIDI channel
+ _midiChannels[midiChannel].currentActiveVoicesCount++;
+
+ // Mark virtual FM-Voice as being connected to physical FM-Voice
+ _virtualFmVoices[virtualFmVoice].isPhysical = true;
+ _virtualFmVoices[virtualFmVoice].physicalFmVoice = physicalFmVoice;
+
+ // Mark physical FM-Voice as being connected to virtual FM-Voice
+ _physicalFmVoices[physicalFmVoice].inUse = true;
+ _physicalFmVoices[physicalFmVoice].virtualFmVoice = virtualFmVoice;
+
+ // Update the physical FM-Voice
+ updatePhysicalFmVoice(virtualFmVoice, true, kMilesAdLibUpdateFlags_Reg_All);
+}
+
+void MidiDriver_Miles_AdLib::noteOff(byte midiChannel, byte note) {
+ //warning("Note Off: channel %d, note %d", midiChannel, note);
+
+ // Search through all virtual FM-Voices for current midiChannel + note
+ for (byte virtualFmVoice = 0; virtualFmVoice < _modeVirtualFmVoicesCount; virtualFmVoice++) {
+ if (_virtualFmVoices[virtualFmVoice].inUse) {
+ if ((_virtualFmVoices[virtualFmVoice].actualMidiChannel == midiChannel) && (_virtualFmVoices[virtualFmVoice].currentOriginalMidiNote == note)) {
+ // found one
+ if (_midiChannels[midiChannel].currentSustain >= 64) {
+ _virtualFmVoices[virtualFmVoice].sustained = true;
+ continue;
+ }
+ //
+ releaseFmVoice(virtualFmVoice);
+ }
+ }
+ }
+}
+
+void MidiDriver_Miles_AdLib::prioritySort() {
+ byte virtualFmVoice = 0;
+ uint16 virtualPriority = 0;
+ uint16 virtualPriorities[MILES_ADLIB_VIRTUAL_FMVOICES_COUNT_MAX];
+ uint16 virtualFmVoicesCount = 0;
+ byte midiChannel = 0;
+
+ memset(&virtualPriorities, 0, sizeof(virtualPriorities));
+
+ //warning("prioritysort");
+
+ // First calculate priorities for all virtual FM voices, that are in use
+ for (virtualFmVoice = 0; virtualFmVoice < _modeVirtualFmVoicesCount; virtualFmVoice++) {
+ if (_virtualFmVoices[virtualFmVoice].inUse) {
+ virtualFmVoicesCount++;
+
+ midiChannel = _virtualFmVoices[virtualFmVoice].actualMidiChannel;
+ if (_midiChannels[midiChannel].currentVoiceProtection >= 64) {
+ // Voice protection enabled
+ virtualPriority = 0xFFFF;
+ } else {
+ virtualPriority = _virtualFmVoices[virtualFmVoice].currentPriority;
+ }
+ byte currentActiveVoicesCount = _midiChannels[midiChannel].currentActiveVoicesCount;
+ if (virtualPriority >= currentActiveVoicesCount) {
+ virtualPriority -= _midiChannels[midiChannel].currentActiveVoicesCount;
+ } else {
+ virtualPriority = 0; // overflow, should never happen
+ }
+ virtualPriorities[virtualFmVoice] = virtualPriority;
+ }
+ }
+
+ //
+ while (virtualFmVoicesCount) {
+ uint16 unvoicedHighestPriority = 0;
+ byte unvoicedHighestFmVoice = 0;
+ uint16 voicedLowestPriority = 65535;
+ byte voicedLowestFmVoice = 0;
+
+ for (virtualFmVoice = 0; virtualFmVoice < _modeVirtualFmVoicesCount; virtualFmVoice++) {
+ if (_virtualFmVoices[virtualFmVoice].inUse) {
+ virtualPriority = virtualPriorities[virtualFmVoice];
+ if (!_virtualFmVoices[virtualFmVoice].isPhysical) {
+ // currently not physical, so unvoiced
+ if (virtualPriority >= unvoicedHighestPriority) {
+ unvoicedHighestPriority = virtualPriority;
+ unvoicedHighestFmVoice = virtualFmVoice;
+ }
+ } else {
+ // currently physical, so voiced
+ if (virtualPriority <= voicedLowestPriority) {
+ voicedLowestPriority = virtualPriority;
+ voicedLowestFmVoice = virtualFmVoice;
+ }
+ }
+ }
+ }
+
+ if (unvoicedHighestPriority < voicedLowestPriority)
+ break; // We are done
+
+ if (unvoicedHighestPriority == 0)
+ break;
+
+ // Safety checks
+ assert(_virtualFmVoices[voicedLowestFmVoice].isPhysical);
+ assert(!_virtualFmVoices[unvoicedHighestFmVoice].isPhysical);
+
+ // Steal this physical voice
+ byte physicalFmVoice = _virtualFmVoices[voicedLowestFmVoice].physicalFmVoice;
+
+ //warning("MILES-ADLIB: stealing physical FM-Voice %d from virtual FM-Voice %d for virtual FM-Voice %d", physicalFmVoice, voicedLowestFmVoice, unvoicedHighestFmVoice);
+ //warning("priority old %d, priority new %d", unvoicedHighestPriority, voicedLowestPriority);
+
+ releaseFmVoice(voicedLowestFmVoice);
+
+ // Get some data of the unvoiced highest priority virtual FM Voice
+ midiChannel = _virtualFmVoices[unvoicedHighestFmVoice].actualMidiChannel;
+
+ // Another voice active on this MIDI channel
+ _midiChannels[midiChannel].currentActiveVoicesCount++;
+
+ // Mark virtual FM-Voice as being connected to physical FM-Voice
+ _virtualFmVoices[unvoicedHighestFmVoice].isPhysical = true;
+ _virtualFmVoices[unvoicedHighestFmVoice].physicalFmVoice = physicalFmVoice;
+
+ // Mark physical FM-Voice as being connected to virtual FM-Voice
+ _physicalFmVoices[physicalFmVoice].inUse = true;
+ _physicalFmVoices[physicalFmVoice].virtualFmVoice = unvoicedHighestFmVoice;
+
+ // Update the physical FM-Voice
+ updatePhysicalFmVoice(unvoicedHighestFmVoice, true, kMilesAdLibUpdateFlags_Reg_All);
+
+ virtualFmVoicesCount--;
+ }
+}
+
+void MidiDriver_Miles_AdLib::releaseFmVoice(byte virtualFmVoice) {
+ // virtual Voice not actually played? -> exit
+ if (!_virtualFmVoices[virtualFmVoice].isPhysical) {
+ _virtualFmVoices[virtualFmVoice].inUse = false;
+ return;
+ }
+
+ byte midiChannel = _virtualFmVoices[virtualFmVoice].actualMidiChannel;
+ byte physicalFmVoice = _virtualFmVoices[virtualFmVoice].physicalFmVoice;
+
+ // stop note from playing
+ updatePhysicalFmVoice(virtualFmVoice, false, kMilesAdLibUpdateFlags_Reg_A0);
+
+ // this virtual FM voice isn't physical anymore
+ _virtualFmVoices[virtualFmVoice].isPhysical = false;
+ _virtualFmVoices[virtualFmVoice].inUse = false;
+
+ // Remove physical FM-Voice from being active
+ _physicalFmVoices[physicalFmVoice].inUse = false;
+
+ // One less voice active on this MIDI channel
+ assert(_midiChannels[midiChannel].currentActiveVoicesCount);
+ _midiChannels[midiChannel].currentActiveVoicesCount--;
+}
+
+void MidiDriver_Miles_AdLib::releaseSustain(byte midiChannel) {
+ // Search through all virtual FM-Voices for currently sustained notes and call noteOff on them
+ for (byte virtualFmVoice = 0; virtualFmVoice < _modeVirtualFmVoicesCount; virtualFmVoice++) {
+ if (_virtualFmVoices[virtualFmVoice].inUse) {
+ if ((_virtualFmVoices[virtualFmVoice].actualMidiChannel == midiChannel) && (_virtualFmVoices[virtualFmVoice].sustained)) {
+ // is currently sustained
+ // so do a noteOff (which will check current sustain controller)
+ noteOff(midiChannel, _virtualFmVoices[virtualFmVoice].currentOriginalMidiNote);
+ }
+ }
+ }
+}
+
+void MidiDriver_Miles_AdLib::updatePhysicalFmVoice(byte virtualFmVoice, bool keyOn, uint16 registerUpdateFlags) {
+ byte midiChannel = _virtualFmVoices[virtualFmVoice].actualMidiChannel;
+
+ if (!_virtualFmVoices[virtualFmVoice].isPhysical) {
+ // virtual FM-Voice has no physical FM-Voice assigned? -> ignore
+ return;
+ }
+
+ byte physicalFmVoice = _virtualFmVoices[virtualFmVoice].physicalFmVoice;
+ const InstrumentEntry *instrumentPtr = _virtualFmVoices[virtualFmVoice].currentInstrumentPtr;
+
+ uint16 op1Reg = milesAdLibOperator1Register[physicalFmVoice];
+ uint16 op2Reg = milesAdLibOperator2Register[physicalFmVoice];
+ uint16 channelReg = milesAdLibChannelRegister[physicalFmVoice];
+
+ uint16 compositeVolume = 0;
+
+ if (registerUpdateFlags & kMilesAdLibUpdateFlags_Reg_40) {
+ // Calculate new volume
+ byte midiVolume = _midiChannels[midiChannel].currentVolume;
+ byte midiVolumeExpression = _midiChannels[midiChannel].currentVolumeExpression;
+ compositeVolume = midiVolume * midiVolumeExpression * 2;
+
+ compositeVolume = compositeVolume >> 8; // get upmost 8 bits
+ if (compositeVolume)
+ compositeVolume++; // round up in case result wasn't 0
+
+ compositeVolume = compositeVolume * _virtualFmVoices[virtualFmVoice].currentVelocity * 2;
+ compositeVolume = compositeVolume >> 8; // get upmost 8 bits
+ if (compositeVolume)
+ compositeVolume++; // round up in case result wasn't 0
+ }
+
+ if (registerUpdateFlags & kMilesAdLibUpdateFlags_Reg_20) {
+ // Amplitude Modulation / Vibrato / Envelope Generator Type / Keyboard Scaling Rate / Modulator Frequency Multiple
+ byte reg20op1 = instrumentPtr->reg20op1;
+ byte reg20op2 = instrumentPtr->reg20op2;
+
+ if (_midiChannels[midiChannel].currentModulation >= 64) {
+ // set bit 6 (Vibrato)
+ reg20op1 |= 0x40;
+ reg20op2 |= 0x40;
+ }
+ setRegister(0x20 + op1Reg, reg20op1);
+ setRegister(0x20 + op2Reg, reg20op2);
+ }
+
+ if (registerUpdateFlags & kMilesAdLibUpdateFlags_Reg_40) {
+ // Volume (Level Key Scaling / Total Level)
+ byte reg40op1 = instrumentPtr->reg40op1;
+ byte reg40op2 = instrumentPtr->reg40op2;
+
+ uint16 volumeOp1 = (~reg40op1) & 0x3F;
+ uint16 volumeOp2 = (~reg40op2) & 0x3F;
+
+ if (instrumentPtr->regC0 & 1) {
+ // operator 2 enabled
+ // scale volume factor
+ volumeOp1 = (volumeOp1 * compositeVolume) / 127;
+ // 2nd operator always scaled
+ }
+
+ volumeOp2 = (volumeOp2 * compositeVolume) / 127;
+
+ volumeOp1 = (~volumeOp1) & 0x3F; // negate it, so we get the proper value for the register
+ volumeOp2 = (~volumeOp2) & 0x3F; // ditto
+ reg40op1 = (reg40op1 & 0xC0) | volumeOp1; // keep "scaling level" and merge in our volume
+ reg40op2 = (reg40op2 & 0xC0) | volumeOp2;
+
+ setRegister(0x40 + op1Reg, reg40op1);
+ setRegister(0x40 + op2Reg, reg40op2);
+ }
+
+ if (registerUpdateFlags & kMilesAdLibUpdateFlags_Reg_60) {
+ // Attack Rate / Decay Rate
+ // Sustain Level / Release Rate
+ byte reg60op1 = instrumentPtr->reg60op1;
+ byte reg60op2 = instrumentPtr->reg60op2;
+ byte reg80op1 = instrumentPtr->reg80op1;
+ byte reg80op2 = instrumentPtr->reg80op2;
+
+ setRegister(0x60 + op1Reg, reg60op1);
+ setRegister(0x60 + op2Reg, reg60op2);
+ setRegister(0x80 + op1Reg, reg80op1);
+ setRegister(0x80 + op2Reg, reg80op2);
+ }
+
+ if (registerUpdateFlags & kMilesAdLibUpdateFlags_Reg_E0) {
+ // Waveform Select
+ byte regE0op1 = instrumentPtr->regE0op1;
+ byte regE0op2 = instrumentPtr->regE0op2;
+
+ setRegister(0xE0 + op1Reg, regE0op1);
+ setRegister(0xE0 + op2Reg, regE0op2);
+ }
+
+ if (registerUpdateFlags & kMilesAdLibUpdateFlags_Reg_C0) {
+ // Feedback / Algorithm
+ byte regC0 = instrumentPtr->regC0;
+
+ if (_modeOPL3) {
+ // Panning for OPL3
+ byte panning = _midiChannels[midiChannel].currentPanning;
+
+ if (panning <= MILES_ADLIB_STEREO_PANNING_THRESHOLD_LEFT) {
+ regC0 |= 0x20; // left speaker only
+ } else if (panning >= MILES_ADLIB_STEREO_PANNING_THRESHOLD_RIGHT) {
+ regC0 |= 0x10; // right speaker only
+ } else {
+ regC0 |= 0x30; // center
+ }
+ }
+
+ setRegister(0xC0 + channelReg, regC0);
+ }
+
+ if (registerUpdateFlags & kMilesAdLibUpdateFlags_Reg_A0) {
+ // Frequency / Key-On
+ // Octave / F-Number / Key-On
+ if (!keyOn) {
+ // turn off note
+ byte regB0 = _physicalFmVoices[physicalFmVoice].currentB0hReg & 0x1F; // remove bit 5 "key on"
+ setRegister(0xB0 + channelReg, regB0);
+
+ } else {
+ // turn on note, calculate frequency, octave...
+ int16 pitchBender = _midiChannels[midiChannel].currentPitchBender;
+ byte pitchRange = _midiChannels[midiChannel].currentPitchRange;
+ int16 currentNote = _virtualFmVoices[virtualFmVoice].currentNote;
+ int16 physicalNote = 0;
+ int16 halfTone = 0;
+ uint16 frequency = 0;
+ uint16 frequencyIdx = 0;
+ byte octave = 0;
+
+ pitchBender -= 0x2000;
+ pitchBender = pitchBender >> 5; // divide by 32
+ pitchBender = pitchBender * pitchRange; // pitchrange 12: now +0x0C00 to -0xC00
+ // difference between Miles Audio 2 + 3
+ // Miles Audio 2 used a pitch range of 12, which was basically hardcoded
+ // Miles Audio 3 used an array, which got set by control change events
+
+ currentNote += _virtualFmVoices->currentTransposition;
+
+ // Normalize note
+ currentNote -= 24;
+ do {
+ currentNote += 12;
+ } while (currentNote < 0);
+ currentNote += 12;
+
+ do {
+ currentNote -= 12;
+ } while (currentNote > 95);
+
+ // combine note + pitchbender, also adjust by 8 for rounding
+ currentNote = (currentNote << 8) + pitchBender + 8;
+
+ currentNote = currentNote >> 4; // get actual note
+
+ // Normalize
+ currentNote -= (12 * 16);
+ do {
+ currentNote += (12 * 16);
+ } while (currentNote < 0);
+
+ currentNote += (12 * 16);
+ do {
+ currentNote -= (12 * 16);
+ } while (currentNote > ((96 * 16) - 1));
+
+ physicalNote = currentNote >> 4;
+
+ halfTone = physicalNote % 12; // remainder of physicalNote / 12
+
+ frequencyIdx = (halfTone << 4) + (currentNote & 0x0F);
+ assert(frequencyIdx < sizeof(milesAdLibFrequencyLookUpTable));
+ frequency = milesAdLibFrequencyLookUpTable[frequencyIdx];
+
+ octave = (physicalNote / 12) - 1;
+
+ if (frequency & 0x8000)
+ octave++;
+
+ if (octave & 0x80) {
+ octave++;
+ frequency = frequency >> 1;
+ }
+
+ byte regA0 = frequency & 0xFF;
+ byte regB0 = ((frequency >> 8) & 0x03) | (octave << 2) | 0x20;
+
+ setRegister(0xA0 + channelReg, regA0);
+ setRegister(0xB0 + channelReg, regB0);
+
+ _physicalFmVoices[physicalFmVoice].currentB0hReg = regB0;
+ }
+ }
+
+ //warning("end of update voice");
+}
+
+void MidiDriver_Miles_AdLib::controlChange(byte midiChannel, byte controllerNumber, byte controllerValue) {
+ uint16 registerUpdateFlags = kMilesAdLibUpdateFlags_None;
+
+ switch (controllerNumber) {
+ case MILES_CONTROLLER_SELECT_PATCH_BANK:
+ //warning("patch bank channel %d, bank %x", midiChannel, controllerValue);
+ _midiChannels[midiChannel].currentPatchBank = controllerValue;
+ break;
+
+ case MILES_CONTROLLER_PROTECT_VOICE:
+ _midiChannels[midiChannel].currentVoiceProtection = controllerValue;
+ break;
+
+ case MILES_CONTROLLER_PROTECT_TIMBRE:
+ // It seems that this can get ignored, because we don't cache timbres at all
+ break;
+
+ case MILES_CONTROLLER_MODULATION:
+ _midiChannels[midiChannel].currentModulation = controllerValue;
+ registerUpdateFlags = kMilesAdLibUpdateFlags_Reg_20;
+ break;
+
+ case MILES_CONTROLLER_VOLUME:
+ _midiChannels[midiChannel].currentVolume = controllerValue;
+ registerUpdateFlags = kMilesAdLibUpdateFlags_Reg_40;
+ break;
+
+ case MILES_CONTROLLER_EXPRESSION:
+ _midiChannels[midiChannel].currentVolumeExpression = controllerValue;
+ registerUpdateFlags = kMilesAdLibUpdateFlags_Reg_40;
+ break;
+
+ case MILES_CONTROLLER_PANNING:
+ _midiChannels[midiChannel].currentPanning = controllerValue;
+ if (_modeStereo) {
+ // Update register only in case we are in stereo mode
+ registerUpdateFlags = kMilesAdLibUpdateFlags_Reg_C0;
+ }
+ break;
+
+ case MILES_CONTROLLER_SUSTAIN:
+ _midiChannels[midiChannel].currentSustain = controllerValue;
+ if (controllerValue < 64) {
+ releaseSustain(midiChannel);
+ }
+ break;
+
+ case MILES_CONTROLLER_PITCH_RANGE:
+ // Miles Audio 3 feature
+ _midiChannels[midiChannel].currentPitchRange = controllerValue;
+ break;
+
+ case MILES_CONTROLLER_RESET_ALL:
+ _midiChannels[midiChannel].currentSustain = 0;
+ releaseSustain(midiChannel);
+ _midiChannels[midiChannel].currentModulation = 0;
+ _midiChannels[midiChannel].currentVolumeExpression = 127;
+ _midiChannels[midiChannel].currentPitchBender = MILES_PITCHBENDER_DEFAULT;
+ registerUpdateFlags = kMilesAdLibUpdateFlags_Reg_20 | kMilesAdLibUpdateFlags_Reg_40 | kMilesAdLibUpdateFlags_Reg_A0;
+ break;
+
+ case MILES_CONTROLLER_ALL_NOTES_OFF:
+ for (byte virtualFmVoice = 0; virtualFmVoice < _modeVirtualFmVoicesCount; virtualFmVoice++) {
+ if (_virtualFmVoices[virtualFmVoice].inUse) {
+ // used
+ if (_virtualFmVoices[virtualFmVoice].actualMidiChannel == midiChannel) {
+ // by our current MIDI channel -> noteOff
+ noteOff(midiChannel, _virtualFmVoices[virtualFmVoice].currentNote);
+ }
+ }
+ }
+ break;
+
+ default:
+ //warning("MILES-ADLIB: Unsupported control change %d", controllerNumber);
+ break;
+ }
+
+ if (registerUpdateFlags) {
+ for (byte virtualFmVoice = 0; virtualFmVoice < _modeVirtualFmVoicesCount; virtualFmVoice++) {
+ if (_virtualFmVoices[virtualFmVoice].inUse) {
+ // used
+ if (_virtualFmVoices[virtualFmVoice].actualMidiChannel == midiChannel) {
+ // by our current MIDI channel -> update
+ updatePhysicalFmVoice(virtualFmVoice, true, registerUpdateFlags);
+ }
+ }
+ }
+ }
+}
+
+void MidiDriver_Miles_AdLib::programChange(byte midiChannel, byte patchId) {
+ const InstrumentEntry *instrumentPtr = NULL;
+ byte patchBank = _midiChannels[midiChannel].currentPatchBank;
+
+ //warning("patch channel %d, patch %x, bank %x", midiChannel, patchId, patchBank);
+
+ // we check, if we actually have data for the requested instrument...
+ instrumentPtr = searchInstrument(patchBank, patchId);
+ if (!instrumentPtr) {
+ warning("MILES-ADLIB: unknown instrument requested (%d, %d)", patchBank, patchId);
+ return;
+ }
+
+ // and remember it in that case for the current MIDI-channel
+ _midiChannels[midiChannel].currentInstrumentPtr = instrumentPtr;
+}
+
+const InstrumentEntry *MidiDriver_Miles_AdLib::searchInstrument(byte bankId, byte patchId) {
+ const InstrumentEntry *instrumentPtr = _instrumentTablePtr;
+
+ for (uint16 instrumentNr = 0; instrumentNr < _instrumentTableCount; instrumentNr++) {
+ if ((instrumentPtr->bankId == bankId) && (instrumentPtr->patchId == patchId)) {
+ return instrumentPtr;
+ }
+ instrumentPtr++;
+ }
+
+ return NULL;
+}
+
+void MidiDriver_Miles_AdLib::pitchBendChange(byte midiChannel, byte parameter1, byte parameter2) {
+ // Miles Audio actually didn't shift parameter 2 1 down in here
+ // which means in memory it used a 15-bit pitch bender, which also means the default was 0x4000
+ if ((parameter1 & 0x80) || (parameter2 & 0x80)) {
+ warning("MILES-ADLIB: invalid pitch bend change");
+ return;
+ }
+ _midiChannels[midiChannel].currentPitchBender = parameter1 | (parameter2 << 7);
+}
+
+void MidiDriver_Miles_AdLib::setRegister(int reg, int value) {
+ if (!(reg & 0x100)) {
+ _opl->write(0x220, reg);
+ _opl->write(0x221, value);
+ //warning("OPL write %x %x (%d)", reg, value, value);
+ } else {
+ _opl->write(0x222, reg & 0xFF);
+ _opl->write(0x223, value);
+ //warning("OPL3 write %x %x (%d)", reg & 0xFF, value, value);
+ }
+}
+
+uint32 MidiDriver_Miles_AdLib::property(int prop, uint32 param) {
+ return 0;
+}
+
+MidiDriver *MidiDriver_Miles_AdLib_create(const Common::String &filenameAdLib, const Common::String &filenameOPL3, Common::SeekableReadStream *streamAdLib, Common::SeekableReadStream *streamOPL3) {
+ // Load adlib instrument data from file SAMPLE.AD (OPL3: SAMPLE.OPL)
+ Common::String timbreFilename;
+ Common::SeekableReadStream *timbreStream = nullptr;
+
+ bool preferOPL3 = false;
+
+ Common::File *fileStream = new Common::File();
+ uint32 fileSize = 0;
+ uint32 fileDataOffset = 0;
+ uint32 fileDataLeft = 0;
+
+
+ uint32 streamSize = 0;
+ byte *streamDataPtr = nullptr;
+
+ byte curBankId = 0;
+ byte curPatchId = 0;
+
+ InstrumentEntry *instrumentTablePtr = nullptr;
+ uint16 instrumentTableCount = 0;
+ InstrumentEntry *instrumentPtr = nullptr;
+ uint32 instrumentOffset = 0;
+ uint16 instrumentDataSize = 0;
+
+ // Logic:
+ // We prefer OPL3 timbre data in case OPL3 is available in ScummVM
+ // If it's not or OPL3 timbre data is not available, we go for AdLib timbre data
+ // And if OPL3 is not available in ScummVM and also AdLib timbre data is not available,
+ // we then still go for OPL3 timbre data.
+ //
+ // Note: for most games OPL3 timbre data + AdLib timbre data is the same.
+ // And at least in theory we should still be able to use OPL3 timbre data even for AdLib.
+ // However there is a special OPL3-specific timbre format, which is currently not supported.
+ // In this case the error message "unsupported instrument size" should appear. I haven't found
+ // a game that uses it, which is why I haven't implemented it yet.
+
+ if (OPL::Config::detect(OPL::Config::kOpl3) >= 0) {
+ // OPL3 available, prefer OPL3 timbre data because of this
+ preferOPL3 = true;
+ }
+
+ // Check if streams were passed to us and select one of them
+ if ((streamAdLib) || (streamOPL3)) {
+ // At least one stream was passed by caller
+ if (preferOPL3) {
+ // Prefer OPL3 timbre stream in case OPL3 is available
+ timbreStream = streamOPL3;
+ }
+ if (!timbreStream) {
+ // Otherwise prefer AdLib timbre stream first
+ if (streamAdLib) {
+ timbreStream = streamAdLib;
+ } else {
+ // If not available, use OPL3 timbre stream
+ if (streamOPL3) {
+ timbreStream = streamOPL3;
+ }
+ }
+ }
+ }
+
+ // Now check if any filename was passed to us
+ if ((!filenameAdLib.empty()) || (!filenameOPL3.empty())) {
+ // If that's the case, check if one of those exists
+ if (preferOPL3) {
+ // OPL3 available
+ if (!filenameOPL3.empty()) {
+ if (fileStream->exists(filenameOPL3)) {
+ // If OPL3 available, prefer OPL3 timbre file in case file exists
+ timbreFilename = filenameOPL3;
+ }
+ }
+ if (timbreFilename.empty()) {
+ if (!filenameAdLib.empty()) {
+ if (fileStream->exists(filenameAdLib)) {
+ // otherwise use AdLib timbre file, if it exists
+ timbreFilename = filenameAdLib;
+ }
+ }
+ }
+ } else {
+ // OPL3 not available
+ // Prefer the AdLib one for now
+ if (!filenameAdLib.empty()) {
+ if (fileStream->exists(filenameAdLib)) {
+ // if AdLib file exists, use it
+ timbreFilename = filenameAdLib;
+ }
+ }
+ if (timbreFilename.empty()) {
+ if (!filenameOPL3.empty()) {
+ if (fileStream->exists(filenameOPL3)) {
+ // if OPL3 file exists, use it
+ timbreFilename = filenameOPL3;
+ }
+ }
+ }
+ }
+ if (timbreFilename.empty() && (!timbreStream)) {
+ // If none of them exists and also no stream was passed, we can't do anything about it
+ if (!filenameAdLib.empty()) {
+ if (!filenameOPL3.empty()) {
+ error("MILES-ADLIB: could not open timbre file (%s or %s)", filenameAdLib.c_str(), filenameOPL3.c_str());
+ } else {
+ error("MILES-ADLIB: could not open timbre file (%s)", filenameAdLib.c_str());
+ }
+ } else {
+ error("MILES-ADLIB: could not open timbre file (%s)", filenameOPL3.c_str());
+ }
+ }
+ }
+
+ if (!timbreFilename.empty()) {
+ // Filename was passed to us and file exists (this is the common case for most games)
+ // We prefer this situation
+
+ if (!fileStream->open(timbreFilename))
+ error("MILES-ADLIB: could not open timbre file (%s)", timbreFilename.c_str());
+
+ streamSize = fileStream->size();
+
+ streamDataPtr = new byte[streamSize];
+
+ if (fileStream->read(streamDataPtr, streamSize) != streamSize)
+ error("MILES-ADLIB: error while reading timbre file (%s)", timbreFilename.c_str());
+ fileStream->close();
+
+ } else if (timbreStream) {
+ // Timbre data was passed directly (possibly read from resource file by caller)
+ // Currently used by "Amazon Guardians of Eden", "Simon 2" and "Return To Zork"
+ streamSize = timbreStream->size();
+
+ streamDataPtr = new byte[streamSize];
+
+ if (timbreStream->read(streamDataPtr, streamSize) != streamSize)
+ error("MILES-ADLIB: error while reading timbre stream");
+
+ } else {
+ error("MILES-ADLIB: timbre filenames nor timbre stream were passed");
+ }
+
+ delete fileStream;
+
+ // File is like this:
+ // [patch:BYTE] [bank:BYTE] [patchoffset:UINT32]
+ // ...
+ // until patch + bank are both 0xFF, which signals end of header
+
+ // First we check how many entries there are
+ fileDataOffset = 0;
+ fileDataLeft = streamSize;
+ while (1) {
+ if (fileDataLeft < 6)
+ error("MILES-ADLIB: unexpected EOF in instrument file");
+
+ curPatchId = streamDataPtr[fileDataOffset++];
+ curBankId = streamDataPtr[fileDataOffset++];
+
+ if ((curBankId == 0xFF) && (curPatchId == 0xFF))
+ break;
+
+ fileDataOffset += 4; // skip over offset
+ instrumentTableCount++;
+ }
+
+ if (instrumentTableCount == 0)
+ error("MILES-ADLIB: no instruments in instrument file");
+
+ // Allocate space for instruments
+ instrumentTablePtr = new InstrumentEntry[instrumentTableCount];
+
+ // Now actually read all entries
+ instrumentPtr = instrumentTablePtr;
+
+ fileDataOffset = 0;
+ fileDataLeft = fileSize;
+ while (1) {
+ curPatchId = streamDataPtr[fileDataOffset++];
+ curBankId = streamDataPtr[fileDataOffset++];
+
+ if ((curBankId == 0xFF) && (curPatchId == 0xFF))
+ break;
+
+ instrumentOffset = READ_LE_UINT32(streamDataPtr + fileDataOffset);
+ fileDataOffset += 4;
+
+ instrumentPtr->bankId = curBankId;
+ instrumentPtr->patchId = curPatchId;
+
+ instrumentDataSize = READ_LE_UINT16(streamDataPtr + instrumentOffset);
+ if (instrumentDataSize != 14)
+ error("MILES-ADLIB: unsupported instrument size");
+
+ instrumentPtr->transposition = (signed char)streamDataPtr[instrumentOffset + 2];
+ instrumentPtr->reg20op1 = streamDataPtr[instrumentOffset + 3];
+ instrumentPtr->reg40op1 = streamDataPtr[instrumentOffset + 4];
+ instrumentPtr->reg60op1 = streamDataPtr[instrumentOffset + 5];
+ instrumentPtr->reg80op1 = streamDataPtr[instrumentOffset + 6];
+ instrumentPtr->regE0op1 = streamDataPtr[instrumentOffset + 7];
+ instrumentPtr->regC0 = streamDataPtr[instrumentOffset + 8];
+ instrumentPtr->reg20op2 = streamDataPtr[instrumentOffset + 9];
+ instrumentPtr->reg40op2 = streamDataPtr[instrumentOffset + 10];
+ instrumentPtr->reg60op2 = streamDataPtr[instrumentOffset + 11];
+ instrumentPtr->reg80op2 = streamDataPtr[instrumentOffset + 12];
+ instrumentPtr->regE0op2 = streamDataPtr[instrumentOffset + 13];
+
+ // Instrument read, next instrument please
+ instrumentPtr++;
+ }
+
+ // Free instrument file/stream data
+ delete[] streamDataPtr;
+
+ return new MidiDriver_Miles_AdLib(instrumentTablePtr, instrumentTableCount);
+}
+
+} // End of namespace Audio
diff --git a/audio/miles_mt32.cpp b/audio/miles_mt32.cpp
new file mode 100644
index 0000000000..dff863f119
--- /dev/null
+++ b/audio/miles_mt32.cpp
@@ -0,0 +1,912 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public 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/miles.h"
+
+#include "common/config-manager.h"
+#include "common/file.h"
+#include "common/mutex.h"
+#include "common/system.h"
+#include "common/textconsole.h"
+
+namespace Audio {
+
+// Miles Audio MT32 driver
+//
+
+#define MILES_MT32_PATCHES_COUNT 128
+#define MILES_MT32_CUSTOMTIMBRE_COUNT 64
+
+#define MILES_MT32_TIMBREBANK_STANDARD_ROLAND 0
+#define MILES_MT32_TIMBREBANK_MELODIC_MODULE 127
+
+#define MILES_MT32_PATCHDATA_COMMONPARAMETER_SIZE 14
+#define MILES_MT32_PATCHDATA_PARTIALPARAMETER_SIZE 58
+#define MILES_MT32_PATCHDATA_PARTIALPARAMETERS_COUNT 4
+#define MILES_MT32_PATCHDATA_TOTAL_SIZE (MILES_MT32_PATCHDATA_COMMONPARAMETER_SIZE + (MILES_MT32_PATCHDATA_PARTIALPARAMETER_SIZE * MILES_MT32_PATCHDATA_PARTIALPARAMETERS_COUNT))
+
+#define MILES_MT32_SYSEX_TERMINATOR 0xFF
+
+struct MilesMT32InstrumentEntry {
+ byte bankId;
+ byte patchId;
+ byte commonParameter[MILES_MT32_PATCHDATA_COMMONPARAMETER_SIZE + 1];
+ byte partialParameters[MILES_MT32_PATCHDATA_PARTIALPARAMETERS_COUNT][MILES_MT32_PATCHDATA_PARTIALPARAMETER_SIZE + 1];
+};
+
+const byte milesMT32SysExResetParameters[] = {
+ 0x01, MILES_MT32_SYSEX_TERMINATOR
+};
+
+const byte milesMT32SysExChansSetup[] = {
+ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, MILES_MT32_SYSEX_TERMINATOR
+};
+
+const byte milesMT32SysExPartialReserveTable[] = {
+ 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x04, MILES_MT32_SYSEX_TERMINATOR
+};
+
+const byte milesMT32SysExInitReverb[] = {
+ 0x00, 0x03, 0x02, MILES_MT32_SYSEX_TERMINATOR // Reverb mode 0, reverb time 3, reverb level 2
+};
+
+class MidiDriver_Miles_MT32 : public MidiDriver {
+public:
+ MidiDriver_Miles_MT32(MilesMT32InstrumentEntry *instrumentTablePtr, uint16 instrumentTableCount);
+ virtual ~MidiDriver_Miles_MT32();
+
+ // MidiDriver
+ int open();
+ void close();
+ bool isOpen() const { return _isOpen; }
+
+ void send(uint32 b);
+
+ MidiChannel *allocateChannel() {
+ if (_driver)
+ return _driver->allocateChannel();
+ return NULL;
+ }
+ MidiChannel *getPercussionChannel() {
+ if (_driver)
+ return _driver->getPercussionChannel();
+ return NULL;
+ }
+
+ void setTimerCallback(void *timer_param, Common::TimerManager::TimerProc timer_proc) {
+ if (_driver)
+ _driver->setTimerCallback(timer_param, timer_proc);
+ }
+
+ uint32 getBaseTempo() {
+ if (_driver) {
+ return _driver->getBaseTempo();
+ }
+ return 1000000 / _baseFreq;
+ }
+
+protected:
+ Common::Mutex _mutex;
+ MidiDriver *_driver;
+ bool _MT32;
+ bool _nativeMT32;
+
+ bool _isOpen;
+ int _baseFreq;
+
+public:
+ void processXMIDITimbreChunk(const byte *timbreListPtr, uint32 timbreListSize);
+
+private:
+ void resetMT32();
+
+ void MT32SysEx(const uint32 targetAddress, const byte *dataPtr);
+
+ uint32 calculateSysExTargetAddress(uint32 baseAddress, uint32 index);
+
+ void writeRhythmSetup(byte note, byte customTimbreId);
+ void writePatchTimbre(byte patchId, byte timbreGroup, byte timbreId);
+ void writePatchByte(byte patchId, byte index, byte patchValue);
+ void writeToSystemArea(byte index, byte value);
+
+ void controlChange(byte midiChannel, byte controllerNumber, byte controllerValue);
+ void programChange(byte midiChannel, byte patchId);
+
+ const MilesMT32InstrumentEntry *searchCustomInstrument(byte patchBank, byte patchId);
+ int16 searchCustomTimbre(byte patchBank, byte patchId);
+
+ void setupPatch(byte patchBank, byte patchId);
+ int16 installCustomTimbre(byte patchBank, byte patchId);
+
+private:
+ struct MidiChannelEntry {
+ byte currentPatchBank;
+ byte currentPatchId;
+
+ bool usingCustomTimbre;
+ byte currentCustomTimbreId;
+
+ MidiChannelEntry() : currentPatchBank(0),
+ currentPatchId(0),
+ usingCustomTimbre(false),
+ currentCustomTimbreId(0) { }
+ };
+
+ struct MidiCustomTimbreEntry {
+ bool used;
+ bool protectionEnabled;
+ byte currentPatchBank;
+ byte currentPatchId;
+
+ uint32 lastUsedNoteCounter;
+
+ MidiCustomTimbreEntry() : used(false),
+ protectionEnabled(false),
+ currentPatchBank(0),
+ currentPatchId(0),
+ lastUsedNoteCounter(0) {}
+ };
+
+ struct MilesMT32SysExQueueEntry {
+ uint32 targetAddress;
+ byte dataPos;
+ byte data[MILES_CONTROLLER_SYSEX_QUEUE_SIZE + 1]; // 1 extra byte for terminator
+
+ MilesMT32SysExQueueEntry() : targetAddress(0),
+ dataPos(0) {
+ memset(data, 0, sizeof(data));
+ }
+ };
+
+ // stores information about all MIDI channels
+ MidiChannelEntry _midiChannels[MILES_MIDI_CHANNEL_COUNT];
+
+ // stores information about all custom timbres
+ MidiCustomTimbreEntry _customTimbres[MILES_MT32_CUSTOMTIMBRE_COUNT];
+
+ byte _patchesBank[MILES_MT32_PATCHES_COUNT];
+
+ // holds all instruments
+ MilesMT32InstrumentEntry *_instrumentTablePtr;
+ uint16 _instrumentTableCount;
+
+ uint32 _noteCounter; // used to figure out, which timbres are outdated
+
+ // SysEx Queues
+ MilesMT32SysExQueueEntry _sysExQueues[MILES_CONTROLLER_SYSEX_QUEUE_COUNT];
+};
+
+MidiDriver_Miles_MT32::MidiDriver_Miles_MT32(MilesMT32InstrumentEntry *instrumentTablePtr, uint16 instrumentTableCount) {
+ _instrumentTablePtr = instrumentTablePtr;
+ _instrumentTableCount = instrumentTableCount;
+
+ _driver = NULL;
+ _isOpen = false;
+ _MT32 = false;
+ _nativeMT32 = false;
+ _baseFreq = 250;
+
+ _noteCounter = 0;
+
+ memset(_patchesBank, 0, sizeof(_patchesBank));
+}
+
+MidiDriver_Miles_MT32::~MidiDriver_Miles_MT32() {
+ Common::StackLock lock(_mutex);
+ if (_driver) {
+ _driver->setTimerCallback(0, 0);
+ _driver->close();
+ delete _driver;
+ }
+ _driver = NULL;
+}
+
+int MidiDriver_Miles_MT32::open() {
+ assert(!_driver);
+
+ // Setup midi driver
+ MidiDriver::DeviceHandle dev = MidiDriver::detectDevice(MDT_MIDI | MDT_PREFER_MT32);
+ MusicType musicType = MidiDriver::getMusicType(dev);
+
+ switch (musicType) {
+ case MT_MT32:
+ _nativeMT32 = true;
+ break;
+ case MT_GM:
+ if (ConfMan.getBool("native_mt32")) {
+ _nativeMT32 = true;
+ }
+ break;
+ default:
+ break;
+ }
+
+ if (!_nativeMT32) {
+ error("MILES-MT32: non-mt32 currently not supported!");
+ }
+
+ _driver = MidiDriver::createMidi(dev);
+ if (!_driver)
+ return 255;
+
+ if (_nativeMT32)
+ _driver->property(MidiDriver::PROP_CHANNEL_MASK, 0x03FE);
+
+ int ret = _driver->open();
+ if (ret)
+ return ret;
+
+ if (_nativeMT32) {
+ _driver->sendMT32Reset();
+
+ resetMT32();
+ }
+
+ return 0;
+}
+
+void MidiDriver_Miles_MT32::close() {
+ if (_driver) {
+ _driver->close();
+ }
+}
+
+void MidiDriver_Miles_MT32::resetMT32() {
+ // reset all internal parameters / patches
+ MT32SysEx(0x7F0000, milesMT32SysExResetParameters);
+
+ // init part/channel assignments
+ MT32SysEx(0x10000D, milesMT32SysExChansSetup);
+
+ // partial reserve table
+ MT32SysEx(0x100004, milesMT32SysExPartialReserveTable);
+
+ // init reverb
+ MT32SysEx(0x100001, milesMT32SysExInitReverb);
+}
+
+void MidiDriver_Miles_MT32::MT32SysEx(const uint32 targetAddress, const byte *dataPtr) {
+ byte sysExMessage[270];
+ uint16 sysExPos = 0;
+ byte sysExByte = 0;
+ uint16 sysExChecksum = 0;
+
+ memset(&sysExMessage, 0, sizeof(sysExMessage));
+
+ sysExMessage[0] = 0x41; // Roland
+ sysExMessage[1] = 0x10;
+ sysExMessage[2] = 0x16; // Model MT32
+ sysExMessage[3] = 0x12; // Command DT1
+
+ sysExChecksum = 0;
+
+ sysExMessage[4] = (targetAddress >> 16) & 0xFF;
+ sysExMessage[5] = (targetAddress >> 8) & 0xFF;
+ sysExMessage[6] = targetAddress & 0xFF;
+
+ for (byte targetAddressByte = 4; targetAddressByte < 7; targetAddressByte++) {
+ assert(sysExMessage[targetAddressByte] < 0x80); // security check
+ sysExChecksum -= sysExMessage[targetAddressByte];
+ }
+
+ sysExPos = 7;
+ while (1) {
+ sysExByte = *dataPtr++;
+ if (sysExByte == MILES_MT32_SYSEX_TERMINATOR)
+ break; // Message done
+
+ assert(sysExPos < sizeof(sysExMessage));
+ assert(sysExByte < 0x80); // security check
+ sysExMessage[sysExPos++] = sysExByte;
+ sysExChecksum -= sysExByte;
+ }
+
+ // Calculate checksum
+ assert(sysExPos < sizeof(sysExMessage));
+ sysExMessage[sysExPos++] = sysExChecksum & 0x7f;
+
+ // Send SysEx
+ _driver->sysEx(sysExMessage, sysExPos);
+
+ // Wait the time it takes to send the SysEx data
+ uint32 delay = (sysExPos + 2) * 1000 / 3125;
+
+ // Plus an additional delay for the MT-32 rev00
+ if (_nativeMT32)
+ delay += 40;
+
+ g_system->delayMillis(delay);
+}
+
+// MIDI messages can be found at http://www.midi.org/techspecs/midimessages.php
+void MidiDriver_Miles_MT32::send(uint32 b) {
+ byte command = b & 0xf0;
+ byte midiChannel = b & 0xf;
+ byte op1 = (b >> 8) & 0xff;
+ byte op2 = (b >> 16) & 0xff;
+
+ switch (command) {
+ case 0x80: // note off
+ case 0x90: // note on
+ case 0xa0: // Polyphonic key pressure (aftertouch)
+ case 0xd0: // Channel pressure (aftertouch)
+ case 0xe0: // pitch bend change
+ _noteCounter++;
+ if (_midiChannels[midiChannel].usingCustomTimbre) {
+ // Remember that this timbre got used now
+ _customTimbres[_midiChannels[midiChannel].currentCustomTimbreId].lastUsedNoteCounter = _noteCounter;
+ }
+ _driver->send(b);
+ break;
+ case 0xb0: // Control change
+ controlChange(midiChannel, op1, op2);
+ break;
+ case 0xc0: // Program Change
+ programChange(midiChannel, op1);
+ break;
+ case 0xf0: // SysEx
+ warning("MILES-MT32: SysEx: %x", b);
+ break;
+ default:
+ warning("MILES-MT32: Unknown event %02x", command);
+ }
+}
+
+void MidiDriver_Miles_MT32::controlChange(byte midiChannel, byte controllerNumber, byte controllerValue) {
+ byte channelPatchId = 0;
+ byte channelCustomTimbreId = 0;
+
+ switch (controllerNumber) {
+ case MILES_CONTROLLER_SELECT_PATCH_BANK:
+ _midiChannels[midiChannel].currentPatchBank = controllerValue;
+ return;
+
+ case MILES_CONTROLLER_PATCH_REVERB:
+ channelPatchId = _midiChannels[midiChannel].currentPatchId;
+
+ writePatchByte(channelPatchId, 6, controllerValue);
+ _driver->send(0xC0 | midiChannel | (channelPatchId << 8)); // execute program change
+ return;
+
+ case MILES_CONTROLLER_PATCH_BENDER:
+ channelPatchId = _midiChannels[midiChannel].currentPatchId;
+
+ writePatchByte(channelPatchId, 4, controllerValue);
+ _driver->send(0xC0 | midiChannel | (channelPatchId << 8)); // execute program change
+ return;
+
+ case MILES_CONTROLLER_REVERB_MODE:
+ writeToSystemArea(1, controllerValue);
+ return;
+
+ case MILES_CONTROLLER_REVERB_TIME:
+ writeToSystemArea(2, controllerValue);
+ return;
+
+ case MILES_CONTROLLER_REVERB_LEVEL:
+ writeToSystemArea(3, controllerValue);
+ return;
+
+ case MILES_CONTROLLER_RHYTHM_KEY_TIMBRE:
+ if (_midiChannels[midiChannel].usingCustomTimbre) {
+ // custom timbre is set on current channel
+ writeRhythmSetup(controllerValue, _midiChannels[midiChannel].currentCustomTimbreId);
+ }
+ return;
+
+ case MILES_CONTROLLER_PROTECT_TIMBRE:
+ if (_midiChannels[midiChannel].usingCustomTimbre) {
+ // custom timbre set on current channel
+ channelCustomTimbreId = _midiChannels[midiChannel].currentCustomTimbreId;
+ if (controllerValue >= 64) {
+ // enable protection
+ _customTimbres[channelCustomTimbreId].protectionEnabled = true;
+ } else {
+ // disable protection
+ _customTimbres[channelCustomTimbreId].protectionEnabled = false;
+ }
+ }
+ return;
+
+ default:
+ break;
+ }
+
+ if ((controllerNumber >= MILES_CONTROLLER_SYSEX_RANGE_BEGIN) && (controllerNumber <= MILES_CONTROLLER_SYSEX_RANGE_END)) {
+ // send SysEx
+ byte sysExQueueNr = 0;
+
+ // figure out which queue is accessed
+ controllerNumber -= MILES_CONTROLLER_SYSEX_RANGE_BEGIN;
+ while (controllerNumber > MILES_CONTROLLER_SYSEX_COMMAND_SEND) {
+ sysExQueueNr++;
+ controllerNumber -= (MILES_CONTROLLER_SYSEX_COMMAND_SEND + 1);
+ }
+ assert(sysExQueueNr < MILES_CONTROLLER_SYSEX_QUEUE_COUNT);
+
+ byte sysExPos = _sysExQueues[sysExQueueNr].dataPos;
+ bool sysExSend = false;
+
+ switch(controllerNumber) {
+ case MILES_CONTROLLER_SYSEX_COMMAND_ADDRESS1:
+ _sysExQueues[sysExQueueNr].targetAddress &= 0x00FFFF;
+ _sysExQueues[sysExQueueNr].targetAddress |= (controllerValue << 16);
+ break;
+ case MILES_CONTROLLER_SYSEX_COMMAND_ADDRESS2:
+ _sysExQueues[sysExQueueNr].targetAddress &= 0xFF00FF;
+ _sysExQueues[sysExQueueNr].targetAddress |= (controllerValue << 8);
+ break;
+ case MILES_CONTROLLER_SYSEX_COMMAND_ADDRESS3:
+ _sysExQueues[sysExQueueNr].targetAddress &= 0xFFFF00;
+ _sysExQueues[sysExQueueNr].targetAddress |= controllerValue;
+ break;
+ case MILES_CONTROLLER_SYSEX_COMMAND_DATA:
+ if (sysExPos < MILES_CONTROLLER_SYSEX_QUEUE_SIZE) {
+ // Space left? put current byte into queue
+ _sysExQueues[sysExQueueNr].data[sysExPos] = controllerValue;
+ sysExPos++;
+ _sysExQueues[sysExQueueNr].dataPos = sysExPos;
+ if (sysExPos >= MILES_CONTROLLER_SYSEX_QUEUE_SIZE) {
+ // overflow? -> send it now
+ sysExSend = true;
+ }
+ }
+ break;
+ case MILES_CONTROLLER_SYSEX_COMMAND_SEND:
+ sysExSend = true;
+ break;
+ default:
+ assert(0);
+ }
+
+ if (sysExSend) {
+ if (sysExPos > 0) {
+ // data actually available? -> send it
+ _sysExQueues[sysExQueueNr].data[sysExPos] = MILES_MT32_SYSEX_TERMINATOR; // put terminator
+
+ // Execute SysEx
+ MT32SysEx(_sysExQueues[sysExQueueNr].targetAddress, _sysExQueues[sysExQueueNr].data);
+
+ // adjust target address to point at the end of the current data
+ _sysExQueues[sysExQueueNr].targetAddress += sysExPos;
+ // reset queue data buffer
+ _sysExQueues[sysExQueueNr].dataPos = 0;
+ }
+ }
+ return;
+ }
+
+ if ((controllerNumber >= MILES_CONTROLLER_XMIDI_RANGE_BEGIN) && (controllerNumber <= MILES_CONTROLLER_XMIDI_RANGE_END)) {
+ // XMIDI controllers? ignore those
+ return;
+ }
+
+ _driver->send(0xB0 | midiChannel | (controllerNumber << 8) | (controllerValue << 16));
+}
+
+void MidiDriver_Miles_MT32::programChange(byte midiChannel, byte patchId) {
+ byte channelPatchBank = _midiChannels[midiChannel].currentPatchBank;
+ byte activePatchBank = _patchesBank[patchId];
+
+ //warning("patch channel %d, patch %x, bank %x", midiChannel, patchId, channelPatchBank);
+
+ // remember patch id for the current MIDI-channel
+ _midiChannels[midiChannel].currentPatchId = patchId;
+
+ if (channelPatchBank != activePatchBank) {
+ // associate patch with timbre
+ setupPatch(channelPatchBank, patchId);
+ }
+
+ // If this is a custom patch, remember customTimbreId
+ int16 customTimbre = searchCustomTimbre(channelPatchBank, patchId);
+ if (customTimbre >= 0) {
+ _midiChannels[midiChannel].usingCustomTimbre = true;
+ _midiChannels[midiChannel].currentCustomTimbreId = customTimbre;
+ } else {
+ _midiChannels[midiChannel].usingCustomTimbre = false;
+ }
+
+ // Finally send program change to MT32
+ _driver->send(0xC0 | midiChannel | (patchId << 8));
+}
+
+int16 MidiDriver_Miles_MT32::searchCustomTimbre(byte patchBank, byte patchId) {
+ byte customTimbreId = 0;
+
+ for (customTimbreId = 0; customTimbreId < MILES_MT32_CUSTOMTIMBRE_COUNT; customTimbreId++) {
+ if (_customTimbres[customTimbreId].used) {
+ if ((_customTimbres[customTimbreId].currentPatchBank == patchBank) && (_customTimbres[customTimbreId].currentPatchId == patchId)) {
+ return customTimbreId;
+ }
+ }
+ }
+ return -1;
+}
+
+const MilesMT32InstrumentEntry *MidiDriver_Miles_MT32::searchCustomInstrument(byte patchBank, byte patchId) {
+ const MilesMT32InstrumentEntry *instrumentPtr = _instrumentTablePtr;
+
+ for (uint16 instrumentNr = 0; instrumentNr < _instrumentTableCount; instrumentNr++) {
+ if ((instrumentPtr->bankId == patchBank) && (instrumentPtr->patchId == patchId))
+ return instrumentPtr;
+ instrumentPtr++;
+ }
+ return NULL;
+}
+
+void MidiDriver_Miles_MT32::setupPatch(byte patchBank, byte patchId) {
+ _patchesBank[patchId] = patchBank;
+
+ if (patchBank) {
+ // non-built-in bank
+ int16 customTimbreId = searchCustomTimbre(patchBank, patchId);
+ if (customTimbreId >= 0) {
+ // now available? -> use this timbre
+ writePatchTimbre(patchId, 2, customTimbreId); // Group MEMORY
+ return;
+ }
+ }
+
+ // for built-in bank (or timbres, that are not available) use default MT32 timbres
+ byte timbreId = patchId & 0x3F;
+ if (!(patchId & 0x40)) {
+ writePatchTimbre(patchId, 0, timbreId); // Group A
+ } else {
+ writePatchTimbre(patchId, 1, timbreId); // Group B
+ }
+}
+
+void MidiDriver_Miles_MT32::processXMIDITimbreChunk(const byte *timbreListPtr, uint32 timbreListSize) {
+ uint16 timbreCount = 0;
+ uint32 expectedSize = 0;
+ const byte *timbreListSeeker = timbreListPtr;
+
+ if (timbreListSize < 2) {
+ warning("MILES-MT32: XMIDI-TIMB chunk - not enough bytes in chunk");
+ return;
+ }
+
+ timbreCount = READ_LE_UINT16(timbreListPtr);
+ expectedSize = timbreCount * 2;
+ if (expectedSize > timbreListSize) {
+ warning("MILES-MT32: XMIDI-TIMB chunk - size mismatch");
+ return;
+ }
+
+ timbreListSeeker += 2;
+
+ while (timbreCount) {
+ const byte patchId = *timbreListSeeker++;
+ const byte patchBank = *timbreListSeeker++;
+ int16 customTimbreId = 0;
+
+ switch (patchBank) {
+ case MILES_MT32_TIMBREBANK_STANDARD_ROLAND:
+ case MILES_MT32_TIMBREBANK_MELODIC_MODULE:
+ // ignore those 2 banks
+ break;
+
+ default:
+ // Check, if this timbre was already loaded
+ customTimbreId = searchCustomTimbre(patchBank, patchId);
+
+ if (customTimbreId < 0) {
+ // currently not loaded, try to install it
+ installCustomTimbre(patchBank, patchId);
+ }
+ }
+ timbreCount--;
+ }
+}
+
+//
+int16 MidiDriver_Miles_MT32::installCustomTimbre(byte patchBank, byte patchId) {
+ switch(patchBank) {
+ case MILES_MT32_TIMBREBANK_STANDARD_ROLAND: // Standard Roland MT32 bank
+ case MILES_MT32_TIMBREBANK_MELODIC_MODULE: // Reserved for melodic mode
+ return -1;
+ default:
+ break;
+ }
+
+ // Original driver did a search for custom timbre here
+ // and in case it was found, it would call setup_patch()
+ // we are called from within setup_patch(), so this isn't needed
+
+ int16 customTimbreId = -1;
+ int16 leastUsedTimbreId = -1;
+ uint32 leastUsedTimbreNoteCounter = _noteCounter;
+ const MilesMT32InstrumentEntry *instrumentPtr = NULL;
+
+ // Check, if requested instrument is actually available
+ instrumentPtr = searchCustomInstrument(patchBank, patchId);
+ if (!instrumentPtr) {
+ warning("MILES-MT32: instrument not found during installCustomTimbre()");
+ return -1; // not found -> bail out
+ }
+
+ // Look for an empty timbre slot
+ // or get the least used non-protected slot
+ for (byte customTimbreNr = 0; customTimbreNr < MILES_MT32_CUSTOMTIMBRE_COUNT; customTimbreNr++) {
+ if (!_customTimbres[customTimbreNr].used) {
+ // found an empty slot -> use this one
+ customTimbreId = customTimbreNr;
+ break;
+ } else {
+ // used slot
+ if (!_customTimbres[customTimbreNr].protectionEnabled) {
+ // not protected
+ uint32 customTimbreNoteCounter = _customTimbres[customTimbreNr].lastUsedNoteCounter;
+ if (customTimbreNoteCounter < leastUsedTimbreNoteCounter) {
+ leastUsedTimbreId = customTimbreNr;
+ leastUsedTimbreNoteCounter = customTimbreNoteCounter;
+ }
+ }
+ }
+ }
+
+ if (customTimbreId < 0) {
+ // no empty slot found, check if we got a least used non-protected slot
+ if (leastUsedTimbreId < 0) {
+ // everything is protected, bail out
+ warning("MILES-MT32: no non-protected timbre slots available during installCustomTimbre()");
+ return -1;
+ }
+ customTimbreId = leastUsedTimbreId;
+ }
+
+ // setup timbre slot
+ _customTimbres[customTimbreId].used = true;
+ _customTimbres[customTimbreId].currentPatchBank = patchBank;
+ _customTimbres[customTimbreId].currentPatchId = patchId;
+ _customTimbres[customTimbreId].lastUsedNoteCounter = _noteCounter;
+ _customTimbres[customTimbreId].protectionEnabled = false;
+
+ uint32 targetAddress = 0x080000 | (customTimbreId << 9);
+ uint32 targetAddressCommon = targetAddress + 0x000000;
+ uint32 targetAddressPartial1 = targetAddress + 0x00000E;
+ uint32 targetAddressPartial2 = targetAddress + 0x000048;
+ uint32 targetAddressPartial3 = targetAddress + 0x000102;
+ uint32 targetAddressPartial4 = targetAddress + 0x00013C;
+
+#if 0
+ byte parameterData[MILES_MT32_PATCHDATA_TOTAL_SIZE + 1];
+ uint16 parameterDataPos = 0;
+
+ memcpy(parameterData, instrumentPtr->commonParameter, MILES_MT32_PATCHDATA_COMMONPARAMETER_SIZE);
+ parameterDataPos += MILES_MT32_PATCHDATA_COMMONPARAMETER_SIZE;
+ memcpy(parameterData + parameterDataPos, instrumentPtr->partialParameters[0], MILES_MT32_PATCHDATA_PARTIALPARAMETER_SIZE);
+ parameterDataPos += MILES_MT32_PATCHDATA_PARTIALPARAMETER_SIZE;
+ memcpy(parameterData + parameterDataPos, instrumentPtr->partialParameters[1], MILES_MT32_PATCHDATA_PARTIALPARAMETER_SIZE);
+ parameterDataPos += MILES_MT32_PATCHDATA_PARTIALPARAMETER_SIZE;
+ memcpy(parameterData + parameterDataPos, instrumentPtr->partialParameters[2], MILES_MT32_PATCHDATA_PARTIALPARAMETER_SIZE);
+ parameterDataPos += MILES_MT32_PATCHDATA_PARTIALPARAMETER_SIZE;
+ memcpy(parameterData + parameterDataPos, instrumentPtr->partialParameters[3], MILES_MT32_PATCHDATA_PARTIALPARAMETER_SIZE);
+ parameterDataPos += MILES_MT32_PATCHDATA_PARTIALPARAMETER_SIZE;
+ parameterData[parameterDataPos] = MILES_MT32_SYSEX_TERMINATOR;
+
+ MT32SysEx(targetAddressCommon, parameterData);
+#endif
+
+ // upload common parameter data
+ MT32SysEx(targetAddressCommon, instrumentPtr->commonParameter);
+ // upload partial parameter data
+ MT32SysEx(targetAddressPartial1, instrumentPtr->partialParameters[0]);
+ MT32SysEx(targetAddressPartial2, instrumentPtr->partialParameters[1]);
+ MT32SysEx(targetAddressPartial3, instrumentPtr->partialParameters[2]);
+ MT32SysEx(targetAddressPartial4, instrumentPtr->partialParameters[3]);
+
+ setupPatch(patchBank, patchId);
+
+ return customTimbreId;
+}
+
+uint32 MidiDriver_Miles_MT32::calculateSysExTargetAddress(uint32 baseAddress, uint32 index) {
+ uint16 targetAddressLSB = baseAddress & 0xFF;
+ uint16 targetAddressKSB = (baseAddress >> 8) & 0xFF;
+ uint16 targetAddressMSB = (baseAddress >> 16) & 0xFF;
+
+ // add index to it, but use 7-bit of the index for each byte
+ targetAddressLSB += (index & 0x7F);
+ targetAddressKSB += ((index >> 7) & 0x7F);
+ targetAddressMSB += ((index >> 14) & 0x7F);
+
+ // adjust bytes, so that none of them is above or equal 0x80
+ while (targetAddressLSB >= 0x80) {
+ targetAddressLSB -= 0x80;
+ targetAddressKSB++;
+ }
+ while (targetAddressKSB >= 0x80) {
+ targetAddressKSB -= 0x80;
+ targetAddressMSB++;
+ }
+ assert(targetAddressMSB < 0x80);
+
+ // put everything together
+ return targetAddressLSB | (targetAddressKSB << 8) | (targetAddressMSB << 16);
+}
+
+void MidiDriver_Miles_MT32::writeRhythmSetup(byte note, byte customTimbreId) {
+ byte sysExData[2];
+ uint32 targetAddress = 0;
+
+ targetAddress = calculateSysExTargetAddress(0x030110, ((note - 24) << 2));
+
+ sysExData[0] = customTimbreId;
+ sysExData[1] = MILES_MT32_SYSEX_TERMINATOR; // terminator
+
+ MT32SysEx(targetAddress, sysExData);
+}
+
+void MidiDriver_Miles_MT32::writePatchTimbre(byte patchId, byte timbreGroup, byte timbreId) {
+ byte sysExData[3];
+ uint32 targetAddress = 0;
+
+ // write to patch memory (starts at 0x050000, each entry is 8 bytes)
+ targetAddress = calculateSysExTargetAddress(0x050000, patchId << 3);
+
+ sysExData[0] = timbreGroup; // 0 - group A, 1 - group B, 2 - memory, 3 - rhythm
+ sysExData[1] = timbreId; // timbre number (0-63)
+ sysExData[2] = MILES_MT32_SYSEX_TERMINATOR; // terminator
+
+ MT32SysEx(targetAddress, sysExData);
+}
+
+void MidiDriver_Miles_MT32::writePatchByte(byte patchId, byte index, byte patchValue) {
+ byte sysExData[2];
+ uint32 targetAddress = 0;
+
+ targetAddress = calculateSysExTargetAddress(0x050000, (patchId << 3) + index);
+
+ sysExData[0] = patchValue;
+ sysExData[1] = MILES_MT32_SYSEX_TERMINATOR; // terminator
+
+ MT32SysEx(targetAddress, sysExData);
+}
+
+void MidiDriver_Miles_MT32::writeToSystemArea(byte index, byte value) {
+ byte sysExData[2];
+ uint32 targetAddress = 0;
+
+ targetAddress = calculateSysExTargetAddress(0x100000, index);
+
+ sysExData[0] = value;
+ sysExData[1] = MILES_MT32_SYSEX_TERMINATOR; // terminator
+
+ MT32SysEx(targetAddress, sysExData);
+}
+
+MidiDriver *MidiDriver_Miles_MT32_create(const Common::String &instrumentDataFilename) {
+ MilesMT32InstrumentEntry *instrumentTablePtr = NULL;
+ uint16 instrumentTableCount = 0;
+
+ if (!instrumentDataFilename.empty()) {
+ // Load MT32 instrument data from file SAMPLE.MT
+ Common::File *fileStream = new Common::File();
+ uint32 fileSize = 0;
+ byte *fileDataPtr = NULL;
+ uint32 fileDataOffset = 0;
+ uint32 fileDataLeft = 0;
+
+ byte curBankId = 0;
+ byte curPatchId = 0;
+
+ MilesMT32InstrumentEntry *instrumentPtr = NULL;
+ uint32 instrumentOffset = 0;
+ uint16 instrumentDataSize = 0;
+
+ if (!fileStream->open(instrumentDataFilename))
+ error("MILES-MT32: could not open instrument file '%s'", instrumentDataFilename.c_str());
+
+ fileSize = fileStream->size();
+
+ fileDataPtr = new byte[fileSize];
+
+ if (fileStream->read(fileDataPtr, fileSize) != fileSize)
+ error("MILES-MT32: error while reading instrument file");
+ fileStream->close();
+ delete fileStream;
+
+ // File is like this:
+ // [patch:BYTE] [bank:BYTE] [patchoffset:UINT32]
+ // ...
+ // until patch + bank are both 0xFF, which signals end of header
+
+ // First we check how many entries there are
+ fileDataOffset = 0;
+ fileDataLeft = fileSize;
+ while (1) {
+ if (fileDataLeft < 6)
+ error("MILES-MT32: unexpected EOF in instrument file");
+
+ curPatchId = fileDataPtr[fileDataOffset++];
+ curBankId = fileDataPtr[fileDataOffset++];
+
+ if ((curBankId == 0xFF) && (curPatchId == 0xFF))
+ break;
+
+ fileDataOffset += 4; // skip over offset
+ instrumentTableCount++;
+ }
+
+ if (instrumentTableCount == 0)
+ error("MILES-MT32: no instruments in instrument file");
+
+ // Allocate space for instruments
+ instrumentTablePtr = new MilesMT32InstrumentEntry[instrumentTableCount];
+
+ // Now actually read all entries
+ instrumentPtr = instrumentTablePtr;
+
+ fileDataOffset = 0;
+ fileDataLeft = fileSize;
+ while (1) {
+ curPatchId = fileDataPtr[fileDataOffset++];
+ curBankId = fileDataPtr[fileDataOffset++];
+
+ if ((curBankId == 0xFF) && (curPatchId == 0xFF))
+ break;
+
+ instrumentOffset = READ_LE_UINT32(fileDataPtr + fileDataOffset);
+ fileDataOffset += 4;
+
+ instrumentPtr->bankId = curBankId;
+ instrumentPtr->patchId = curPatchId;
+
+ instrumentDataSize = READ_LE_UINT16(fileDataPtr + instrumentOffset);
+ if (instrumentDataSize != (MILES_MT32_PATCHDATA_TOTAL_SIZE + 2))
+ error("MILES-MT32: unsupported instrument size");
+
+ instrumentOffset += 2;
+ // Copy common parameter data
+ memcpy(instrumentPtr->commonParameter, fileDataPtr + instrumentOffset, MILES_MT32_PATCHDATA_COMMONPARAMETER_SIZE);
+ instrumentPtr->commonParameter[MILES_MT32_PATCHDATA_COMMONPARAMETER_SIZE] = MILES_MT32_SYSEX_TERMINATOR; // Terminator
+ instrumentOffset += MILES_MT32_PATCHDATA_COMMONPARAMETER_SIZE;
+
+ // Copy partial parameter data
+ for (byte partialNr = 0; partialNr < MILES_MT32_PATCHDATA_PARTIALPARAMETERS_COUNT; partialNr++) {
+ memcpy(&instrumentPtr->partialParameters[partialNr], fileDataPtr + instrumentOffset, MILES_MT32_PATCHDATA_PARTIALPARAMETER_SIZE);
+ instrumentPtr->partialParameters[partialNr][MILES_MT32_PATCHDATA_PARTIALPARAMETER_SIZE] = MILES_MT32_SYSEX_TERMINATOR; // Terminator
+ instrumentOffset += MILES_MT32_PATCHDATA_PARTIALPARAMETER_SIZE;
+ }
+
+ // Instrument read, next instrument please
+ instrumentPtr++;
+ }
+
+ // Free instrument file data
+ delete[] fileDataPtr;
+ }
+
+ return new MidiDriver_Miles_MT32(instrumentTablePtr, instrumentTableCount);
+}
+
+void MidiDriver_Miles_MT32_processXMIDITimbreChunk(MidiDriver_BASE *driver, const byte *timbreListPtr, uint32 timbreListSize) {
+ MidiDriver_Miles_MT32 *driverMT32 = dynamic_cast<MidiDriver_Miles_MT32 *>(driver);
+
+ if (driverMT32) {
+ driverMT32->processXMIDITimbreChunk(timbreListPtr, timbreListSize);
+ }
+}
+
+} // End of namespace Audio
diff --git a/audio/module.mk b/audio/module.mk
index 4e1c031c83..9e002d57ba 100644
--- a/audio/module.mk
+++ b/audio/module.mk
@@ -1,6 +1,7 @@
MODULE := audio
MODULE_OBJS := \
+ adlib.o \
audiostream.o \
fmopl.o \
mididrv.o \
@@ -9,11 +10,14 @@ MODULE_OBJS := \
midiparser_xmidi.o \
midiparser.o \
midiplayer.o \
+ miles_adlib.o \
+ miles_mt32.o \
mixer.o \
mpu401.o \
musicplugin.o \
null.o \
timestamp.o \
+ decoders/3do.o \
decoders/aac.o \
decoders/adpcm.o \
decoders/aiff.o \
@@ -36,7 +40,6 @@ MODULE_OBJS := \
mods/rjp1.o \
mods/soundfx.o \
mods/tfmx.o \
- softsynth/adlib.o \
softsynth/cms.o \
softsynth/opl/dbopl.o \
softsynth/opl/dosbox.o \
@@ -55,6 +58,11 @@ MODULE_OBJS := \
softsynth/sid.o \
softsynth/wave6581.o
+ifdef USE_ALSA
+MODULE_OBJS += \
+ alsa_opl.o
+endif
+
ifndef USE_ARM_SOUND_ASM
MODULE_OBJS += \
rate.o
diff --git a/audio/softsynth/opl/dosbox.cpp b/audio/softsynth/opl/dosbox.cpp
index 5c3d833f54..3d90ec93d0 100644
--- a/audio/softsynth/opl/dosbox.cpp
+++ b/audio/softsynth/opl/dosbox.cpp
@@ -32,6 +32,7 @@
#include "dosbox.h"
#include "dbopl.h"
+#include "audio/mixer.h"
#include "common/system.h"
#include "common/scummsys.h"
#include "common/util.h"
@@ -148,6 +149,7 @@ OPL::OPL(Config::OplType type) : _type(type), _rate(0), _emulator(0) {
}
OPL::~OPL() {
+ stop();
free();
}
@@ -156,7 +158,7 @@ void OPL::free() {
_emulator = 0;
}
-bool OPL::init(int rate) {
+bool OPL::init() {
free();
memset(&_reg, 0, sizeof(_reg));
@@ -167,19 +169,19 @@ bool OPL::init(int rate) {
return false;
DBOPL::InitTables();
- _emulator->Setup(rate);
+ _rate = g_system->getMixer()->getOutputRate();
+ _emulator->Setup(_rate);
if (_type == Config::kDualOpl2) {
// Setup opl3 mode in the hander
_emulator->WriteReg(0x105, 1);
}
- _rate = rate;
return true;
}
void OPL::reset() {
- init(_rate);
+ init();
}
void OPL::write(int port, int val) {
@@ -307,7 +309,7 @@ void OPL::dualWrite(uint8 index, uint8 reg, uint8 val) {
_emulator->WriteReg(fullReg, val);
}
-void OPL::readBuffer(int16 *buffer, int length) {
+void OPL::generateSamples(int16 *buffer, int length) {
// For stereo OPL cards, we divide the sample count by 2,
// to match stereo AudioStream behavior.
if (_type != Config::kOpl2)
diff --git a/audio/softsynth/opl/dosbox.h b/audio/softsynth/opl/dosbox.h
index 513a49f6b8..c52f06761a 100644
--- a/audio/softsynth/opl/dosbox.h
+++ b/audio/softsynth/opl/dosbox.h
@@ -69,7 +69,7 @@ namespace DBOPL {
struct Chip;
} // end of namespace DBOPL
-class OPL : public ::OPL::OPL {
+class OPL : public ::OPL::EmulatedOPL {
private:
Config::OplType _type;
uint _rate;
@@ -87,7 +87,7 @@ public:
OPL(Config::OplType type);
~OPL();
- bool init(int rate);
+ bool init();
void reset();
void write(int a, int v);
@@ -95,8 +95,10 @@ public:
void writeReg(int r, int v);
- void readBuffer(int16 *buffer, int length);
bool isStereo() const { return _type != Config::kOpl2; }
+
+protected:
+ void generateSamples(int16 *buffer, int length);
};
} // End of namespace DOSBox
diff --git a/audio/softsynth/opl/mame.cpp b/audio/softsynth/opl/mame.cpp
index da75ba76ba..696169be09 100644
--- a/audio/softsynth/opl/mame.cpp
+++ b/audio/softsynth/opl/mame.cpp
@@ -31,6 +31,8 @@
#include "mame.h"
+#include "audio/mixer.h"
+#include "common/system.h"
#include "common/textconsole.h"
#include "common/util.h"
@@ -46,15 +48,19 @@ namespace OPL {
namespace MAME {
OPL::~OPL() {
+ stop();
MAME::OPLDestroy(_opl);
_opl = 0;
}
-bool OPL::init(int rate) {
- if (_opl)
+bool OPL::init() {
+ if (_opl) {
+ stopCallbacks();
MAME::OPLDestroy(_opl);
+ }
+
+ _opl = MAME::makeAdLibOPL(g_system->getMixer()->getOutputRate());
- _opl = MAME::makeAdLibOPL(rate);
return (_opl != 0);
}
@@ -74,7 +80,7 @@ void OPL::writeReg(int r, int v) {
MAME::OPLWriteReg(_opl, r, v);
}
-void OPL::readBuffer(int16 *buffer, int length) {
+void OPL::generateSamples(int16 *buffer, int length) {
MAME::YM3812UpdateOne(_opl, buffer, length);
}
diff --git a/audio/softsynth/opl/mame.h b/audio/softsynth/opl/mame.h
index bd479d9e45..67d80bb193 100644
--- a/audio/softsynth/opl/mame.h
+++ b/audio/softsynth/opl/mame.h
@@ -174,14 +174,14 @@ void YM3812UpdateOne(FM_OPL *OPL, int16 *buffer, int length);
FM_OPL *makeAdLibOPL(int rate);
// OPL API implementation
-class OPL : public ::OPL::OPL {
+class OPL : public ::OPL::EmulatedOPL {
private:
FM_OPL *_opl;
public:
OPL() : _opl(0) {}
~OPL();
- bool init(int rate);
+ bool init();
void reset();
void write(int a, int v);
@@ -189,8 +189,10 @@ public:
void writeReg(int r, int v);
- void readBuffer(int16 *buffer, int length);
bool isStereo() const { return false; }
+
+protected:
+ void generateSamples(int16 *buffer, int length);
};
} // End of namespace MAME
diff --git a/common/dcl.cpp b/common/dcl.cpp
index 2f4cdeda6b..5993c218cb 100644
--- a/common/dcl.cpp
+++ b/common/dcl.cpp
@@ -30,17 +30,15 @@ namespace Common {
class DecompressorDCL {
public:
- bool unpack(ReadStream *src, byte *dest, uint32 nPacked, uint32 nUnpacked);
+ bool unpack(SeekableReadStream *sourceStream, WriteStream *targetStream, uint32 targetSize, bool targetFixedSize);
protected:
/**
* Initialize decompressor.
- * @param src source stream to read from
- * @param dest destination stream to write to
- * @param nPacked size of packed data
- * @param nUnpacked size of unpacked data
+ * @param sourceStream source stream to read from
+ * @param targetStream target memory stream to write to
*/
- void init(ReadStream *src, byte *dest, uint32 nPacked, uint32 nUnpacked);
+ void init(SeekableReadStream *sourceStream, WriteStream *targetStream, uint32 targetSize, bool targetFixedSize);
/**
* Get a number of bits from _src stream, starting with the least
@@ -66,36 +64,38 @@ protected:
int huffman_lookup(const int *tree);
- uint32 _dwBits; ///< bits buffer
- byte _nBits; ///< number of unread bits in _dwBits
- uint32 _szPacked; ///< size of the compressed data
- uint32 _szUnpacked; ///< size of the decompressed data
- uint32 _dwRead; ///< number of bytes read from _src
- uint32 _dwWrote; ///< number of bytes written to _dest
- ReadStream *_src;
- byte *_dest;
+ uint32 _dwBits; ///< bits buffer
+ byte _nBits; ///< number of unread bits in _dwBits
+ uint32 _sourceSize; ///< size of the source stream
+ uint32 _targetSize; ///< size of the target stream (if fixed)
+ bool _targetFixedSize; ///< if target stream is fixed size or dynamic size
+ uint32 _bytesRead; ///< number of bytes read from _sourceStream
+ uint32 _bytesWritten; ///< number of bytes written to _targetStream
+ SeekableReadStream *_sourceStream;
+ WriteStream *_targetStream;
};
-void DecompressorDCL::init(ReadStream *src, byte *dest, uint32 nPacked, uint32 nUnpacked) {
- _src = src;
- _dest = dest;
- _szPacked = nPacked;
- _szUnpacked = nUnpacked;
+void DecompressorDCL::init(SeekableReadStream *sourceStream, WriteStream *targetStream, uint32 targetSize, bool targetFixedSize) {
+ _sourceStream = sourceStream;
+ _targetStream = targetStream;
+ _sourceSize = sourceStream->size();
+ _targetSize = targetSize;
+ _targetFixedSize = targetFixedSize;
_nBits = 0;
- _dwRead = _dwWrote = 0;
+ _bytesRead = _bytesWritten = 0;
_dwBits = 0;
}
void DecompressorDCL::fetchBitsLSB() {
while (_nBits <= 24) {
- _dwBits |= ((uint32)_src->readByte()) << _nBits;
+ _dwBits |= ((uint32)_sourceStream->readByte()) << _nBits;
_nBits += 8;
- _dwRead++;
+ _bytesRead++;
}
}
uint32 DecompressorDCL::getBitsLSB(int n) {
- // fetching more data to buffer if needed
+ // Fetching more data to buffer if needed
if (_nBits < n)
fetchBitsLSB();
uint32 ret = (_dwBits & ~((~0) << n));
@@ -109,7 +109,8 @@ byte DecompressorDCL::getByteLSB() {
}
void DecompressorDCL::putByte(byte b) {
- _dest[_dwWrote++] = b;
+ _targetStream->writeByte(b);
+ _bytesWritten++;
}
#define HUFFMAN_LEAF 0x40000000
@@ -331,97 +332,189 @@ int DecompressorDCL::huffman_lookup(const int *tree) {
#define DCL_BINARY_MODE 0
#define DCL_ASCII_MODE 1
-bool DecompressorDCL::unpack(ReadStream *src, byte *dest, uint32 nPacked, uint32 nUnpacked) {
- init(src, dest, nPacked, nUnpacked);
+#define MIDI_SETUP_BUNDLE_FILE_MAXIMUM_DICTIONARY_SIZE 4096
+bool DecompressorDCL::unpack(SeekableReadStream *sourceStream, WriteStream *targetStream, uint32 targetSize, bool targetFixedSize) {
+ byte dictionary[MIDI_SETUP_BUNDLE_FILE_MAXIMUM_DICTIONARY_SIZE];
+ uint16 dictionaryPos = 0;
+ uint16 dictionarySize = 0;
+ uint16 dictionaryMask = 0;
int value;
- uint32 val_distance, val_length;
+ uint16 tokenOffset = 0;
+ uint16 tokenLength = 0;
- int mode = getByteLSB();
- int length_param = getByteLSB();
+ init(sourceStream, targetStream, targetSize, targetFixedSize);
+
+ byte mode = getByteLSB();
+ byte dictionaryType = getByteLSB();
if (mode != DCL_BINARY_MODE && mode != DCL_ASCII_MODE) {
warning("DCL-INFLATE: Error: Encountered mode %02x, expected 00 or 01", mode);
return false;
}
- if (length_param < 3 || length_param > 6)
- warning("Unexpected length_param value %d (expected in [3,6])", length_param);
+ // TODO: original code supported 3 as well???
+ // Was this an accident or on purpose? And the original code did just give out a warning
+ // and didn't error out at all
+ switch (dictionaryType) {
+ case 4:
+ dictionarySize = 1024;
+ break;
+ case 5:
+ dictionarySize = 2048;
+ break;
+ case 6:
+ dictionarySize = 4096;
+ break;
+ default:
+ warning("DCL-INFLATE: Error: unsupported dictionary type %02x", dictionaryType);
+ return false;
+ }
+ dictionaryMask = dictionarySize - 1;
- while (_dwWrote < _szUnpacked) {
+ while ((!targetFixedSize) || (_bytesWritten < _targetSize)) {
if (getBitsLSB(1)) { // (length,distance) pair
value = huffman_lookup(length_tree);
if (value < 8)
- val_length = value + 2;
+ tokenLength = value + 2;
else
- val_length = 8 + (1 << (value - 7)) + getBitsLSB(value - 7);
+ tokenLength = 8 + (1 << (value - 7)) + getBitsLSB(value - 7);
+
+ if (tokenLength == 519)
+ break; // End of stream signal
debug(8, " | ");
value = huffman_lookup(distance_tree);
- if (val_length == 2)
- val_distance = (value << 2) | getBitsLSB(2);
+ if (tokenLength == 2)
+ tokenOffset = (value << 2) | getBitsLSB(2);
else
- val_distance = (value << length_param) | getBitsLSB(length_param);
- val_distance ++;
+ tokenOffset = (value << dictionaryType) | getBitsLSB(dictionaryType);
+ tokenOffset++;
- debug(8, "\nCOPY(%d from %d)\n", val_length, val_distance);
+ debug(8, "\nCOPY(%d from %d)\n", tokenLength, tokenOffset);
- if (val_length + _dwWrote > _szUnpacked) {
- warning("DCL-INFLATE Error: Write out of bounds while copying %d bytes (declared unpacked size is %d bytes, current is %d + %d bytes)",
- val_length, _szUnpacked, _dwWrote, val_length);
- return false;
+ if (_targetFixedSize) {
+ if (tokenLength + _bytesWritten > _targetSize) {
+ warning("DCL-INFLATE Error: Write out of bounds while copying %d bytes (declared unpacked size is %d bytes, current is %d + %d bytes)",
+ tokenLength, _targetSize, _bytesWritten, tokenLength);
+ return false;
+ }
}
- if (_dwWrote < val_distance) {
+ if (_bytesWritten < tokenOffset) {
warning("DCL-INFLATE Error: Attempt to copy from before beginning of input stream (declared unpacked size is %d bytes, current is %d bytes)",
- _szUnpacked, _dwWrote);
+ _targetSize, _bytesWritten);
return false;
}
- while (val_length) {
- uint32 copy_length = (val_length > val_distance) ? val_distance : val_length;
- assert(val_distance >= copy_length);
- uint32 pos = _dwWrote - val_distance;
- for (uint32 i = 0; i < copy_length; i++)
- putByte(dest[pos + i]);
+ uint16 dictionaryBaseIndex = (dictionaryPos - tokenOffset) & dictionaryMask;
+ uint16 dictionaryIndex = dictionaryBaseIndex;
+ uint16 dictionaryNextIndex = dictionaryPos;
+
+ while (tokenLength) {
+ // Write byte from dictionary
+ putByte(dictionary[dictionaryIndex]);
+ debug(9, "\33[32;31m%02x\33[37;37m ", dictionary[dictionaryIndex]);
+
+ dictionary[dictionaryNextIndex] = dictionary[dictionaryIndex];
- for (uint32 i = 0; i < copy_length; i++)
- debug(9, "\33[32;31m%02x\33[37;37m ", dest[pos + i]);
- debug(9, "\n");
+ dictionaryNextIndex = (dictionaryNextIndex + 1) & dictionaryMask;
+ dictionaryIndex = (dictionaryIndex + 1) & dictionaryMask;
- val_length -= copy_length;
- val_distance += copy_length;
+ if (dictionaryIndex == dictionaryPos)
+ dictionaryIndex = dictionaryBaseIndex;
+ if (dictionaryNextIndex == dictionarySize)
+ dictionaryNextIndex = 0;
+
+ tokenLength--;
}
+ dictionaryPos = dictionaryNextIndex;
+ debug(9, "\n");
} else { // Copy byte verbatim
value = (mode == DCL_ASCII_MODE) ? huffman_lookup(ascii_tree) : getByteLSB();
putByte(value);
+
+ // Also remember it inside dictionary
+ dictionary[dictionaryPos] = value;
+ dictionaryPos++;
+ if (dictionaryPos >= dictionarySize)
+ dictionaryPos = 0;
+
debug(9, "\33[32;31m%02x \33[37;37m", value);
}
}
- return _dwWrote == _szUnpacked;
+ if (_targetFixedSize) {
+ return _bytesWritten == _targetSize;
+ }
+ return true; // For targets featuring dynamic size we always succeed
}
bool decompressDCL(ReadStream *src, byte *dest, uint32 packedSize, uint32 unpackedSize) {
+ bool success = false;
+ DecompressorDCL dcl;
+
if (!src || !dest)
return false;
+ byte *sourceBufferPtr = (byte *)malloc(packedSize);
+ if (!sourceBufferPtr)
+ return false;
+
+ // Read source into memory
+ src->read(sourceBufferPtr, packedSize);
+
+ Common::MemoryReadStream *sourceStream = new MemoryReadStream(sourceBufferPtr, packedSize, DisposeAfterUse::NO);
+ Common::MemoryWriteStream *targetStream = new MemoryWriteStream(dest, unpackedSize);
+
+ success = dcl.unpack(sourceStream, targetStream, unpackedSize, true);
+ delete sourceStream;
+ delete targetStream;
+ return success;
+}
+
+SeekableReadStream *decompressDCL(SeekableReadStream *sourceStream, uint32 packedSize, uint32 unpackedSize) {
+ bool success = false;
+ byte *targetPtr = nullptr;
+ Common::MemoryWriteStream *targetStream;
DecompressorDCL dcl;
- return dcl.unpack(src, dest, packedSize, unpackedSize);
+
+ targetPtr = (byte *)malloc(unpackedSize);
+ if (!targetPtr)
+ return nullptr;
+
+ targetStream = new MemoryWriteStream(targetPtr, unpackedSize);
+
+ success = dcl.unpack(sourceStream, targetStream, unpackedSize, true);
+ delete targetStream;
+
+ if (!success) {
+ free(targetPtr);
+ return nullptr;
+ }
+ return new MemoryReadStream(targetPtr, unpackedSize, DisposeAfterUse::YES);
}
-SeekableReadStream *decompressDCL(ReadStream *src, uint32 packedSize, uint32 unpackedSize) {
- byte *data = (byte *)malloc(unpackedSize);
+// This one figures out the unpacked size by itself
+// Needed for at least Simon 2, because the unpacked size is not stored anywhere
+SeekableReadStream *decompressDCL(SeekableReadStream *sourceStream) {
+ Common::MemoryWriteStreamDynamic *targetStream;
+ DecompressorDCL dcl;
- if (decompressDCL(src, data, packedSize, unpackedSize))
- return new MemoryReadStream(data, unpackedSize, DisposeAfterUse::YES);
+ targetStream = new MemoryWriteStreamDynamic(DisposeAfterUse::NO);
- free(data);
- return 0;
+ if (dcl.unpack(sourceStream, targetStream, 0, false)) {
+ byte *targetPtr = targetStream->getData();
+ uint32 unpackedSize = targetStream->size();
+ delete targetStream;
+ return new MemoryReadStream(targetPtr, unpackedSize, DisposeAfterUse::YES);
+ }
+ delete targetStream;
+ return nullptr;
}
} // End of namespace Common
diff --git a/common/dcl.h b/common/dcl.h
index 0e96f74c07..f90bc23c8d 100644
--- a/common/dcl.h
+++ b/common/dcl.h
@@ -22,7 +22,8 @@
/**
* @file
- * PKWARE DCL ("explode") decompressor used in engines:
+ * PKWARE DCL ("explode") ("PKWARE data compression library") decompressor used in engines:
+ * - agos (exclusively for Simon 2 setup.shr file)
* - mohawk
* - sci
*/
@@ -38,16 +39,22 @@ class ReadStream;
class SeekableReadStream;
/**
- * Try to decompress a PKWARE DCL compressed stream. Returns true if
+ * Try to decompress a PKWARE DCL (PKWARE data compression library) compressed stream. Returns true if
* successful.
*/
-bool decompressDCL(ReadStream *src, byte *dest, uint32 packedSize, uint32 unpackedSize);
+bool decompressDCL(ReadStream *sourceStream, byte *dest, uint32 packedSize, uint32 unpackedSize);
/**
- * Try to decompress a PKWARE DCL compressed stream. Returns a valid pointer
+ * Try to decompress a PKWARE DCL (PKWARE data compression library) compressed stream. Returns a valid pointer
* if successful and 0 otherwise.
*/
-SeekableReadStream *decompressDCL(ReadStream *src, uint32 packedSize, uint32 unpackedSize);
+SeekableReadStream *decompressDCL(SeekableReadStream *sourceStream, uint32 packedSize, uint32 unpackedSize);
+
+/**
+ * Try to decompress a PKWARE DCL (PKWARE data compression library) compressed stream. Returns a valid pointer
+ * if successful and 0 otherwise. This method is meant for cases, where the unpacked size is not known.
+ */
+SeekableReadStream *decompressDCL(SeekableReadStream *sourceStream);
} // End of namespace Common
diff --git a/common/fft.cpp b/common/fft.cpp
index 477f7aca62..27a04abb6a 100644
--- a/common/fft.cpp
+++ b/common/fft.cpp
@@ -56,6 +56,10 @@ FFT::FFT(int bits, int inverse) : _bits(bits), _inverse(inverse) {
}
FFT::~FFT() {
+ for (int i = 0; i < ARRAYSIZE(_cosTables); i++) {
+ delete _cosTables[i];
+ }
+
delete[] _revTab;
delete[] _expTab;
delete[] _tmpBuf;
diff --git a/configure b/configure
index 78f147f4b2..a2f73644cf 100755
--- a/configure
+++ b/configure
@@ -69,6 +69,16 @@ get_var() {
eval echo \$${1}
}
+append_var() {
+ VAR=${1}
+ shift
+ if eval test -z \"\$${VAR}\" ; then
+ eval ${VAR}='$@'
+ else
+ eval ${VAR}=\"\$${VAR} \"'$@'
+ fi
+}
+
# Add an engine: id name build subengines base-games dependencies
add_engine() {
_engines="${_engines} ${1}"
@@ -1172,7 +1182,7 @@ for ac_option in $@; do
_debug_build=no
;;
--enable-Werror)
- CXXFLAGS="$CXXFLAGS -Werror"
+ append_var CXXFLAGS "-Werror"
;;
--enable-release-mode)
_release_build=yes
@@ -1309,8 +1319,8 @@ dreamcast)
_host_os=dreamcast
_host_cpu=sh
_host_alias=sh-elf
- CXXFLAGS="$CXXFLAGS -ml -m4-single-only"
- LDFLAGS="$LDFLAGS -ml -m4-single-only"
+ append_var CXXFLAGS "-ml -m4-single-only"
+ append_var LDFLAGS "-ml -m4-single-only"
;;
ds)
_host_os=ds
@@ -1497,18 +1507,18 @@ if test "$_debug_build" != no; then
case $_host_os in
amigaos*)
# AmigaOS debugger uses plain stabs, with no gdb extensions.
- CXXFLAGS="$CXXFLAGS -gstabs"
+ append_var CXXFLAGS "-gstabs"
;;
*)
# Use the system default format for debug info.
- CXXFLAGS="$CXXFLAGS -g"
+ append_var CXXFLAGS "-g"
esac
fi
if test "$_release_build" = yes; then
# Add a define, which indicates we are doing
# an build for a release version.
- DEFINES="$DEFINES -DRELEASE_BUILD"
+ append_var DEFINES "-DRELEASE_BUILD"
fi
@@ -1680,7 +1690,7 @@ if test "$have_icc" = yes; then
# Make ICC error our on unknown command line options instead of printing
# a warning. This is for example required to make the -Wglobal-destructors
# detection work correctly.
- CXXFLAGS="$CXXFLAGS -diag-error 10006,10148"
+ append_var CXXFLAGS "-diag-error 10006,10148"
fi
have_gcc=no
@@ -1788,20 +1798,20 @@ if test "$have_gcc" = yes ; then
amigaos* | android | dreamcast | ds | gamecube | mingw* | n64 | psp | ps2 | ps3 | tizen | wii | wince )
;;
*)
- CXXFLAGS="$CXXFLAGS -ansi"
+ append_var CXXFLAGS "-ansi"
;;
esac
fi
- CXXFLAGS="$CXXFLAGS -W -Wno-unused-parameter"
+ append_var CXXFLAGS "-W -Wno-unused-parameter"
add_line_to_config_mk 'HAVE_GCC3 = 1'
add_line_to_config_mk 'CXX_UPDATE_DEP_FLAG = -MMD -MF "$(*D)/$(DEPDIR)/$(*F).d" -MQ "$@" -MP'
fi;
if test "$_cxx_major" -eq 4 && test "$_cxx_minor" -ge 3 || \
test "$_cxx_major" -gt 4 ; then
- CXXFLAGS="$CXXFLAGS -Wno-empty-body"
+ append_var CXXFLAGS "-Wno-empty-body"
else
- CXXFLAGS="$CXXFLAGS -Wconversion"
+ append_var CXXFLAGS "-Wconversion"
fi;
elif test "$have_icc" = yes ; then
add_line_to_config_mk 'CXX_UPDATE_DEP_FLAG = -MMD -MF "$(*D)/$(DEPDIR)/$(*F).d" -MQ "$@" -MP'
@@ -1812,7 +1822,7 @@ fi;
#
echo_n "Building as C++11... "
if test "$_use_cxx11" = "yes" ; then
- CXXFLAGS="$CXXFLAGS -std=c++11"
+ append_var CXXFLAGS "-std=c++11"
fi
echo $_use_cxx11
@@ -1827,7 +1837,7 @@ android | gamecube | psp | tizen | wii | webos)
# ICC does not support pedantic, while GCC and clang do.
if test "$have_icc" = no ; then
# We *do* want the 'long long' extension.
- CXXFLAGS="$CXXFLAGS -pedantic -Wno-long-long"
+ append_var CXXFLAGS "-pedantic -Wno-long-long"
fi
;;
esac
@@ -1841,7 +1851,7 @@ EOF
cc_check -Wglobal-constructors && _global_constructors=yes
if test "$_global_constructors" = yes; then
- CXXFLAGS="$CXXFLAGS -Wglobal-constructors"
+ append_var CXXFLAGS "-Wglobal-constructors"
fi
echo $_global_constructors
@@ -2037,7 +2047,7 @@ case $_host_cpu in
# (on Pandora and iPhone at least)
#define_in_config_if_yes yes 'USE_ARM_COSTUME_ASM'
- DEFINES="$DEFINES -DARM_TARGET"
+ append_var DEFINES "-DARM_TARGET"
;;
i[3-6]86)
echo "x86"
@@ -2046,11 +2056,11 @@ case $_host_cpu in
;;
mips*)
echo "MIPS"
- DEFINES="$DEFINES -DMIPS_TARGET"
+ append_var DEFINES "-DMIPS_TARGET"
;;
powerpc*)
echo "PowerPC"
- DEFINES="$DEFINES -DPPC_TARGET"
+ append_var DEFINES "-DPPC_TARGET"
;;
amd64 | x86_64)
echo "x86_64"
@@ -2068,56 +2078,56 @@ echo_n "Checking hosttype... "
echo $_host_os
case $_host_os in
amigaos*)
- LDFLAGS="$LDFLAGS -use-dynld -Wl,--export-dynamic"
- LDFLAGS="$LDFLAGS -L/sdk/local/newlib/lib"
+ append_var LDFLAGS "-use-dynld -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.
type_4_byte='long'
# Supress format warnings as the long 4 byte causes noisy warnings.
- CXXFLAGS="$CXXFLAGS -Wno-format"
+ append_var CXXFLAGS "-Wno-format"
add_line_to_config_mk 'AMIGAOS = 1'
_port_mk="backends/platform/sdl/amigaos/amigaos.mk"
;;
android)
case $_host in
android | android-arm)
- CXXFLAGS="$CXXFLAGS -march=armv5te"
- CXXFLAGS="$CXXFLAGS -mtune=xscale"
- CXXFLAGS="$CXXFLAGS -msoft-float"
+ append_var CXXFLAGS "-march=armv5te"
+ append_var CXXFLAGS "-mtune=xscale"
+ append_var CXXFLAGS "-msoft-float"
ABI="armeabi"
ANDROID_PLATFORM=4
ANDROID_PLATFORM_ARCH="arm"
;;
android-v7a | android-arm-v7a)
- CXXFLAGS="$CXXFLAGS -march=armv7-a"
- CXXFLAGS="$CXXFLAGS -mfloat-abi=softfp"
- CXXFLAGS="$CXXFLAGS -mfpu=vfp"
- LDFLAGS="$LDFLAGS -Wl,--fix-cortex-a8"
+ append_var CXXFLAGS "-march=armv7-a"
+ append_var CXXFLAGS "-mfloat-abi=softfp"
+ append_var CXXFLAGS "-mfpu=vfp"
+ append_var LDFLAGS "-Wl,--fix-cortex-a8"
ABI="armeabi-v7a"
ANDROID_PLATFORM=4
ANDROID_PLATFORM_ARCH="arm"
;;
android-mips)
- CXXFLAGS="$CXXFLAGS -march=mips32"
- CXXFLAGS="$CXXFLAGS -mtune=mips32"
+ append_var CXXFLAGS "-march=mips32"
+ append_var CXXFLAGS "-mtune=mips32"
ABI="mips"
# Platform version 9 is needed as earlier versions of platform do not support this arch.
ANDROID_PLATFORM=9
ANDROID_PLATFORM_ARCH="mips"
;;
android-x86)
- CXXFLAGS="$CXXFLAGS -march=i686"
- CXXFLAGS="$CXXFLAGS -mtune=i686"
+ append_var CXXFLAGS "-march=i686"
+ append_var CXXFLAGS "-mtune=i686"
ABI="x86"
# Platform version 9 is needed as earlier versions of platform do not support this arch.
ANDROID_PLATFORM=9
ANDROID_PLATFORM_ARCH="x86"
;;
ouya)
- CXXFLAGS="$CXXFLAGS -march=armv7-a"
- CXXFLAGS="$CXXFLAGS -mtune=cortex-a9"
- CXXFLAGS="$CXXFLAGS -mfloat-abi=softfp"
- CXXFLAGS="$CXXFLAGS -mfpu=neon"
+ append_var CXXFLAGS "-march=armv7-a"
+ append_var CXXFLAGS "-mtune=cortex-a9"
+ append_var CXXFLAGS "-mfloat-abi=softfp"
+ append_var CXXFLAGS "-mfpu=neon"
ABI="armeabi-v7a"
ANDROID_PLATFORM=4
ANDROID_PLATFORM_ARCH="arm"
@@ -2125,40 +2135,40 @@ case $_host_os in
esac
# Setup platform version and arch
- CXXFLAGS="$CXXFLAGS --sysroot=$ANDROID_NDK/platforms/android-$ANDROID_PLATFORM/arch-$ANDROID_PLATFORM_ARCH"
- LDFLAGS="$LDFLAGS --sysroot=$ANDROID_NDK/platforms/android-$ANDROID_PLATFORM/arch-$ANDROID_PLATFORM_ARCH"
+ append_var CXXFLAGS "--sysroot=$ANDROID_NDK/platforms/android-$ANDROID_PLATFORM/arch-$ANDROID_PLATFORM_ARCH"
+ append_var LDFLAGS "--sysroot=$ANDROID_NDK/platforms/android-$ANDROID_PLATFORM/arch-$ANDROID_PLATFORM_ARCH"
- CXXFLAGS="$CXXFLAGS -fpic"
- CXXFLAGS="$CXXFLAGS -ffunction-sections"
- CXXFLAGS="$CXXFLAGS -funwind-tables"
+ append_var CXXFLAGS "-fpic"
+ append_var CXXFLAGS "-ffunction-sections"
+ append_var CXXFLAGS "-funwind-tables"
if test "$_debug_build" = yes; then
- CXXFLAGS="$CXXFLAGS -fno-omit-frame-pointer"
- CXXFLAGS="$CXXFLAGS -fno-strict-aliasing"
+ append_var CXXFLAGS "-fno-omit-frame-pointer"
+ append_var CXXFLAGS "-fno-strict-aliasing"
else
- CXXFLAGS="$CXXFLAGS -fomit-frame-pointer"
- CXXFLAGS="$CXXFLAGS -fstrict-aliasing"
+ append_var CXXFLAGS "-fomit-frame-pointer"
+ append_var CXXFLAGS "-fstrict-aliasing"
fi
- CXXFLAGS="$CXXFLAGS -finline-limit=300"
+ append_var CXXFLAGS "-finline-limit=300"
_optimization_level=-Os
if test "$_host" = android -o "$_host" = android-arm; then
- CXXFLAGS="$CXXFLAGS -mthumb-interwork"
+ append_var CXXFLAGS "-mthumb-interwork"
# FIXME: Why is the following in CXXFLAGS and not in DEFINES? Change or document this.
- CXXFLAGS="$CXXFLAGS -D__ARM_ARCH_5__"
- CXXFLAGS="$CXXFLAGS -D__ARM_ARCH_5T__"
- CXXFLAGS="$CXXFLAGS -D__ARM_ARCH_5E__"
- CXXFLAGS="$CXXFLAGS -D__ARM_ARCH_5TE__"
+ append_var CXXFLAGS "-D__ARM_ARCH_5__"
+ append_var CXXFLAGS "-D__ARM_ARCH_5T__"
+ append_var CXXFLAGS "-D__ARM_ARCH_5E__"
+ append_var CXXFLAGS "-D__ARM_ARCH_5TE__"
fi
# surpress 'mangling of 'va_list' has changed in GCC 4.4' warning
- CXXFLAGS="$CXXFLAGS -Wno-psabi"
+ append_var CXXFLAGS "-Wno-psabi"
if test "$_host" = android -o "$_host" = android-arm; then
- LDFLAGS="$LDFLAGS -mthumb-interwork"
+ append_var LDFLAGS "-mthumb-interwork"
fi
- LDFLAGS="$LDFLAGS -L$ANDROID_NDK/sources/cxx-stl/gnu-libstdc++/`$CXX -dumpversion`/libs/$ABI/"
- LIBS="$LIBS -lsupc++"
+ append_var LDFLAGS "-L$ANDROID_NDK/sources/cxx-stl/gnu-libstdc++/`$CXX -dumpversion`/libs/$ABI/"
+ append_var LIBS "-lsupc++"
add_line_to_config_mk "ANDROID_SDK = $ANDROID_SDK"
if test -d "$ANDROID_SDK"/build-tools; then
_build_tools_version=`cd "$ANDROID_SDK"/build-tools && ls -1 | sort -rn | head -1`
@@ -2169,12 +2179,12 @@ case $_host_os in
_seq_midi=no
;;
beos*)
- DEFINES="$DEFINES -DSYSTEM_NOT_SUPPORTING_D_TYPE"
+ append_var DEFINES "-DSYSTEM_NOT_SUPPORTING_D_TYPE"
# Needs -lbind -lsocket for the timidity MIDI driver
LDFLAGS="-L/boot/home/config/lib"
CFLAGS="-I/boot/home/config/include"
- CXXFLAGS="$CXXFLAGS -fhuge-objects"
- LIBS="$LIBS -lbind -lsocket"
+ append_var CXXFLAGS "-fhuge-objects"
+ append_var LIBS "-lbind -lsocket"
_seq_midi=no
;;
cygwin*)
@@ -2188,15 +2198,15 @@ case $_host_os in
# need to ensure the compiler emits them in the first place.
case $_host_cpu in
powerpc*)
- CFLAGS="$CFLAGS -mlongcall"
- CXXFLAGS="$CXXFLAGS -mlongcall"
+ append_var CFLAGS "-mlongcall"
+ append_var CXXFLAGS "-mlongcall"
;;
esac
- DEFINES="$DEFINES -DMACOSX"
- LIBS="$LIBS -framework AudioUnit -framework AudioToolbox -framework Carbon -framework CoreMIDI"
+ append_var DEFINES "-DMACOSX"
+ append_var LIBS "-framework AudioUnit -framework AudioToolbox -framework Carbon -framework CoreMIDI"
# SDL2 doesn't seem to add Cocoa for us.
- LIBS="$LIBS -framework Cocoa"
+ append_var LIBS "-framework Cocoa"
add_line_to_config_mk 'MACOSX = 1'
# Now we may have MacPorts or Fink installed
@@ -2283,115 +2293,115 @@ case $_host_os in
fi
;;
dreamcast)
- DEFINES="$DEFINES -D__DC__"
- DEFINES="$DEFINES -DNONSTANDARD_PORT"
+ append_var DEFINES "-D__DC__"
+ append_var DEFINES "-DNONSTANDARD_PORT"
;;
ds)
- DEFINES="$DEFINES -D__DS__"
- DEFINES="$DEFINES -DNDS"
- DEFINES="$DEFINES -DARM9"
- DEFINES="$DEFINES -DARM"
- DEFINES="$DEFINES -DNONSTANDARD_PORT"
- CXXFLAGS="$CXXFLAGS -isystem $DEVKITPRO/libnds/include"
- CXXFLAGS="$CXXFLAGS -isystem $DEVKITPRO/devkitARM/arm-eabi/include"
- CXXFLAGS="$CXXFLAGS -mcpu=arm9tdmi"
- CXXFLAGS="$CXXFLAGS -mtune=arm9tdmi"
- CXXFLAGS="$CXXFLAGS -fomit-frame-pointer"
- CXXFLAGS="$CXXFLAGS -mthumb-interwork"
- CXXFLAGS="$CXXFLAGS -ffunction-sections"
- CXXFLAGS="$CXXFLAGS -fdata-sections"
- CXXFLAGS="$CXXFLAGS -fno-strict-aliasing"
- CXXFLAGS="$CXXFLAGS -fuse-cxa-atexit"
- LDFLAGS="$LDFLAGS -specs=ds_arm9.specs"
- LDFLAGS="$LDFLAGS -mthumb-interwork"
- LDFLAGS="$LDFLAGS -mno-fpu"
- LDFLAGS="$LDFLAGS -Wl,-Map,map.txt"
+ append_var DEFINES "-D__DS__"
+ append_var DEFINES "-DNDS"
+ append_var DEFINES "-DARM9"
+ append_var DEFINES "-DARM"
+ append_var DEFINES "-DNONSTANDARD_PORT"
+ append_var CXXFLAGS "-isystem $DEVKITPRO/libnds/include"
+ append_var CXXFLAGS "-isystem $DEVKITPRO/devkitARM/arm-eabi/include"
+ append_var CXXFLAGS "-mcpu=arm9tdmi"
+ append_var CXXFLAGS "-mtune=arm9tdmi"
+ append_var CXXFLAGS "-fomit-frame-pointer"
+ append_var CXXFLAGS "-mthumb-interwork"
+ append_var CXXFLAGS "-ffunction-sections"
+ append_var CXXFLAGS "-fdata-sections"
+ append_var CXXFLAGS "-fno-strict-aliasing"
+ append_var CXXFLAGS "-fuse-cxa-atexit"
+ append_var LDFLAGS "-specs=ds_arm9.specs"
+ append_var LDFLAGS "-mthumb-interwork"
+ append_var LDFLAGS "-mno-fpu"
+ append_var LDFLAGS "-Wl,-Map,map.txt"
if test "$_dynamic_modules" = no ; then
- LDFLAGS="$LDFLAGS -Wl,--gc-sections"
+ append_var LDFLAGS "-Wl,--gc-sections"
else
- LDFLAGS="$LDFLAGS -Wl,--no-gc-sections"
+ append_var LDFLAGS "-Wl,--no-gc-sections"
# TODO automate this required 2 step linking phase
- # LDFLAGS="$LDFLAGS -Wl,--retain-symbols-file,ds.syms"
+ # append_var LDFLAGS "-Wl,--retain-symbols-file,ds.syms"
fi
- LDFLAGS="$LDFLAGS -L$DEVKITPRO/libnds/lib"
- LIBS="$LIBS -lnds9"
+ append_var LDFLAGS "-L$DEVKITPRO/libnds/lib"
+ append_var LIBS "-lnds9"
;;
freebsd*)
- LDFLAGS="$LDFLAGS -L/usr/local/lib"
- CXXFLAGS="$CXXFLAGS -I/usr/local/include"
+ append_var LDFLAGS "-L/usr/local/lib"
+ append_var CXXFLAGS "-I/usr/local/include"
;;
gamecube)
_optimization_level=-Os
- CXXFLAGS="$CXXFLAGS -mogc"
- CXXFLAGS="$CXXFLAGS -mcpu=750"
- CXXFLAGS="$CXXFLAGS -meabi"
- CXXFLAGS="$CXXFLAGS -mhard-float"
- CXXFLAGS="$CXXFLAGS -ffunction-sections"
- CXXFLAGS="$CXXFLAGS -fdata-sections"
- CXXFLAGS="$CXXFLAGS -fmodulo-sched"
- CXXFLAGS="$CXXFLAGS -fuse-cxa-atexit"
- CXXFLAGS="$CXXFLAGS -I$DEVKITPRO/libogc/include"
+ append_var CXXFLAGS "-mogc"
+ append_var CXXFLAGS "-mcpu=750"
+ append_var CXXFLAGS "-meabi"
+ append_var CXXFLAGS "-mhard-float"
+ append_var CXXFLAGS "-ffunction-sections"
+ append_var CXXFLAGS "-fdata-sections"
+ append_var CXXFLAGS "-fmodulo-sched"
+ append_var CXXFLAGS "-fuse-cxa-atexit"
+ append_var CXXFLAGS "-I$DEVKITPRO/libogc/include"
# libogc is required to link the cc tests (includes _start())
- LDFLAGS="$LDFLAGS -mogc"
- LDFLAGS="$LDFLAGS -mcpu=750"
- LDFLAGS="$LDFLAGS -L$DEVKITPRO/libogc/lib/cube"
- LDFLAGS="$LDFLAGS -logc"
+ append_var LDFLAGS "-mogc"
+ append_var LDFLAGS "-mcpu=750"
+ append_var LDFLAGS "-L$DEVKITPRO/libogc/lib/cube"
+ append_var LDFLAGS "-logc"
if test "$_dynamic_modules" = "yes" ; then
# retarded toolchain patch forces --gc-sections, overwrite it
- LDFLAGS="$LDFLAGS -Wl,--no-gc-sections"
+ append_var LDFLAGS "-Wl,--no-gc-sections"
fi
;;
haiku*)
- DEFINES="$DEFINES -DSYSTEM_NOT_SUPPORTING_D_TYPE"
+ append_var DEFINES "-DSYSTEM_NOT_SUPPORTING_D_TYPE"
# Needs -lnetwork for the timidity MIDI driver
- LIBS="$LIBS -lnetwork"
+ append_var LIBS "-lnetwork"
_seq_midi=no
;;
irix*)
- DEFINES="$DEFINES -DIRIX"
- DEFINES="$DEFINES -DSYSTEM_NOT_SUPPORTING_D_TYPE"
- LIBS="$LIBS -lmd -lfastm -lm"
+ append_var DEFINES "-DIRIX"
+ append_var DEFINES "-DSYSTEM_NOT_SUPPORTING_D_TYPE"
+ append_var LIBS "-lmd -lfastm -lm"
_ranlib=:
;;
linux* | uclinux*)
# When not cross-compiling, enable large file support, but don't
# care if getconf doesn't exist or doesn't recognize LFS_CFLAGS.
if test -z "$_host"; then
- CXXFLAGS="$CXXFLAGS `getconf LFS_CFLAGS 2>/dev/null`"
+ append_var CXXFLAGS "`getconf LFS_CFLAGS 2>/dev/null`"
fi
;;
maemo)
- DEFINES="$DEFINES -DMAEMO"
+ append_var DEFINES "-DMAEMO"
;;
mingw*)
- DEFINES="$DEFINES -DWIN32"
- DEFINES="$DEFINES -D__USE_MINGW_ANSI_STDIO=0"
- LDFLAGS="$LDFLAGS -static-libgcc -static-libstdc++"
- LIBS="$LIBS -lmingw32 -lwinmm -lgdi32"
- OBJS="$OBJS scummvmwinres.o"
+ append_var DEFINES "-DWIN32"
+ append_var DEFINES "-D__USE_MINGW_ANSI_STDIO=0"
+ append_var LDFLAGS "-static-libgcc -static-libstdc++"
+ append_var LIBS "-lmingw32 -lwinmm -lgdi32"
+ append_var OBJS "scummvmwinres.o"
add_line_to_config_mk 'WIN32 = 1'
;;
mint*)
- DEFINES="$DEFINES -DSYSTEM_NOT_SUPPORTING_D_TYPE"
+ append_var DEFINES "-DSYSTEM_NOT_SUPPORTING_D_TYPE"
;;
n64)
- DEFINES="$DEFINES -D__N64__"
- DEFINES="$DEFINES -DLIMIT_FPS"
- DEFINES="$DEFINES -DNONSTANDARD_PORT"
- DEFINES="$DEFINES -DDISABLE_COMMAND_LINE"
- DEFINES="$DEFINES -DDISABLE_DEFAULT_SAVEFILEMANAGER"
- DEFINES="$DEFINES -DDISABLE_DOSBOX_OPL"
- DEFINES="$DEFINES -DDISABLE_FANCY_THEMES"
- DEFINES="$DEFINES -DDISABLE_NES_APU"
- DEFINES="$DEFINES -DDISABLE_SID"
- DEFINES="$DEFINES -DREDUCE_MEMORY_USAGE"
+ append_var DEFINES "-D__N64__"
+ append_var DEFINES "-DLIMIT_FPS"
+ append_var DEFINES "-DNONSTANDARD_PORT"
+ append_var DEFINES "-DDISABLE_COMMAND_LINE"
+ append_var DEFINES "-DDISABLE_DEFAULT_SAVEFILEMANAGER"
+ append_var DEFINES "-DDISABLE_DOSBOX_OPL"
+ append_var DEFINES "-DDISABLE_FANCY_THEMES"
+ append_var DEFINES "-DDISABLE_NES_APU"
+ append_var DEFINES "-DDISABLE_SID"
+ append_var DEFINES "-DREDUCE_MEMORY_USAGE"
;;
ps2)
- CXXFLAGS="$CXXFLAGS -G2"
- DEFINES="$DEFINES -D_EE"
- DEFINES="$DEFINES -D__PLAYSTATION2__"
+ append_var CXXFLAGS "-G2"
+ append_var DEFINES "-D_EE"
+ append_var DEFINES "-D__PLAYSTATION2__"
if test -z "$PS2SDK_OLD"; then
- DEFINES="$DEFINES -D__NEW_PS2SDK__"
+ append_var DEFINES "-D__NEW_PS2SDK__"
fi
;;
ps3)
@@ -2399,87 +2409,87 @@ case $_host_os in
_sdlpath="$PS3DEV/portlibs/ppu:$PS3DEV/portlibs/ppu/bin"
_freetypepath="$PS3DEV/portlibs/ppu:$PS3DEV/portlibs/ppu/bin"
- DEFINES="$DEFINES -DPLAYSTATION3"
- CXXFLAGS="$CXXFLAGS -mcpu=cell -mminimal-toc -I$PSL1GHT/ppu/include -I$PS3DEV/portlibs/ppu/include"
- LDFLAGS="$LDFLAGS -L$PSL1GHT/ppu/lib -L$PS3DEV/portlibs/ppu/lib"
+ append_var DEFINES "-DPLAYSTATION3"
+ append_var CXXFLAGS "-mcpu=cell -mminimal-toc -I$PSL1GHT/ppu/include -I$PS3DEV/portlibs/ppu/include"
+ append_var LDFLAGS "-L$PSL1GHT/ppu/lib -L$PS3DEV/portlibs/ppu/lib"
add_line_to_config_mk 'PLAYSTATION3 = 1'
add_line_to_config_h "#define PREFIX \"${prefix}\""
;;
psp)
if test -d "$PSPDEV/psp/lib"; then
- LDFLAGS="$LDFLAGS -L$PSPDEV/psp/lib"
+ append_var LDFLAGS "-L$PSPDEV/psp/lib"
fi
- LDFLAGS="$LDFLAGS -L$PSPSDK/lib"
- LDFLAGS="$LDFLAGS -specs=$_srcdir/backends/platform/psp/psp.spec"
+ append_var LDFLAGS "-L$PSPSDK/lib"
+ append_var LDFLAGS "-specs=$_srcdir/backends/platform/psp/psp.spec"
_optimization_level=-O3
- CXXFLAGS="$CXXFLAGS -I$PSPSDK/include"
+ append_var CXXFLAGS "-I$PSPSDK/include"
# FIXME: Why is the following in CXXFLAGS and not in DEFINES? Change or document this.
- CXXFLAGS="$CXXFLAGS -D_PSP_FW_VERSION=150"
+ append_var CXXFLAGS "-D_PSP_FW_VERSION=150"
;;
solaris*)
- DEFINES="$DEFINES -DSOLARIS"
- DEFINES="$DEFINES -DSYSTEM_NOT_SUPPORTING_D_TYPE"
+ append_var DEFINES "-DSOLARIS"
+ append_var DEFINES "-DSYSTEM_NOT_SUPPORTING_D_TYPE"
# Needs -lbind -lsocket for the timidity MIDI driver
- LIBS="$LIBS -lnsl -lsocket"
+ append_var LIBS "-lnsl -lsocket"
;;
tizen)
add_line_to_config_mk "TIZEN_ROOTSTRAP = $TIZEN_ROOTSTRAP"
- LDFLAGS="$LDFLAGS --sysroot=${TIZEN_ROOTSTRAP}"
- LDFLAGS="$LDFLAGS -L${TIZEN_LIBS}/lib"
- CXXFLAGS="$CXXFLAGS -I${TIZEN_LIBS}/include"
+ append_var LDFLAGS "--sysroot=${TIZEN_ROOTSTRAP}"
+ append_var LDFLAGS "-L${TIZEN_LIBS}/lib"
+ append_var CXXFLAGS "-I${TIZEN_LIBS}/include"
;;
webos)
- CXXFLAGS="$CXXFLAGS --sysroot=$WEBOS_PDK/arm-gcc/sysroot"
- CXXFLAGS="$CXXFLAGS -I$WEBOS_PDK/include"
- CXXFLAGS="$CXXFLAGS -I$WEBOS_PDK/include/SDL"
- CXXFLAGS="$CXXFLAGS -I$WEBOS_PDK/device/usr/include"
+ append_var CXXFLAGS "--sysroot=$WEBOS_PDK/arm-gcc/sysroot"
+ append_var CXXFLAGS "-I$WEBOS_PDK/include"
+ append_var CXXFLAGS "-I$WEBOS_PDK/include/SDL"
+ append_var CXXFLAGS "-I$WEBOS_PDK/device/usr/include"
# These compiler options are needed to support the Palm Pixi
- CXXFLAGS="$CXXFLAGS -mcpu=arm1136jf-s"
- CXXFLAGS="$CXXFLAGS -mfpu=vfp "
- CXXFLAGS="$CXXFLAGS -mfloat-abi=softfp"
- LDFLAGS="$LDFLAGS -L$WEBOS_PDK/device/lib"
- LDFLAGS="$LDFLAGS -L$WEBOS_PDK/device/usr/lib"
- LDFLAGS="$LDFLAGS -Wl,--allow-shlib-undefined"
- LDFLAGS="$LDFLAGS --sysroot=$WEBOS_PDK/arm-gcc/sysroot"
+ append_var CXXFLAGS "-mcpu=arm1136jf-s"
+ append_var CXXFLAGS "-mfpu=vfp "
+ append_var CXXFLAGS "-mfloat-abi=softfp"
+ append_var LDFLAGS "-L$WEBOS_PDK/device/lib"
+ append_var LDFLAGS "-L$WEBOS_PDK/device/usr/lib"
+ append_var LDFLAGS "-Wl,--allow-shlib-undefined"
+ append_var LDFLAGS "--sysroot=$WEBOS_PDK/arm-gcc/sysroot"
add_line_to_config_mk "WEBOS_SDK = $WEBOS_SDK"
_seq_midi=no
;;
wii)
_optimization_level=-Os
- CXXFLAGS="$CXXFLAGS -mrvl"
- CXXFLAGS="$CXXFLAGS -mcpu=750"
- CXXFLAGS="$CXXFLAGS -meabi"
- CXXFLAGS="$CXXFLAGS -mhard-float"
- CXXFLAGS="$CXXFLAGS -ffunction-sections"
- CXXFLAGS="$CXXFLAGS -fdata-sections"
- CXXFLAGS="$CXXFLAGS -fmodulo-sched"
- CXXFLAGS="$CXXFLAGS -fuse-cxa-atexit"
- CXXFLAGS="$CXXFLAGS -I$DEVKITPRO/libogc/include"
+ append_var CXXFLAGS "-mrvl"
+ append_var CXXFLAGS "-mcpu=750"
+ append_var CXXFLAGS "-meabi"
+ append_var CXXFLAGS "-mhard-float"
+ append_var CXXFLAGS "-ffunction-sections"
+ append_var CXXFLAGS "-fdata-sections"
+ append_var CXXFLAGS "-fmodulo-sched"
+ append_var CXXFLAGS "-fuse-cxa-atexit"
+ append_var CXXFLAGS "-I$DEVKITPRO/libogc/include"
# libogc is required to link the cc tests (includes _start())
- LDFLAGS="$LDFLAGS -mrvl"
- LDFLAGS="$LDFLAGS -mcpu=750"
- LDFLAGS="$LDFLAGS -L$DEVKITPRO/libogc/lib/wii"
- LDFLAGS="$LDFLAGS -logc"
+ append_var LDFLAGS "-mrvl"
+ append_var LDFLAGS "-mcpu=750"
+ append_var LDFLAGS "-L$DEVKITPRO/libogc/lib/wii"
+ append_var LDFLAGS "-logc"
if test "$_dynamic_modules" = "yes" ; then
# retarded toolchain patch forces --gc-sections, overwrite it
- LDFLAGS="$LDFLAGS -Wl,--no-gc-sections"
+ append_var LDFLAGS "-Wl,--no-gc-sections"
fi
;;
wince)
_optimization_level=-O3
- CXXFLAGS="$CXXFLAGS -fno-inline-functions"
- CXXFLAGS="$CXXFLAGS -march=armv4"
- CXXFLAGS="$CXXFLAGS -mtune=xscale"
- DEFINES="$DEFINES -D_WIN32_WCE=300"
- DEFINES="$DEFINES -D__ARM__"
- DEFINES="$DEFINES -D_ARM_"
- DEFINES="$DEFINES -DUNICODE"
- DEFINES="$DEFINES -DFPM_DEFAULT"
- DEFINES="$DEFINES -DNONSTANDARD_PORT"
- DEFINES="$DEFINES -DWRAP_MALLOC"
- DEFINES="$DEFINES -DWIN32"
- DEFINES="$DEFINES -Dcdecl="
- DEFINES="$DEFINES -D__cdecl__="
+ append_var CXXFLAGS "-fno-inline-functions"
+ append_var CXXFLAGS "-march=armv4"
+ append_var CXXFLAGS "-mtune=xscale"
+ append_var DEFINES "-D_WIN32_WCE=300"
+ append_var DEFINES "-D__ARM__"
+ append_var DEFINES "-D_ARM_"
+ append_var DEFINES "-DUNICODE"
+ append_var DEFINES "-DFPM_DEFAULT"
+ append_var DEFINES "-DNONSTANDARD_PORT"
+ append_var DEFINES "-DWRAP_MALLOC"
+ append_var DEFINES "-DWIN32"
+ append_var DEFINES "-Dcdecl="
+ append_var DEFINES "-D__cdecl__="
add_line_to_config_mk "WRAP_MALLOC = 1"
;;
esac
@@ -2490,8 +2500,8 @@ if test -n "$_host"; then
case "$_host" in
android | android-arm | android-v7a | android-arm-v7a | android-mips | android-x86 | ouya)
# we link a .so as default
- LDFLAGS="$LDFLAGS -shared"
- LDFLAGS="$LDFLAGS -Wl,-Bsymbolic,--no-undefined"
+ append_var LDFLAGS "-shared"
+ append_var LDFLAGS "-Wl,-Bsymbolic,--no-undefined"
HOSTEXEPRE=lib
HOSTEXEEXT=.so
_backend="android"
@@ -2504,19 +2514,18 @@ if test -n "$_host"; then
arm-linux|arm*-linux-gnueabi|arm-*-linux)
;;
arm-riscos|linupy)
- DEFINES="$DEFINES -DLINUPY"
+ append_var DEFINES "-DLINUPY"
;;
bfin*)
;;
caanoo)
- DEFINES="$DEFINES -DCAANOO"
+ append_var DEFINES "-DCAANOO"
if test "$_debug_build" = no; then
# Use -O3 on the Caanoo for non-debug builds.
_optimization_level=-O3
fi
- CXXFLAGS="$CXXFLAGS -mcpu=arm926ej-s"
- CXXFLAGS="$CXXFLAGS -mtune=arm926ej-s"
- ASFLAGS="$ASFLAGS"
+ append_var CXXFLAGS "-mcpu=arm926ej-s"
+ append_var CXXFLAGS "-mtune=arm926ej-s"
_backend="gph"
_build_hq_scalers=no
_savegame_timestamp=no
@@ -2531,12 +2540,11 @@ if test -n "$_host"; then
_strip=$_host-strip
;;
dingux)
- DEFINES="$DEFINES -DDINGUX"
- DEFINES="$DEFINES -DDISABLE_DOSBOX_OPL"
- DEFINES="$DEFINES -DREDUCE_MEMORY_USAGE"
- ASFLAGS="$ASFLAGS"
- CXXFLAGS="$CXXFLAGS -msoft-float"
- CXXFLAGS="$CXXFLAGS -mips32"
+ append_var DEFINES "-DDINGUX"
+ append_var DEFINES "-DDISABLE_DOSBOX_OPL"
+ append_var DEFINES "-DREDUCE_MEMORY_USAGE"
+ append_var CXXFLAGS "-msoft-float"
+ append_var CXXFLAGS "-mips32"
_backend="dingux"
_mt32emu=no
_optimization_level=-O3
@@ -2552,20 +2560,20 @@ if test -n "$_host"; then
_port_mk="backends/platform/dingux/dingux.mk"
;;
dreamcast)
- DEFINES="$DEFINES -DDISABLE_DEFAULT_SAVEFILEMANAGER"
- DEFINES="$DEFINES -DDISABLE_TEXT_CONSOLE"
- DEFINES="$DEFINES -DDISABLE_COMMAND_LINE"
+ append_var DEFINES "-DDISABLE_DEFAULT_SAVEFILEMANAGER"
+ append_var DEFINES "-DDISABLE_TEXT_CONSOLE"
+ append_var DEFINES "-DDISABLE_COMMAND_LINE"
# Enable serial debugging output only when --enable-debug is passed
if test "$_release_build" = yes -o "$_debug_build" != yes; then
- DEFINES="$DEFINES -DNOSERIAL"
+ append_var DEFINES "-DNOSERIAL"
fi
_optimization_level=-O3
- CXXFLAGS="$CXXFLAGS -funroll-loops"
- CXXFLAGS="$CXXFLAGS -fschedule-insns2"
- CXXFLAGS="$CXXFLAGS -fomit-frame-pointer"
- CXXFLAGS="$CXXFLAGS -fdelete-null-pointer-checks"
+ append_var CXXFLAGS "-funroll-loops"
+ append_var CXXFLAGS "-fschedule-insns2"
+ append_var CXXFLAGS "-fomit-frame-pointer"
+ append_var CXXFLAGS "-fdelete-null-pointer-checks"
# no-delayed-branch is a workaround for GCC bug #42841 - "SH: Assembler complains pcrel too far."
- CXXFLAGS="$CXXFLAGS -fno-delayed-branch"
+ append_var CXXFLAGS "-fno-delayed-branch"
_backend="dc"
_build_scalers=no
_mad=yes
@@ -2574,16 +2582,16 @@ if test -n "$_host"; then
_port_mk="backends/platform/dc/dreamcast.mk"
;;
ds)
- DEFINES="$DEFINES -DDISABLE_COMMAND_LINE"
- DEFINES="$DEFINES -DDISABLE_DEFAULT_SAVEFILEMANAGER"
- DEFINES="$DEFINES -DDISABLE_DOSBOX_OPL"
- DEFINES="$DEFINES -DDISABLE_FANCY_THEMES"
- DEFINES="$DEFINES -DDISABLE_SID"
- DEFINES="$DEFINES -DDISABLE_NES_APU"
- DEFINES="$DEFINES -DDISABLE_TEXT_CONSOLE"
- DEFINES="$DEFINES -DREDUCE_MEMORY_USAGE"
- DEFINES="$DEFINES -DSTREAM_AUDIO_FROM_DISK"
- DEFINES="$DEFINES -DVECTOR_RENDERER_FORMAT=1555"
+ append_var DEFINES "-DDISABLE_COMMAND_LINE"
+ append_var DEFINES "-DDISABLE_DEFAULT_SAVEFILEMANAGER"
+ append_var DEFINES "-DDISABLE_DOSBOX_OPL"
+ append_var DEFINES "-DDISABLE_FANCY_THEMES"
+ append_var DEFINES "-DDISABLE_SID"
+ append_var DEFINES "-DDISABLE_NES_APU"
+ append_var DEFINES "-DDISABLE_TEXT_CONSOLE"
+ append_var DEFINES "-DREDUCE_MEMORY_USAGE"
+ append_var DEFINES "-DSTREAM_AUDIO_FROM_DISK"
+ append_var DEFINES "-DVECTOR_RENDERER_FORMAT=1555"
_backend="ds"
_build_scalers=no
_mt32emu=no
@@ -2604,10 +2612,9 @@ if test -n "$_host"; then
add_line_to_config_h "#define USE_WII_DI"
;;
gcw0)
- DEFINES="$DEFINES -DDINGUX -DGCW0"
- DEFINES="$DEFINES -DREDUCE_MEMORY_USAGE"
- ASFLAGS="$ASFLAGS"
- CXXFLAGS="$CXXFLAGS -mips32"
+ append_var DEFINES "-DDINGUX -DGCW0"
+ append_var DEFINES "-DREDUCE_MEMORY_USAGE"
+ append_var CXXFLAGS "-mips32"
_backend="dingux"
_mt32emu=no
_optimization_level=-O3
@@ -2623,10 +2630,10 @@ if test -n "$_host"; then
_port_mk="backends/platform/dingux/dingux.mk"
;;
gp2x)
- DEFINES="$DEFINES -DGP2X"
- CXXFLAGS="$CXXFLAGS -march=armv4t"
- ASFLAGS="$ASFLAGS -mfloat-abi=soft"
- LDFLAGS="$LDFLAGS -static"
+ append_var DEFINES "-DGP2X"
+ append_var CXXFLAGS "-march=armv4t"
+ append_var ASFLAGS "-mfloat-abi=soft"
+ append_var LDFLAGS "-static"
_backend="gph"
_build_hq_scalers=no
_savegame_timestamp=no
@@ -2637,10 +2644,10 @@ if test -n "$_host"; then
_port_mk="backends/platform/gph/gp2x-bundle.mk"
;;
gp2xwiz)
- DEFINES="$DEFINES -DGP2XWIZ"
- CXXFLAGS="$CXXFLAGS -mcpu=arm926ej-s"
- CXXFLAGS="$CXXFLAGS -mtune=arm926ej-s"
- ASFLAGS="$ASFLAGS -mfloat-abi=soft"
+ append_var DEFINES "-DGP2XWIZ"
+ append_var CXXFLAGS "-mcpu=arm926ej-s"
+ append_var CXXFLAGS "-mtune=arm926ej-s"
+ append_var ASFLAGS "-mfloat-abi=soft"
_backend="gph"
_build_hq_scalers=no
_savegame_timestamp=no
@@ -2651,8 +2658,8 @@ if test -n "$_host"; then
_port_mk="backends/platform/gph/gp2xwiz-bundle.mk"
;;
iphone)
- DEFINES="$DEFINES -DIPHONE"
- ASFLAGS="$ASFLAGS -arch armv6"
+ append_var DEFINES "-DIPHONE"
+ append_var ASFLAGS "-arch armv6"
_backend="iphone"
_build_scalers=no
_mt32emu=no
@@ -2660,18 +2667,18 @@ if test -n "$_host"; then
_timidity=no
;;
m68k-atari-mint)
- DEFINES="$DEFINES -DSYSTEM_NOT_SUPPORTING_D_TYPE"
+ append_var DEFINES "-DSYSTEM_NOT_SUPPORTING_D_TYPE"
_ranlib=m68k-atari-mint-ranlib
_ar="m68k-atari-mint-ar cru"
_seq_midi=no
;;
maemo)
_optimization_level=-Os
- CXXFLAGS="$CXXFLAGS -mcpu=arm926ej-s"
- CXXFLAGS="$CXXFLAGS -fomit-frame-pointer"
- INCLUDES="$INCLUDES -I/usr/X11R6/include"
- LIBS="$LIBS -lX11"
- LIBS="$LIBS -L/usr/lib"
+ append_var CXXFLAGS "-mcpu=arm926ej-s"
+ append_var CXXFLAGS "-fomit-frame-pointer"
+ append_var INCLUDES "-I/usr/X11R6/include"
+ append_var LIBS "-lX11"
+ append_var LIBS "-L/usr/lib"
_backend="maemo"
_vkeybd=yes
@@ -2690,12 +2697,12 @@ if test -n "$_host"; then
_ranlib=$_host-ranlib
;;
mips-sgi*)
- LDFLAGS="$LDFLAGS -static-libgcc"
- LIBS="$LIBS -laudio"
+ append_var LDFLAGS "-static-libgcc"
+ append_var LIBS "-laudio"
;;
motoezx)
- DEFINES="$DEFINES -DMOTOEZX"
- ASFLAGS="$ASFLAGS -mfpu=vfp"
+ append_var DEFINES "-DMOTOEZX"
+ append_var ASFLAGS "-mfpu=vfp"
_backend="linuxmoto"
_build_hq_scalers=no
_mt32emu=no
@@ -2704,8 +2711,8 @@ if test -n "$_host"; then
_port_mk="backends/platform/linuxmoto/linuxmoto.mk"
;;
motomagx)
- DEFINES="$DEFINES -DMOTOMAGX"
- ASFLAGS="$ASFLAGS -mfpu=vfp"
+ append_var DEFINES "-DMOTOMAGX"
+ append_var ASFLAGS "-mfpu=vfp"
_backend="linuxmoto"
_build_hq_scalers=no
_mt32emu=no
@@ -2714,20 +2721,20 @@ if test -n "$_host"; then
_port_mk="backends/platform/linuxmoto/linuxmoto.mk"
;;
n64)
- CXXFLAGS="$CXXFLAGS -mno-extern-sdata"
- CXXFLAGS="$CXXFLAGS --param max-inline-insns-auto=20"
- CXXFLAGS="$CXXFLAGS -fomit-frame-pointer"
- CXXFLAGS="$CXXFLAGS -march=vr4300"
- CXXFLAGS="$CXXFLAGS -mtune=vr4300"
- CXXFLAGS="$CXXFLAGS -mhard-float"
- LDFLAGS="$LDFLAGS -march=vr4300"
- LDFLAGS="$LDFLAGS -mtune=vr4300"
- LDFLAGS="$LDFLAGS -nodefaultlibs"
- LDFLAGS="$LDFLAGS -nostartfiles"
- LDFLAGS="$LDFLAGS -mno-crt0"
- LDFLAGS="$LDFLAGS -L$N64SDK/hkz-libn64"
- LDFLAGS="$LDFLAGS -L$N64SDK/lib"
- LDFLAGS="$LDFLAGS -T n64ld_cpp.x -Xlinker -Map -Xlinker scummvm.map"
+ append_var CXXFLAGS "-mno-extern-sdata"
+ append_var CXXFLAGS "--param max-inline-insns-auto=20"
+ append_var CXXFLAGS "-fomit-frame-pointer"
+ append_var CXXFLAGS "-march=vr4300"
+ append_var CXXFLAGS "-mtune=vr4300"
+ append_var CXXFLAGS "-mhard-float"
+ append_var LDFLAGS "-march=vr4300"
+ append_var LDFLAGS "-mtune=vr4300"
+ append_var LDFLAGS "-nodefaultlibs"
+ append_var LDFLAGS "-nostartfiles"
+ append_var LDFLAGS "-mno-crt0"
+ append_var LDFLAGS "-L$N64SDK/hkz-libn64"
+ append_var LDFLAGS "-L$N64SDK/lib"
+ append_var LDFLAGS "-T n64ld_cpp.x -Xlinker -Map -Xlinker scummvm.map"
_backend="n64"
_mt32emu=no
_build_scalers=no
@@ -2745,16 +2752,16 @@ if test -n "$_host"; then
_port_mk="backends/platform/n64/n64.mk"
;;
neuros)
- DEFINES="$DEFINES -DNEUROS"
+ append_var DEFINES "-DNEUROS"
_backend='null'
_build_hq_scalers=no
_mt32emu=no
;;
openpandora)
- DEFINES="$DEFINES -DOPENPANDORA"
- DEFINES="$DEFINES -DREDUCE_MEMORY_USAGE"
+ append_var DEFINES "-DOPENPANDORA"
+ append_var DEFINES "-DREDUCE_MEMORY_USAGE"
if test "$_release_build" = no; then
- DEFINES="$DEFINES -DOP_DEBUG"
+ append_var DEFINES "-DOP_DEBUG"
fi
# Use -O3 on the OpenPandora for optimized builds.
@@ -2763,12 +2770,12 @@ if test -n "$_host"; then
fi
define_in_config_if_yes yes 'USE_ARM_NEON_ASPECT_CORRECTOR'
- CXXFLAGS="$CXXFLAGS -march=armv7-a"
- CXXFLAGS="$CXXFLAGS -mtune=cortex-a8"
- CXXFLAGS="$CXXFLAGS -mfloat-abi=softfp"
- CXXFLAGS="$CXXFLAGS -mfpu=neon"
- CXXFLAGS="$CXXFLAGS -fsingle-precision-constant"
- ASFLAGS="$ASFLAGS -mfloat-abi=softfp"
+ append_var CXXFLAGS "-march=armv7-a"
+ append_var CXXFLAGS "-mtune=cortex-a8"
+ append_var CXXFLAGS "-mfloat-abi=softfp"
+ append_var CXXFLAGS "-mfpu=neon"
+ append_var CXXFLAGS "-fsingle-precision-constant"
+ append_var ASFLAGS "-mfloat-abi=softfp"
_backend="openpandora"
_build_hq_scalers=yes
_vkeybd=no
@@ -2778,11 +2785,11 @@ if test -n "$_host"; then
;;
ppc-amigaos)
# PPC Linker requires this to fix relocation errors
- CXXFLAGS="$CXXFLAGS -mlongcall"
+ append_var CXXFLAGS "-mlongcall"
# Only static builds link successfully on buildbot
LDFLAGS=`echo $LDFLAGS | sed 's/-use-dynld//'`
- LDFLAGS="$LDFLAGS -static"
+ append_var LDFLAGS "-static"
# toolchain binaries prefixed by host
_ranlib=$_host-ranlib
@@ -2794,13 +2801,13 @@ if test -n "$_host"; then
_port_mk="backends/platform/sdl/amigaos/amigaos.mk"
;;
ps2)
- DEFINES="$DEFINES -DDISABLE_TEXT_CONSOLE"
- DEFINES="$DEFINES -DDISABLE_COMMAND_LINE"
- DEFINES="$DEFINES -DDISABLE_DOSBOX_OPL"
- DEFINES="$DEFINES -DDISABLE_SID"
- DEFINES="$DEFINES -DDISABLE_NES_APU"
- CXXFLAGS="$CXXFLAGS -fno-exceptions"
- CXXFLAGS="$CXXFLAGS -fno-rtti"
+ append_var DEFINES "-DDISABLE_TEXT_CONSOLE"
+ append_var DEFINES "-DDISABLE_COMMAND_LINE"
+ append_var DEFINES "-DDISABLE_DOSBOX_OPL"
+ append_var DEFINES "-DDISABLE_SID"
+ append_var DEFINES "-DDISABLE_NES_APU"
+ append_var CXXFLAGS "-fno-exceptions"
+ append_var CXXFLAGS "-fno-rtti"
_backend="ps2"
_build_scalers=no
_mt32emu=no
@@ -2822,15 +2829,15 @@ if test -n "$_host"; then
if test "$_debug_build" = yes; then
# TODO: Setup debug build properly
- DEFINES="$DEFINES -D__PS2_DEBUG__"
- #INCLUDES="$INCLUDES -I$(PS2GDB)/ee"
- #LDFLAGS="$LDFLAGS -L$(PS2GDB)/lib"
- LDFLAGS="$LDFLAGS -lps2gdbStub"
- LDFLAGS="$LDFLAGS -lps2ip"
- LDFLAGS="$LDFLAGS -ldebug"
+ append_var DEFINES "-D__PS2_DEBUG__"
+ #append_var INCLUDES "-I$(PS2GDB)/ee"
+ #append_var LDFLAGS "-L$(PS2GDB)/lib"
+ append_var LDFLAGS "-lps2gdbStub"
+ append_var LDFLAGS "-lps2ip"
+ append_var LDFLAGS "-ldebug"
else
# If not building for debug mode, strip binaries.
- CXXFLAGS="$CXXFLAGS -s"
+ append_var CXXFLAGS "-s"
fi
;;
ps3)
@@ -2847,9 +2854,9 @@ if test -n "$_host"; then
_port_mk="backends/platform/psp/psp.mk"
;;
samsungtv)
- DEFINES="$DEFINES -DSAMSUNGTV"
- DEFINES="$DEFINES -DDISABLE_COMMAND_LINE"
- ASFLAGS="$ASFLAGS -mfpu=vfp"
+ append_var DEFINES "-DSAMSUNGTV"
+ append_var DEFINES "-DDISABLE_COMMAND_LINE"
+ append_var ASFLAGS "-mfpu=vfp"
HOSTEXEEXT=".so"
_backend="samsungtv"
_mt32emu=no
@@ -2893,7 +2900,7 @@ if test -n "$_host"; then
add_line_to_config_h "#define USE_WII_KBD"
;;
wince)
- LDFLAGS="$LDFLAGS -Wl,--stack,65536"
+ append_var LDFLAGS "-Wl,--stack,65536"
_tremolo=yes
_backend="wince"
_detectlang=yes
@@ -2911,140 +2918,140 @@ fi
#
case $_backend in
android)
- DEFINES="$DEFINES -DREDUCE_MEMORY_USAGE"
- CXXFLAGS="$CXXFLAGS -Wa,--noexecstack"
- LDFLAGS="$LDFLAGS -Wl,-z,noexecstack"
- INCLUDES="$INCLUDES -I$ANDROID_NDK/sources/cxx-stl/system/include"
+ 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"
;;
dc)
- INCLUDES="$INCLUDES "'-I$(srcdir)/backends/platform/dc'
- INCLUDES="$INCLUDES "'-isystem $(ronindir)/include'
- LDFLAGS="$LDFLAGS -Wl,-Ttext,0x8c010000"
- LDFLAGS="$LDFLAGS -nostartfiles"
- LDFLAGS="$LDFLAGS "'$(ronindir)/lib/crt0.o'
- LDFLAGS="$LDFLAGS "'-L$(ronindir)/lib'
+ append_var INCLUDES '-I$(srcdir)/backends/platform/dc'
+ append_var INCLUDES '-isystem $(ronindir)/include'
+ append_var LDFLAGS "-Wl,-Ttext,0x8c010000"
+ append_var LDFLAGS "-nostartfiles"
+ append_var LDFLAGS '$(ronindir)/lib/crt0.o'
+ append_var LDFLAGS '-L$(ronindir)/lib'
# Enable serial debugging output only when --enable-debug is passed
if test "$_release_build" = yes -o "$_debug_build" != yes; then
- LIBS="$LIBS -lronin-noserial -lm"
+ append_var LIBS "-lronin-noserial -lm"
else
- LIBS="$LIBS -lronin -lm"
+ append_var LIBS "-lronin -lm"
fi
;;
dingux)
- DEFINES="$DEFINES -DDINGUX"
+ append_var DEFINES "-DDINGUX"
;;
ds)
- INCLUDES="$INCLUDES "'-I$(srcdir)/backends/platform/ds/arm9/source'
- INCLUDES="$INCLUDES "'-I$(srcdir)/backends/platform/ds/commoninclude'
- INCLUDES="$INCLUDES "'-Ibackends/platform/ds/arm9/data'
+ append_var INCLUDES '-I$(srcdir)/backends/platform/ds/arm9/source'
+ append_var INCLUDES '-I$(srcdir)/backends/platform/ds/commoninclude'
+ append_var INCLUDES '-Ibackends/platform/ds/arm9/data'
;;
gph)
# On the GPH devices we want fancy themes but do not want the load/save thumbnail grid.
- DEFINES="$DEFINES -DDISABLE_SAVELOADCHOOSER_GRID"
- DEFINES="$DEFINES -DGPH_DEVICE"
- DEFINES="$DEFINES -DREDUCE_MEMORY_USAGE"
+ append_var DEFINES "-DDISABLE_SAVELOADCHOOSER_GRID"
+ append_var DEFINES "-DGPH_DEVICE"
+ append_var DEFINES "-DREDUCE_MEMORY_USAGE"
if test "$_debug_build" = yes; then
- DEFINES="$DEFINES -DGPH_DEBUG"
+ append_var DEFINES "-DGPH_DEBUG"
fi
;;
iphone)
- LIBS="$LIBS -lobjc -framework UIKit -framework CoreGraphics -framework OpenGLES"
- LIBS="$LIBS -framework QuartzCore -framework CoreFoundation -framework Foundation"
- LIBS="$LIBS -framework AudioToolbox -framework CoreAudio"
+ 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"
;;
linuxmoto)
- DEFINES="$DEFINES -DLINUXMOTO"
+ append_var DEFINES "-DLINUXMOTO"
;;
maemo)
- DEFINES="$DEFINES -DMAEMO"
+ append_var DEFINES "-DMAEMO"
;;
n64)
- INCLUDES="$INCLUDES "'-I$(N64SDK)/include'
- INCLUDES="$INCLUDES "'-I$(N64SDK)/mips64/include'
- INCLUDES="$INCLUDES "'-I$(N64SDK)/hkz-libn64'
- INCLUDES="$INCLUDES "'-I$(srcdir)/backends/platform/n64'
- LIBS="$LIBS -lpakfs -lframfs -ln64 -ln64utils -lromfs"
- LIBS="$LIBS -lm -lstdc++ -lz"
+ append_var INCLUDES '-I$(N64SDK)/include'
+ append_var INCLUDES '-I$(N64SDK)/mips64/include'
+ append_var INCLUDES '-I$(N64SDK)/hkz-libn64'
+ append_var INCLUDES '-I$(srcdir)/backends/platform/n64'
+ append_var LIBS "-lpakfs -lframfs -ln64 -ln64utils -lromfs"
+ append_var LIBS "-lm -lstdc++ -lz"
;;
null)
- DEFINES="$DEFINES -DUSE_NULL_DRIVER"
+ append_var DEFINES "-DUSE_NULL_DRIVER"
;;
openpandora)
;;
ps2)
- DEFINES="$DEFINES -D_EE"
- DEFINES="$DEFINES -DFORCE_RTL"
- INCLUDES="$INCLUDES -I$PS2SDK/ee/include"
- INCLUDES="$INCLUDES -I$PS2SDK/common/include"
- INCLUDES="$INCLUDES -I$PS2SDK/ports/include"
+ append_var DEFINES "-D_EE"
+ append_var DEFINES "-DFORCE_RTL"
+ append_var INCLUDES "-I$PS2SDK/ee/include"
+ append_var INCLUDES "-I$PS2SDK/common/include"
+ append_var INCLUDES "-I$PS2SDK/ports/include"
if test "$_dynamic_modules" = no ; then
- LDFLAGS="$LDFLAGS -mno-crt0"
- LDFLAGS="$LDFLAGS $PS2SDK/ee/startup/crt0.o"
- LDFLAGS="$LDFLAGS -T $PS2SDK/ee/startup/linkfile"
+ append_var LDFLAGS "-mno-crt0"
+ append_var LDFLAGS "$PS2SDK/ee/startup/crt0.o"
+ append_var LDFLAGS "-T $PS2SDK/ee/startup/linkfile"
fi
- LDFLAGS="$LDFLAGS -L$PS2SDK/ee/lib"
- LDFLAGS="$LDFLAGS -L$PS2SDK/ports/lib"
- LIBS="$LIBS -lmc -lpad -lmouse -lhdd -lpoweroff -lsjpcm"
- LIBS="$LIBS -lm -lc -lfileXio -lkernel -lstdc++"
+ append_var LDFLAGS "-L$PS2SDK/ee/lib"
+ append_var LDFLAGS "-L$PS2SDK/ports/lib"
+ append_var LIBS "-lmc -lpad -lmouse -lhdd -lpoweroff -lsjpcm"
+ append_var LIBS "-lm -lc -lfileXio -lkernel -lstdc++"
;;
psp)
- DEFINES="$DEFINES -D__PSP__"
- DEFINES="$DEFINES -DDISABLE_COMMAND_LINE"
- DEFINES="$DEFINES -DDISABLE_DOSBOX_OPL"
- LIBS="$LIBS -lpng"
- LIBS="$LIBS -Wl,-Map,mapfile.txt"
+ append_var DEFINES "-D__PSP__"
+ append_var DEFINES "-DDISABLE_COMMAND_LINE"
+ append_var DEFINES "-DDISABLE_DOSBOX_OPL"
+ append_var LIBS "-lpng"
+ append_var LIBS "-Wl,-Map,mapfile.txt"
;;
samsungtv)
- DEFINES="$DEFINES -DSAMSUNGTV"
- LDFLAGS="$LDFLAGS -shared"
- LDFLAGS="$LDFLAGS -fpic"
+ append_var DEFINES "-DSAMSUNGTV"
+ append_var LDFLAGS "-shared"
+ append_var LDFLAGS "-fpic"
;;
tizen)
# dirent.h not available. NONSTANDARD_PORT==ensure portdefs.h is included
- DEFINES="$DEFINES -DTIZEN -DDISABLE_STDIO_FILESTREAM -DNONSTANDARD_PORT"
- DEFINES="$DEFINES -DNO_STDERR_STDOUT"
- DEFINES="$DEFINES -DDISABLE_COMMAND_LINE"
- INCLUDES="$INCLUDES "'-I$(srcdir)/backends/platform/tizen'
- INCLUDES="$INCLUDES "'-I$(TIZEN_ROOTSTRAP)/usr/include'
- INCLUDES="$INCLUDES "'-I$(TIZEN_ROOTSTRAP)/usr/include/osp'
+ append_var DEFINES "-DTIZEN -DDISABLE_STDIO_FILESTREAM -DNONSTANDARD_PORT"
+ append_var DEFINES "-DNO_STDERR_STDOUT"
+ append_var DEFINES "-DDISABLE_COMMAND_LINE"
+ append_var INCLUDES '-I$(srcdir)/backends/platform/tizen'
+ append_var INCLUDES '-I$(TIZEN_ROOTSTRAP)/usr/include'
+ append_var INCLUDES '-I$(TIZEN_ROOTSTRAP)/usr/include/osp'
if test "$_debug_build" = yes; then
- CXXFLAGS="$CXXFLAGS -D_DEBUG -DBUILD_DLL -O0 -g3"
+ append_var CXXFLAGS "-D_DEBUG -DBUILD_DLL -O0 -g3"
fi
# created a shared library for inclusion via the eclipse build
- CXXFLAGS="$CXXFLAGS -Wno-psabi"
- CXXFLAGS="$CXXFLAGS --sysroot=${TIZEN_ROOTSTRAP}"
- CXXFLAGS="$CXXFLAGS -fmessage-length=0"
- CXXFLAGS="$CXXFLAGS -fPIC"
+ append_var CXXFLAGS "-Wno-psabi"
+ append_var CXXFLAGS "--sysroot=${TIZEN_ROOTSTRAP}"
+ append_var CXXFLAGS "-fmessage-length=0"
+ append_var CXXFLAGS "-fPIC"
HOSTEXEPRE=lib
HOSTEXEEXT=.a
;;
webos)
# There is no sdl-config in the WebOS PDK so we don't use find_sdlconfig here.
# The PDL library acts as the WebOS device toolchain, and is required to control the virtual keyboard among other OS-level events.
- LIBS="$LIBS -lSDL -lpdl"
- DEFINES="$DEFINES -DWEBOS"
- DEFINES="$DEFINES -DSDL_BACKEND"
+ append_var LIBS "-lSDL -lpdl"
+ append_var DEFINES "-DWEBOS"
+ append_var DEFINES "-DSDL_BACKEND"
add_line_to_config_mk "SDL_BACKEND = 1"
- MODULES="$MODULES backends/platform/sdl"
+ append_var MODULES "backends/platform/sdl"
;;
wii)
- DEFINES="$DEFINES -D__WII__"
- DEFINES="$DEFINES -DGEKKO"
+ append_var DEFINES "-D__WII__"
+ append_var DEFINES "-DGEKKO"
case $_host_os in
gamecube)
- LIBS="$LIBS -lgxflux -liso9660 -lfat -logc -ldb"
+ append_var LIBS "-lgxflux -liso9660 -lfat -logc -ldb"
;;
*)
- LIBS="$LIBS -lgxflux -ldi -liso9660 -ltinysmb -lfat -lwiiuse -lbte -logc -lwiikeyboard -ldb"
+ append_var LIBS "-lgxflux -ldi -liso9660 -ltinysmb -lfat -lwiiuse -lbte -logc -lwiikeyboard -ldb"
;;
esac
;;
wince)
- INCLUDES="$INCLUDES "'-I$(srcdir)/backends/platform/wince'
- INCLUDES="$INCLUDES "'-I$(srcdir)/backends/platform/wince/CEgui'
- INCLUDES="$INCLUDES "'-I$(srcdir)/backends/platform/wince/CEkeys'
- LIBS="$LIBS -static -lSDL"
- DEFINES="$DEFINES -DSDL_BACKEND"
+ append_var INCLUDES '-I$(srcdir)/backends/platform/wince'
+ append_var INCLUDES '-I$(srcdir)/backends/platform/wince/CEgui'
+ append_var INCLUDES '-I$(srcdir)/backends/platform/wince/CEkeys'
+ append_var LIBS "-static -lSDL"
+ append_var DEFINES "-DSDL_BACKEND"
add_line_to_config_mk "SDL_BACKEND = 1"
;;
sdl)
@@ -3054,7 +3061,7 @@ case $_backend in
exit 1
;;
esac
-MODULES="$MODULES backends/platform/$_backend"
+append_var MODULES "backends/platform/$_backend"
#
# Setup SDL specifics for SDL based backends
@@ -3062,9 +3069,9 @@ MODULES="$MODULES backends/platform/$_backend"
case $_backend in
dingux | gph | linuxmoto | maemo | openpandora | samsungtv | sdl)
find_sdlconfig
- INCLUDES="$INCLUDES `$_sdlconfig --prefix="$_sdlpath" --cflags`"
- LIBS="$LIBS `$_sdlconfig --prefix="$_sdlpath" --libs`"
- DEFINES="$DEFINES -DSDL_BACKEND"
+ append_var INCLUDES "`$_sdlconfig --prefix="$_sdlpath" --cflags`"
+ append_var LIBS "`$_sdlconfig --prefix="$_sdlpath" --libs`"
+ append_var DEFINES "-DSDL_BACKEND"
add_line_to_config_mk "SDL_BACKEND = 1"
_sdlversion=`$_sdlconfig --version`
@@ -3164,7 +3171,7 @@ esac
echo $_posix
if test "$_posix" = yes ; then
- DEFINES="$DEFINES -DPOSIX"
+ append_var DEFINES "-DPOSIX"
add_line_to_config_mk 'POSIX = 1'
fi
@@ -3194,8 +3201,8 @@ fi
if test "$_optimizations" = yes ; then
# Enable optimizations. This also
# makes it possible to use -Wuninitialized, so let's do that.
- CXXFLAGS="$CXXFLAGS $_optimization_level"
- CXXFLAGS="$CXXFLAGS -Wuninitialized"
+ append_var CXXFLAGS "$_optimization_level"
+ append_var CXXFLAGS "-Wuninitialized"
fi
#
@@ -3211,8 +3218,8 @@ if test "$_dynamic_modules" = yes ; then
android)
_plugin_prefix="lib"
_plugin_suffix=".so"
- CXXFLAGS="$CXXFLAGS -fpic"
- LIBS="$LIBS -ldl"
+ append_var CXXFLAGS "-fpic"
+ append_var LIBS "-ldl"
# Work around an Android 2.0+ run-time linker bug:
# The linker doesn't actually look in previously
# loaded libraries when trying to resolve symbols -
@@ -3231,7 +3238,7 @@ POST_OBJS_FLAGS := -Wl,-no-whole-archive
darwin*)
_plugin_prefix=""
_plugin_suffix=".plugin"
- LIBS="$LIBS -ldl"
+ append_var LIBS "-ldl"
_mak_plugins='
PLUGIN_EXTRA_DEPS = $(EXECUTABLE)
PLUGIN_LDFLAGS += -bundle -bundle_loader $(EXECUTABLE) -exported_symbols_list "$(srcdir)/plugin.exp"
@@ -3251,9 +3258,9 @@ POST_OBJS_FLAGS := -Wl,--no-whole-archive
;;
ds)
_elf_loader=yes
- DEFINES="$DEFINES -DELF_LOADER_CXA_ATEXIT"
- DEFINES="$DEFINES -DUNCACHED_PLUGINS"
- DEFINES="$DEFINES -DELF_NO_MEM_MANAGER"
+ append_var DEFINES "-DELF_LOADER_CXA_ATEXIT"
+ append_var DEFINES "-DUNCACHED_PLUGINS"
+ append_var DEFINES "-DELF_NO_MEM_MANAGER"
_mak_plugins='
PLUGIN_LDFLAGS += -Wl,-T$(srcdir)/backends/plugins/ds/plugin.ld -mthumb-interwork -mno-fpu
'
@@ -3261,7 +3268,7 @@ PLUGIN_LDFLAGS += -Wl,-T$(srcdir)/backends/plugins/ds/plugin.ld -mthumb-interwo
freebsd*)
_plugin_prefix="lib"
_plugin_suffix=".so"
- CXXFLAGS="$CXXFLAGS -fPIC"
+ append_var CXXFLAGS "-fPIC"
_mak_plugins='
PLUGIN_EXTRA_DEPS =
PLUGIN_LDFLAGS += -shared
@@ -3271,8 +3278,8 @@ POST_OBJS_FLAGS := -Wl,-no-whole-archive
;;
gamecube | wii)
_elf_loader=yes
- DEFINES="$DEFINES -DELF_LOADER_CXA_ATEXIT"
- DEFINES="$DEFINES -DUNCACHED_PLUGINS"
+ append_var DEFINES "-DELF_LOADER_CXA_ATEXIT"
+ append_var DEFINES "-DUNCACHED_PLUGINS"
_mak_plugins='
PLUGIN_LDFLAGS += -Wl,-T$(srcdir)/backends/plugins/wii/plugin.ld
'
@@ -3280,8 +3287,8 @@ PLUGIN_LDFLAGS += -Wl,-T$(srcdir)/backends/plugins/wii/plugin.ld
gph*)
_plugin_prefix=""
_plugin_suffix=".plugin"
- CXXFLAGS="$CXXFLAGS -fpic"
- LIBS="$LIBS -ldl"
+ append_var CXXFLAGS "-fpic"
+ append_var LIBS "-ldl"
_mak_plugins='
PLUGIN_EXTRA_DEPS = $(EXECUTABLE)
PLUGIN_LDFLAGS += -shared
@@ -3292,8 +3299,8 @@ POST_OBJS_FLAGS := -Wl,-no-whole-archive
irix*)
_plugin_prefix="lib"
_plugin_suffix=".so"
- CXXFLAGS="$CXXFLAGS -fpic"
- LIBS="$LIBS -ldl"
+ append_var CXXFLAGS "-fpic"
+ append_var LIBS "-ldl"
_mak_plugins='
PLUGIN_EXTRA_DEPS =
PLUGIN_LDFLAGS += -shared -static-libgcc
@@ -3305,8 +3312,8 @@ POST_OBJS_FLAGS := -Wl,-no-whole-archive
linux* | gnu* | k*bsd*-gnu*)
_plugin_prefix="lib"
_plugin_suffix=".so"
- CXXFLAGS="$CXXFLAGS -fPIC"
- LIBS="$LIBS -ldl"
+ append_var CXXFLAGS "-fPIC"
+ append_var LIBS "-ldl"
_mak_plugins='
PLUGIN_EXTRA_DEPS =
PLUGIN_LDFLAGS += -shared
@@ -3325,7 +3332,7 @@ POST_OBJS_FLAGS := -Wl,--export-all-symbols -Wl,--no-whole-archive -Wl,--out-im
'
;;
wince)
- DEFINES="$DEFINES -DUNCACHED_PLUGINS"
+ append_var DEFINES "-DUNCACHED_PLUGINS"
HOSTEXEEXT=".dll"
_plugin_prefix=""
_plugin_suffix=".plugin"
@@ -3338,7 +3345,7 @@ POST_OBJS_FLAGS := -Wl,--export-all-symbols -Wl,--no-whole-archive -Wl,--out-im
;;
ps2)
_elf_loader=yes
- DEFINES="$DEFINES -DUNCACHED_PLUGINS"
+ append_var DEFINES "-DUNCACHED_PLUGINS"
_mak_plugins='
LDFLAGS += -mno-crt0 $(PS2SDK)/ee/startup/crt0.o -Wl,-T$(srcdir)/backends/plugins/ps2/main_prog.ld
PLUGIN_LDFLAGS += -mno-crt0 $(PS2SDK)/ee/startup/crt0.o -Wl,-T$(srcdir)/backends/plugins/ps2/plugin.ld -lstdc++ -lc
@@ -3346,7 +3353,7 @@ PLUGIN_LDFLAGS += -mno-crt0 $(PS2SDK)/ee/startup/crt0.o -Wl,-T$(srcdir)/backend
;;
psp)
_elf_loader=yes
- DEFINES="$DEFINES -DUNCACHED_PLUGINS"
+ append_var DEFINES "-DUNCACHED_PLUGINS"
_mak_plugins='
LDFLAGS += -Wl,-T$(srcdir)/backends/plugins/psp/main_prog.ld
PLUGIN_LDFLAGS += -Wl,-T$(srcdir)/backends/plugins/psp/plugin.ld -lstdc++ -lc
@@ -3355,8 +3362,8 @@ PLUGIN_LDFLAGS += -Wl,-T$(srcdir)/backends/plugins/psp/plugin.ld -lstdc++ -lc
webos)
_plugin_prefix="lib"
_plugin_suffix=".so"
- CXXFLAGS="$CXXFLAGS -fpic"
- LIBS="$LIBS -ldl"
+ append_var CXXFLAGS "-fpic"
+ append_var LIBS "-ldl"
_mak_plugins='
PLUGIN_EXTRA_DEPS =
PLUGIN_LDFLAGS += -shared $(LDFLAGS)
@@ -3432,7 +3439,7 @@ define_in_config_if_yes "$_build_hq_scalers" 'USE_HQ_SCALERS'
cat > $TMPC << EOF
int main(void) { return 0; }
EOF
-cc_check -lm && LIBS="$LIBS -lm"
+cc_check -lm && append_var LIBS "-lm"
#
# Check for Ogg Vorbis
@@ -3448,8 +3455,8 @@ EOF
-lvorbisfile -lvorbis -logg && _vorbis=yes
fi
if test "$_vorbis" = yes ; then
- LIBS="$LIBS $OGG_LIBS $VORBIS_LIBS -lvorbisfile -lvorbis -logg"
- INCLUDES="$INCLUDES $OGG_CFLAGS $VORBIS_CFLAGS"
+ append_var LIBS "$OGG_LIBS $VORBIS_LIBS -lvorbisfile -lvorbis -logg"
+ append_var INCLUDES "$OGG_CFLAGS $VORBIS_CFLAGS"
fi
define_in_config_if_yes "$_vorbis" 'USE_VORBIS'
echo "$_vorbis"
@@ -3476,13 +3483,13 @@ if test "$_tremor" = yes && test "$_vorbis" = no; then
add_line_to_config_h '#define USE_VORBIS'
if test "$_tremolo" = yes ; then
add_line_to_config_h '#define USE_TREMOLO'
- LIBS="$LIBS $TREMOR_LIBS -ltremolo"
+ append_var LIBS "$TREMOR_LIBS -ltremolo"
elif test "$_host" = ps2 ; then
LIBS="-ltremor $LIBS"
else
- LIBS="$LIBS $TREMOR_LIBS -lvorbisidec"
+ append_var LIBS "$TREMOR_LIBS -lvorbisidec"
fi
- INCLUDES="$INCLUDES $TREMOR_CFLAGS"
+ append_var INCLUDES "$TREMOR_CFLAGS"
else
if test "$_vorbis" = yes; then
_tremor="no (Ogg Vorbis/Tremor support is mutually exclusive)"
@@ -3512,11 +3519,11 @@ EOF
fi
if test "$_flac" = yes ; then
if test "$_vorbis" = yes ; then
- LIBS="$LIBS $FLAC_LIBS $OGG_LIBS -lFLAC -logg"
+ append_var LIBS "$FLAC_LIBS $OGG_LIBS -lFLAC -logg"
else
- LIBS="$LIBS $FLAC_LIBS -lFLAC"
+ append_var LIBS "$FLAC_LIBS -lFLAC"
fi
- INCLUDES="$INCLUDES $FLAC_CFLAGS"
+ append_var INCLUDES "$FLAC_CFLAGS"
fi
define_in_config_if_yes "$_flac" 'USE_FLAC'
echo "$_flac"
@@ -3534,8 +3541,8 @@ EOF
cc_check $MAD_CFLAGS $MAD_LIBS -lmad && _mad=yes
fi
if test "$_mad" = yes ; then
- LIBS="$LIBS $MAD_LIBS -lmad"
- INCLUDES="$INCLUDES $MAD_CFLAGS"
+ append_var LIBS "$MAD_LIBS -lmad"
+ append_var INCLUDES "$MAD_CFLAGS"
fi
define_in_config_if_yes "$_mad" 'USE_MAD'
echo "$_mad"
@@ -3553,10 +3560,10 @@ EOF
cc_check $ALSA_CFLAGS $ALSA_LIBS -lasound && _alsa=yes
fi
if test "$_alsa" = yes ; then
- LIBS="$LIBS $ALSA_LIBS -lasound"
- INCLUDES="$INCLUDES $ALSA_CFLAGS"
+ append_var LIBS "$ALSA_LIBS -lasound"
+ append_var INCLUDES "$ALSA_CFLAGS"
fi
-define_in_config_h_if_yes "$_alsa" 'USE_ALSA'
+define_in_config_if_yes "$_alsa" 'USE_ALSA'
echo "$_alsa"
#
@@ -3579,8 +3586,8 @@ EOF
cc_check $JPEG_CFLAGS $JPEG_LIBS -ljpeg && _jpeg=yes
fi
if test "$_jpeg" = yes ; then
- LIBS="$LIBS $JPEG_LIBS -ljpeg"
- INCLUDES="$INCLUDES $JPEG_CFLAGS"
+ append_var LIBS "$JPEG_LIBS -ljpeg"
+ append_var INCLUDES "$JPEG_CFLAGS"
fi
define_in_config_if_yes "$_jpeg" 'USE_JPEG'
echo "$_jpeg"
@@ -3604,8 +3611,8 @@ EOF
cc_check $PNG_CFLAGS $PNG_LIBS -lpng -lz && _png=yes
fi
if test "$_png" = yes ; then
- LIBS="$LIBS $PNG_LIBS -lpng -lz"
- INCLUDES="$INCLUDES $PNG_CFLAGS"
+ append_var LIBS "$PNG_LIBS -lpng -lz"
+ append_var INCLUDES "$PNG_CFLAGS"
fi
define_in_config_if_yes "$_png" 'USE_PNG'
echo "$_png"
@@ -3628,8 +3635,8 @@ EOF
cc_check $THEORADEC_CFLAGS $THEORADEC_LIBS -ltheoradec && _theoradec=yes
fi
if test "$_theoradec" = yes ; then
- LIBS="$LIBS $THEORADEC_LIBS -ltheoradec"
- INCLUDES="$INCLUDES $THEORADEC_CFLAGS"
+ append_var LIBS "$THEORADEC_LIBS -ltheoradec"
+ append_var INCLUDES "$THEORADEC_CFLAGS"
fi
define_in_config_if_yes "$_theoradec" 'USE_THEORADEC'
if test ! "$_theoradec" = notsupported ; then
@@ -3649,8 +3656,8 @@ EOF
cc_check $FAAD_CFLAGS $FAAD_LIBS -lfaad && _faad=yes
fi
if test "$_faad" = yes ; then
- LIBS="$LIBS $FAAD_LIBS -lfaad"
- INCLUDES="$INCLUDES $FAAD_CFLAGS"
+ append_var LIBS "$FAAD_LIBS -lfaad"
+ append_var INCLUDES "$FAAD_CFLAGS"
fi
define_in_config_if_yes "$_faad" 'USE_FAAD'
echo "$_faad"
@@ -3681,8 +3688,8 @@ EOF
cc_check $SNDIO_CFLAGS $SNDIO_LIBS -lsndio && _sndio=yes
fi
if test "$_sndio" = yes ; then
- LIBS="$LIBS $SNDIO_LIBS -lsndio"
- INCLUDES="$INCLUDES $SNDIO_CFLAGS"
+ append_var LIBS "$SNDIO_LIBS -lsndio"
+ append_var INCLUDES "$SNDIO_CFLAGS"
fi
define_in_config_h_if_yes "$_sndio" 'USE_SNDIO'
echo "$_sndio"
@@ -3714,8 +3721,8 @@ EOF
cc_check $ZLIB_CFLAGS $ZLIB_LIBS -lz && _zlib=yes
fi
if test "$_zlib" = yes ; then
- LIBS="$LIBS $ZLIB_LIBS -lz"
- INCLUDES="$INCLUDES $ZLIB_CFLAGS"
+ append_var LIBS "$ZLIB_LIBS -lz"
+ append_var INCLUDES "$ZLIB_CFLAGS"
fi
define_in_config_if_yes "$_zlib" 'USE_ZLIB'
echo "$_zlib"
@@ -3760,8 +3767,8 @@ EOF
fi
fi
if test "$_mpeg2" = yes ; then
- INCLUDES="$INCLUDES $MPEG2_CFLAGS"
- LIBS="$LIBS $MPEG2_LIBS -lmpeg2"
+ append_var INCLUDES "$MPEG2_CFLAGS"
+ append_var LIBS "$MPEG2_LIBS -lmpeg2"
fi
define_in_config_if_yes "$_mpeg2" 'USE_MPEG2'
echo "$_mpeg2"
@@ -3783,8 +3790,8 @@ EOF
cc_check $SPARKLE_CFLAGS $SPARKLE_LIBS -framework Sparkle -ObjC++ -lobjc && _sparkle=yes
fi
if test "$_sparkle" = yes ; then
- LIBS="$LIBS $SPARKLE_LIBS -framework Sparkle"
- INCLUDES="$INCLUDES $SPARKLE_CFLAGS"
+ append_var LIBS "$SPARKLE_LIBS -framework Sparkle"
+ append_var INCLUDES "$SPARKLE_CFLAGS"
fi
define_in_config_if_yes "$_sparkle" 'USE_SPARKLE'
fi
@@ -3805,13 +3812,13 @@ fi
if test "$_fluidsynth" = yes ; then
case $_host_os in
mingw*)
- LIBS="$LIBS $FLUIDSYNTH_LIBS -lfluidsynth -ldsound -lwinmm"
+ append_var LIBS "$FLUIDSYNTH_LIBS -lfluidsynth -ldsound -lwinmm"
;;
*)
- LIBS="$LIBS $FLUIDSYNTH_LIBS -lfluidsynth"
+ append_var LIBS "$FLUIDSYNTH_LIBS -lfluidsynth"
;;
esac
- INCLUDES="$INCLUDES $FLUIDSYNTH_CFLAGS"
+ append_var INCLUDES "$FLUIDSYNTH_CFLAGS"
fi
define_in_config_if_yes "$_fluidsynth" 'USE_FLUIDSYNTH'
echo "$_fluidsynth"
@@ -3847,8 +3854,8 @@ else
fi
if test "$_readline" = yes ; then
- LIBS="$LIBS $READLINE_LIBS $_READLINE_LIBS"
- INCLUDES="$INCLUDES $READLINE_CFLAGS"
+ append_var LIBS "$READLINE_LIBS $_READLINE_LIBS"
+ append_var INCLUDES "$READLINE_CFLAGS"
#
# Check the type of rl_completion_entry_function.
@@ -3907,8 +3914,8 @@ if test "$_libunity" = yes ; then
LIBUNITY_LIBS="$LIBUNITY_LIBS `pkg-config --libs 'unity > 3.8.1' 2>> "$TMPLOG"`"
LIBUNITY_CFLAGS="$LIBUNITY_CFLAGS `pkg-config --cflags 'unity > 3.8.1' 2>> "$TMPLOG"`"
fi
- LIBS="$LIBS $LIBUNITY_LIBS"
- INCLUDES="$INCLUDES $LIBUNITY_CFLAGS"
+ append_var LIBS "$LIBUNITY_LIBS"
+ append_var INCLUDES "$LIBUNITY_CFLAGS"
fi
define_in_config_h_if_yes "$_libunity" 'USE_UNITY'
fi
@@ -3946,8 +3953,8 @@ EOF
fi
if test "$_freetype2" = "yes"; then
- LIBS="$LIBS $FREETYPE2_LIBS"
- INCLUDES="$INCLUDES $FREETYPE2_CFLAGS"
+ append_var LIBS "$FREETYPE2_LIBS"
+ append_var INCLUDES "$FREETYPE2_CFLAGS"
fi
fi
@@ -3971,8 +3978,8 @@ case $_backend in
_opengles=yes
OPENGL_LIBS="-lGLES_CM -lEGL -lX11"
OPENGL_CFLAGS="$OPENGL_LIBS"
- LIBS="$LIBS $OPENGL_LIBS"
- INCLUDES="$INCLUDES $OPENGL_CFLAGS"
+ append_var LIBS "$OPENGL_LIBS"
+ append_var INCLUDES "$OPENGL_CFLAGS"
fi
;;
esac
@@ -4044,8 +4051,8 @@ EOF
cc_check_clean
if test "$_opengl" = yes ; then
- LIBS="$LIBS $OPENGL_LIBS"
- INCLUDES="$INCLUDES $OPENGL_CFLAGS"
+ append_var LIBS "$OPENGL_LIBS"
+ append_var INCLUDES "$OPENGL_CFLAGS"
fi
fi
@@ -4106,16 +4113,16 @@ if test "$_have_x86" = yes ; then
else
case $_host_os in
darwin*)
- NASMFLAGS="$NASMFLAGS -f macho"
+ append_var NASMFLAGS "-f macho"
;;
mingw*)
- NASMFLAGS="$NASMFLAGS -f win32"
+ append_var NASMFLAGS "-f win32"
;;
os2-emx*)
- NASMFLAGS="$NASMFLAGS -f aout"
+ append_var NASMFLAGS "-f aout"
;;
*)
- NASMFLAGS="$NASMFLAGS -f elf"
+ append_var NASMFLAGS "-f elf"
;;
esac
_nasm=yes
@@ -4177,7 +4184,7 @@ if test "$_taskbar" = "no"; then
else
case $_host_os in
mingw*)
- LIBS="$LIBS -lole32 -luuid"
+ append_var LIBS "-lole32 -luuid"
echo "win32"
_taskbar=yes
;;
@@ -4231,26 +4238,26 @@ case $_host_os in
# Windows stores all the external data files in executable file.
;;
*)
- DEFINES="$DEFINES -DDATA_PATH=\\\"$datadir\\\""
+ append_var DEFINES "-DDATA_PATH=\\\"$datadir\\\""
;;
esac
case $_backend in
openpandora)
# Add ../plugins as a path so plugins can be found when running from a .PND.
- DEFINES="$DEFINES -DPLUGIN_DIRECTORY=\\\"../plugins\\\""
+ append_var DEFINES "-DPLUGIN_DIRECTORY=\\\"../plugins\\\""
;;
maemo | webos)
# The WebOS and Maemo apps want the plugins in the "lib" directory
# without a scummvm sub directory.
- DEFINES="$DEFINES -DPLUGIN_DIRECTORY=\\\"$libdir\\\""
+ append_var DEFINES "-DPLUGIN_DIRECTORY=\\\"$libdir\\\""
;;
ps2)
# PS2 bogus dir: it actually depends on launch medium
- DEFINES="$DEFINES -DPLUGIN_DIRECTORY=\\\"host:plugins\\\""
+ append_var DEFINES "-DPLUGIN_DIRECTORY=\\\"host:plugins\\\""
;;
*)
- DEFINES="$DEFINES -DPLUGIN_DIRECTORY=\\\"$libdir/scummvm\\\""
+ append_var DEFINES "-DPLUGIN_DIRECTORY=\\\"$libdir/scummvm\\\""
;;
esac
@@ -4259,9 +4266,9 @@ esac
# We need to do it here to prevent mess-ups with the tests e.g. on the PSP
#
if test "$_enable_prof" = yes ; then
- CXXFLAGS="$CXXFLAGS -pg"
- LDFLAGS="$LDFLAGS -pg"
- DEFINES="$DEFINES -DENABLE_PROFILING"
+ append_var CXXFLAGS "-pg"
+ append_var LDFLAGS "-pg"
+ append_var DEFINES "-DENABLE_PROFILING"
fi
echo_n "Backend... "
@@ -4321,9 +4328,9 @@ case $_backend in
android)
# ssp at this point so the cxxtests link
if test "$_debug_build" = yes; then
- CXXFLAGS="$CXXFLAGS -fstack-protector"
+ append_var CXXFLAGS "-fstack-protector"
else
- CXXFLAGS="$CXXFLAGS -fno-stack-protector"
+ append_var CXXFLAGS "-fno-stack-protector"
fi
static_libs=''
@@ -4347,7 +4354,7 @@ case $_backend in
n64)
# Move some libs down here, otherwise some symbols requires by libvorbis aren't found
# during linking stage
- LIBS="$LIBS -lc -lgcc -lnosys"
+ append_var LIBS "-lc -lgcc -lnosys"
;;
esac
diff --git a/devtools/create_project/create_project.cpp b/devtools/create_project/create_project.cpp
index 34d30e1d69..e4cb67134a 100644
--- a/devtools/create_project/create_project.cpp
+++ b/devtools/create_project/create_project.cpp
@@ -20,7 +20,7 @@
*
*/
-//#define ENABLE_XCODE
+#define ENABLE_XCODE
// HACK to allow building with the SDL backend on MinGW
// see bug #1800764 "TOOLS: MinGW tools building broken"
@@ -336,7 +336,12 @@ int main(int argc, char *argv[]) {
setup.defines.splice(setup.defines.begin(), featureDefines);
// Windows only has support for the SDL backend, so we hardcode it here (along with winmm)
- setup.defines.push_back("WIN32");
+ if (projectType != kProjectXcode) {
+ 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.
+ }
setup.defines.push_back("SDL_BACKEND");
if (!useSDL2) {
cout << "\nLinking to SDL 1.2\n\n";
@@ -410,7 +415,6 @@ int main(int argc, char *argv[]) {
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-rtti");
globalWarnings.push_back("-fno-exceptions");
globalWarnings.push_back("-fcheck-new");
@@ -572,7 +576,7 @@ int main(int argc, char *argv[]) {
globalWarnings.push_back("-fno-exceptions");
globalWarnings.push_back("-fcheck-new");
- provider = new CreateProjectTool::XCodeProvider(globalWarnings, projectWarnings);
+ provider = new CreateProjectTool::XcodeProvider(globalWarnings, projectWarnings);
break;
}
@@ -1039,7 +1043,7 @@ bool producesObjectFile(const std::string &fileName) {
std::string n, ext;
splitFilename(fileName, n, ext);
- if (ext == "cpp" || ext == "c" || ext == "asm")
+ if (ext == "cpp" || ext == "c" || ext == "asm" || ext == "m" || ext == "mm")
return true;
else
return false;
@@ -1279,8 +1283,9 @@ void ProjectProvider::createProject(BuildSetup &setup) {
for (UUIDMap::const_iterator i = _uuidMap.begin(); i != _uuidMap.end(); ++i) {
if (i->first == setup.projectName)
continue;
-
+ // Retain the files between engines if we're creating a single project
in.clear(); ex.clear();
+
const std::string moduleDir = setup.srcDir + targetFolder + i->first;
createModuleList(moduleDir, setup.defines, setup.testDirs, in, ex);
@@ -1290,7 +1295,6 @@ void ProjectProvider::createProject(BuildSetup &setup) {
if (setup.tests) {
// Create the main project file.
in.clear(); ex.clear();
-
createModuleList(setup.srcDir + "/backends", setup.defines, setup.testDirs, in, ex);
createModuleList(setup.srcDir + "/backends/platform/sdl", setup.defines, setup.testDirs, in, ex);
createModuleList(setup.srcDir + "/base", setup.defines, setup.testDirs, in, ex);
@@ -1305,7 +1309,6 @@ void ProjectProvider::createProject(BuildSetup &setup) {
} else if (!setup.devTools) {
// Last but not least create the main project file.
in.clear(); ex.clear();
-
// File list for the Project file
createModuleList(setup.srcDir + "/backends", setup.defines, setup.testDirs, in, ex);
createModuleList(setup.srcDir + "/backends/platform/sdl", setup.defines, setup.testDirs, in, ex);
diff --git a/devtools/create_project/xcode.cpp b/devtools/create_project/xcode.cpp
index d95bf3e9ee..babd530ad7 100644
--- a/devtools/create_project/xcode.cpp
+++ b/devtools/create_project/xcode.cpp
@@ -30,6 +30,14 @@ 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);
@@ -54,39 +62,172 @@ namespace CreateProjectTool {
#define REMOVE_SETTING(config, key) \
config.settings.erase(key);
-#define ADD_BUILD_FILE(id, name, comment) { \
+#define ADD_BUILD_FILE(id, name, fileRefId, comment) { \
Object *buildFile = new Object(this, id, name, "PBXBuildFile", "PBXBuildFile", comment); \
- buildFile->addProperty("fileRef", getHash(name), name, SettingsNoValue); \
+ buildFile->addProperty("fileRef", fileRefId, name, SettingsNoValue); \
_buildFile.add(buildFile); \
_buildFile.flags = SettingsSingleItem; \
}
-#define ADD_FILE_REFERENCE(name, properties) { \
- Object *fileRef = new Object(this, name, name, "PBXFileReference", "PBXFileReference", name); \
+#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); \
- if (!properties.fileName.empty()) fileRef->addProperty("name", properties.fileName, "", SettingsNoValue); \
- if (!properties.filePath.empty()) fileRef->addProperty("path", properties.filePath, "", 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); \
_fileReference.add(fileRef); \
_fileReference.flags = SettingsSingleItem; \
}
-XCodeProvider::XCodeProvider(StringList &global_warnings, std::map<std::string, StringList> &project_warnings, const int version)
+bool producesObjectFileOnOSX(const std::string &fileName) {
+ std::string n, ext;
+ splitFilename(fileName, n, ext);
+
+ // Note that the difference between this and the general producesObjectFile is that
+ // this one adds Objective-C(++), and removes asm-support.
+ if (ext == "cpp" || ext == "c" || ext == "m" || ext == "mm")
+ return true;
+ else
+ 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);
+
+ if (path != "") {
+ addProperty("path", path, "", SettingsNoValue|SettingsQuoteVariable);
+ }
+ _childOrder = 0;
+ _treeName = uniqueName;
+}
+
+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);
+ _childGroups[name] = child;
+ addChildGroup(child);
+ parent->_groups.add(child);
+ }
+}
+
+void XcodeProvider::Group::addChildInternal(const std::string &id, const std::string &comment) {
+ if (properties.find("children") == properties.end()) {
+ Property children;
+ children.hasOrder = true;
+ children.flags = SettingsAsList;
+ properties["children"] = children;
+ }
+ properties["children"].settings[id] = Setting("", comment + " in Sources", SettingsNoValue, 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;
+ } else {
+ properties["children"].flags ^= SettingsSingleItem;
+ }
+
+}
+
+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);
+ FileProperty property = FileProperty(name, name, name, "\"<group>\"");
+
+ parent->addFileReference(id, name, property);
+ if (producesObjectFileOnOSX(name)) {
+ parent->addBuildFile(_treeName + "/" + name, name, parent->getHash(id), name + " in Sources");
+ }
+}
+
+void XcodeProvider::Group::addChildByHash(const std::string &hash, const std::string &name) {
+ addChildInternal(hash, name);
+}
+
+XcodeProvider::Group *XcodeProvider::Group::getChildGroup(const std::string &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);
+ _rootSourceGroup = new Group(this, "Sources", path, path);
+ _groups.add(_rootSourceGroup);
+ return _rootSourceGroup;
+ } else {
+ assert(path.find(_projectRoot) == 0);
+ std::string subPath = path.substr(_projectRoot.size() + 1);
+ Group *currentGroup = _rootSourceGroup;
+ size_t firstPathComponent = subPath.find_first_of('/');
+ // We assume here that all paths have trailing '/', otherwise this breaks.
+ while (firstPathComponent != std::string::npos) {
+ currentGroup->ensureChildExists(subPath.substr(0, firstPathComponent));
+ currentGroup = currentGroup->getChildGroup(subPath.substr(0, firstPathComponent));
+ subPath = subPath.substr(firstPathComponent + 1);
+ firstPathComponent = subPath.find_first_of('/');
+ }
+ return currentGroup;
+ }
+}
+
+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);
+ _fileReference.add(fileRef);
+ _fileReference.flags = SettingsSingleItem;
+}
+
+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);
+ _fileReference.add(fileRef);
+ _fileReference.flags = SettingsSingleItem;
+}
+
+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.add(buildFile);
+ _buildFile.flags = SettingsSingleItem;
+}
+
+XcodeProvider::XcodeProvider(StringList &global_warnings, std::map<std::string, StringList> &project_warnings, const int version)
: ProjectProvider(global_warnings, project_warnings, version) {
+ _rootSourceGroup = NULL;
}
-void XCodeProvider::createWorkspace(const BuildSetup &setup) {
+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 "-OS X");
+#ifdef ENABLE_IOS
_targets.push_back(PROJECT_DESCRIPTION "-Simulator");
-
+#endif
setupCopyFilesBuildPhase();
setupFrameworksBuildPhase();
setupNativeTarget();
@@ -97,7 +238,7 @@ void XCodeProvider::createWorkspace(const BuildSetup &setup) {
// We are done with constructing all the object graph and we got through every project, output the main project file
// (this is kind of a hack since other providers use separate project files)
-void XCodeProvider::createOtherBuildFiles(const BuildSetup &setup) {
+void XcodeProvider::createOtherBuildFiles(const BuildSetup &setup) {
// This needs to be done at the end when all build files have been accounted for
setupSourcesBuildPhase();
@@ -105,7 +246,7 @@ void XCodeProvider::createOtherBuildFiles(const BuildSetup &setup) {
}
// Store information about a project here, for use at the end
-void XCodeProvider::createProjectFile(const std::string &, const std::string &, const BuildSetup &setup, const std::string &moduleDir,
+void XcodeProvider::createProjectFile(const std::string &, const std::string &, const BuildSetup &setup, const std::string &moduleDir,
const StringList &includeList, const StringList &excludeList) {
std::string modulePath;
if (!moduleDir.compare(0, setup.srcDir.size(), setup.srcDir)) {
@@ -124,7 +265,7 @@ void XCodeProvider::createProjectFile(const std::string &, const std::string &,
//////////////////////////////////////////////////////////////////////////
// Main Project file
//////////////////////////////////////////////////////////////////////////
-void XCodeProvider::ouputMainProjectFile(const BuildSetup &setup) {
+void XcodeProvider::ouputMainProjectFile(const BuildSetup &setup) {
std::ofstream project((setup.outputDir + '/' + PROJECT_NAME ".xcodeproj" + '/' + "project.pbxproj").c_str());
if (!project)
error("Could not open \"" + setup.outputDir + '/' + PROJECT_NAME ".xcodeproj" + '/' + "project.pbxproj\" for writing");
@@ -164,92 +305,93 @@ void XCodeProvider::ouputMainProjectFile(const BuildSetup &setup) {
//////////////////////////////////////////////////////////////////////////
// Files
//////////////////////////////////////////////////////////////////////////
-void XCodeProvider::writeFileListToProject(const FileNode &dir, std::ofstream &projectFile, const int indentation,
+void XcodeProvider::writeFileListToProject(const FileNode &dir, std::ofstream &projectFile, const int indentation,
const StringList &duplicate, const std::string &objPrefix, const std::string &filePrefix) {
- // Add comments for shared lists
- _buildFile.comment = "PBXBuildFile";
- _fileReference.comment = "PBXFileReference";
-
- // Init root group
- _groups.comment = "PBXGroup";
-
- // Create group
- std::string name = getLastPathComponent(dir.name);
- Object *group = new Object(this, "PBXGroup_" + name , "PBXGroup", "PBXGroup", "", name);
-
- // List of children
- Property children;
- children.hasOrder = true;
- children.flags = SettingsAsList;
-
- group->addProperty("name", name, "", SettingsNoValue|SettingsQuoteVariable);
- group->addProperty("sourceTree", "<group>", "", SettingsNoValue|SettingsQuoteVariable);
-
- int order = 0;
+ // Ensure that top-level groups are generated for i.e. engines/
+ Group *group = touchGroupsForPath(filePrefix);
for (FileNode::NodeList::const_iterator i = dir.children.begin(); i != dir.children.end(); ++i) {
const FileNode *node = *i;
- std::string id = "FileReference_" + node->name;
- FileProperty property = FileProperty(node->name, node->name, node->name, "<group>");
-
- ADD_SETTING_ORDER_NOVALUE(children, getHash(id), node->name, order++);
- ADD_BUILD_FILE(id, node->name, node->name + " in Sources");
- ADD_FILE_REFERENCE(node->name, property);
-
+ // Iff it is a file, then add (build) file references. Since we're using Groups and not File References
+ // for folders, we shouldn't add folders as file references, obviously.
+ if (node->children.empty()) {
+ group->addChildFile(node->name);
+ }
// Process child nodes
if (!node->children.empty())
writeFileListToProject(*node, projectFile, indentation + 1, duplicate, objPrefix + node->name + '_', filePrefix + node->name + '/');
}
-
- group->properties["children"] = children;
-
- _groups.add(group);
}
//////////////////////////////////////////////////////////////////////////
// Setup functions
//////////////////////////////////////////////////////////////////////////
-void XCodeProvider::setupCopyFilesBuildPhase() {
+void XcodeProvider::setupCopyFilesBuildPhase() {
// Nothing to do here
}
+#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>\""); \
+ ADD_SETTING_ORDER_NOVALUE(children, getHash(lib".a"), lib".a", fwOrder++);
+
/**
* Sets up the frameworks build phase.
*
* (each native target has different build rules)
*/
-void XCodeProvider::setupFrameworksBuildPhase() {
+void XcodeProvider::setupFrameworksBuildPhase() {
_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;
+
// Setup framework file properties
std::map<std::string, FileProperty> properties;
-
+ int fwOrder = 0;
// Frameworks
- properties["ApplicationServices.framework"] = FileProperty("wrapper.framework", "ApplicationServices.framework", "System/Library/Frameworks/ApplicationServices.framework", "SDKROOT");
- properties["AudioToolbox.framework"] = FileProperty("wrapper.framework", "AudioToolbox.framework", "System/Library/Frameworks/AudioToolbox.framework", "SDKROOT");
- properties["AudioUnit.framework"] = FileProperty("wrapper.framework", "AudioUnit.framework", "System/Library/Frameworks/AudioUnit.framework", "SDKROOT");
- properties["Carbon.framework"] = FileProperty("wrapper.framework", "Carbon.framework", "System/Library/Frameworks/Carbon.framework", "SDKROOT");
- properties["Cocoa.framework"] = FileProperty("wrapper.framework", "Cocoa.framework", "System/Library/Frameworks/Cocoa.framework", "SDKROOT");
- properties["CoreAudio.framework"] = FileProperty("wrapper.framework", "CoreAudio.framework", "System/Library/Frameworks/CoreAudio.framework", "SDKROOT");
- properties["CoreFoundation.framework"] = FileProperty("wrapper.framework", "CoreFoundation.framework", "System/Library/Frameworks/CoreFoundation.framework", "SDKROOT");
- properties["CoreMIDI.framework"] = FileProperty("wrapper.framework", "CoreMIDI.framework", "System/Library/Frameworks/CoreMIDI.framework", "SDKROOT");
- properties["Foundation.framework"] = FileProperty("wrapper.framework", "Foundation.framework", "System/Library/Frameworks/Foundation.framework", "SDKROOT");
- properties["IOKit.framework"] = FileProperty("wrapper.framework", "IOKit.framework", "System/Library/Frameworks/IOKit.framework", "SDKROOT");
- properties["OpenGLES.framework"] = FileProperty("wrapper.framework", "OpenGLES.framework", "System/Library/Frameworks/OpenGLES.framework", "SDKROOT");
- properties["QuartzCore.framework"] = FileProperty("wrapper.framework", "QuartzCore.framework", "System/Library/Frameworks/QuartzCore.framework", "SDKROOT");
- properties["QuickTime.framework"] = FileProperty("wrapper.framework", "QuickTime.framework", "System/Library/Frameworks/QuickTime.framework", "SDKROOT");
- properties["UIKit.framework"] = FileProperty("wrapper.framework", "UIKit.framework", "System/Library/Frameworks/UIKit.framework", "SDKROOT");
+ DEF_SYSFRAMEWORK("ApplicationServices");
+ DEF_SYSFRAMEWORK("AudioToolbox");
+ DEF_SYSFRAMEWORK("AudioUnit");
+ DEF_SYSFRAMEWORK("Carbon");
+ DEF_SYSFRAMEWORK("Cocoa");
+ DEF_SYSFRAMEWORK("CoreAudio");
+ DEF_SYSFRAMEWORK("CoreFoundation");
+ DEF_SYSFRAMEWORK("CoreMIDI");
+ DEF_SYSFRAMEWORK("Foundation");
+ DEF_SYSFRAMEWORK("IOKit");
+ DEF_SYSFRAMEWORK("OpenGLES");
+ DEF_SYSFRAMEWORK("QuartzCore");
+ DEF_SYSFRAMEWORK("QuickTime");
+ DEF_SYSFRAMEWORK("UIKit");
+ // Optionals:
+ DEF_SYSFRAMEWORK("OpenGL");
// Local libraries
- properties["libFLAC.a"] = FileProperty("archive.ar", "libFLAC.a", "lib/libFLAC.a", "\"<group>\"");
- properties["libmad.a"] = FileProperty("archive.ar", "libmad.a", "lib/libmad.a", "\"<group>\"");
- //properties["libmpeg2.a"] = FileProperty("archive.ar", "libmpeg2.a", "lib/libmpeg2.a", "\"<group>\"");
- properties["libvorbisidec.a"] = FileProperty("archive.ar", "libvorbisidec.a", "lib/libvorbisidec.a", "\"<group>\"");
+ DEF_LOCALLIB_STATIC("libFLAC");
+ DEF_LOCALLIB_STATIC("libmad");
+ DEF_LOCALLIB_STATIC("libvorbisidec");
+ DEF_LOCALLIB_STATIC("libfreetype");
+// DEF_LOCALLIB_STATIC("libmpeg2");
+
+ 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
+ int order = 0;
+#ifdef ENABLE_IOS
//////////////////////////////////////////////////////////////////////////
// iPhone
- Object *framework_iPhone = new Object(this, "PBXFrameworksBuildPhase_" + _targets[0], "PBXFrameworksBuildPhase", "PBXFrameworksBuildPhase", "", "Frameworks");
+ 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);
@@ -272,23 +414,22 @@ void XCodeProvider::setupFrameworksBuildPhase() {
frameworks_iPhone.push_back("libvorbisidec.a");
frameworks_iPhone.push_back("OpenGLES.framework");
- int order = 0;
for (ValueList::iterator framework = frameworks_iPhone.begin(); framework != frameworks_iPhone.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_BUILD_FILE(id, *framework, comment);
- ADD_FILE_REFERENCE(*framework, properties[*framework]);
+ ADD_BUILD_FILE(id, *framework, getHash(*framework), comment);
+ ADD_FILE_REFERENCE(*framework, *framework, properties[*framework]);
}
framework_iPhone->properties["files"] = iPhone_files;
_frameworksBuildPhase.add(framework_iPhone);
-
+#endif
//////////////////////////////////////////////////////////////////////////
// ScummVM-OS X
- Object *framework_OSX = new Object(this, "PBXFrameworksBuildPhase_" + _targets[1], "PBXFrameworksBuildPhase", "PBXFrameworksBuildPhase", "", "Frameworks");
+ 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);
@@ -311,6 +452,8 @@ 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++) {
@@ -318,17 +461,17 @@ void XCodeProvider::setupFrameworksBuildPhase() {
std::string comment = *framework + " in Frameworks";
ADD_SETTING_ORDER_NOVALUE(osx_files, getHash(id), comment, order++);
- ADD_BUILD_FILE(id, *framework, comment);
- ADD_FILE_REFERENCE(*framework, properties[*framework]);
+ ADD_BUILD_FILE(id, *framework, getHash(*framework), comment);
+ ADD_FILE_REFERENCE(*framework, *framework, properties[*framework]);
}
framework_OSX->properties["files"] = osx_files;
_frameworksBuildPhase.add(framework_OSX);
-
+#ifdef ENABLE_IOS
//////////////////////////////////////////////////////////////////////////
// Simulator
- Object *framework_simulator = new Object(this, "PBXFrameworksBuildPhase_" + _targets[2], "PBXFrameworksBuildPhase", "PBXFrameworksBuildPhase", "", "Frameworks");
+ 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);
@@ -353,20 +496,28 @@ void XCodeProvider::setupFrameworksBuildPhase() {
std::string comment = *framework + " in Frameworks";
ADD_SETTING_ORDER_NOVALUE(simulator_files, getHash(id), comment, order++);
- ADD_BUILD_FILE(id, *framework, comment);
- ADD_FILE_REFERENCE(*framework, properties[*framework]);
+ 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() {
+void XcodeProvider::setupNativeTarget() {
_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);
@@ -385,14 +536,18 @@ void XCodeProvider::setupNativeTarget() {
target->addProperty("name", _targets[i], "", SettingsNoValue|SettingsQuoteVariable);
target->addProperty("productName", PROJECT_NAME, "", SettingsNoValue);
+ 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);
_nativeTarget.add(target);
}
+ _rootSourceGroup->addChildGroup(productsGroup);
+ _groups.add(productsGroup);
}
-void XCodeProvider::setupProject() {
+void XcodeProvider::setupProject() {
_project.comment = "PBXProject";
Object *project = new Object(this, "PBXProject", "PBXProject", "PBXProject", "", "Project object");
@@ -411,22 +566,30 @@ void XCodeProvider::setupProject() {
ADD_SETTING_ORDER_NOVALUE(regions, "German", "", 3);
project->properties["knownRegions"] = regions;
- project->addProperty("mainGroup", getHash("PBXGroup_CustomTemplate"), "CustomTemplate", SettingsNoValue);
- project->addProperty("projectDirPath", "", "", SettingsNoValue|SettingsQuoteVariable);
+ project->addProperty("mainGroup", _rootSourceGroup->getHashRef(), "CustomTemplate", SettingsNoValue);
+ project->addProperty("projectDirPath", _projectRoot, "", SettingsNoValue|SettingsQuoteVariable);
project->addProperty("projectRoot", "", "", SettingsNoValue|SettingsQuoteVariable);
// List of targets
Property targets;
targets.flags = SettingsAsList;
- targets.settings[getHash("PBXNativeTarget_" + _targets[0])] = Setting("", _targets[0], SettingsNoValue, 0, 0);
- targets.settings[getHash("PBXNativeTarget_" + _targets[1])] = Setting("", _targets[1], SettingsNoValue, 0, 1);
- targets.settings[getHash("PBXNativeTarget_" + _targets[2])] = Setting("", _targets[2], SettingsNoValue, 0, 2);
+#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
+ // Force list even when there is only a single target
+ project->properties["targets"].flags |= SettingsSingleItem;
+#endif
_project.add(project);
}
-void XCodeProvider::setupResourcesBuildPhase() {
+void XcodeProvider::setupResourcesBuildPhase() {
_resourcesBuildPhase.comment = "PBXResourcesBuildPhase";
// Setup resource file properties
@@ -483,7 +646,7 @@ void XCodeProvider::setupResourcesBuildPhase() {
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, properties[*file]);
+ ADD_FILE_REFERENCE(*file, *file, properties[*file]);
}
// Add custom files depending on the target
@@ -503,12 +666,41 @@ void XCodeProvider::setupResourcesBuildPhase() {
}
}
-void XCodeProvider::setupSourcesBuildPhase() {
- // TODO
+void XcodeProvider::setupSourcesBuildPhase() {
+ _sourcesBuildPhase.comment = "PBXSourcesBuildPhase";
+
+ // Setup source file properties
+ std::map<std::string, FileProperty> properties;
+
+ // Same as for containers: a rule for each native target
+ for (unsigned int i = 0; i < _targets.size(); i++) {
+ Object *source = new Object(this, "PBXSourcesBuildPhase_" + _targets[i], "PBXSourcesBuildPhase", "PBXSourcesBuildPhase", "", "Sources");
+
+ source->addProperty("buildActionMask", "2147483647", "", SettingsNoValue);
+
+ Property files;
+ files.hasOrder = true;
+ files.flags = SettingsAsList;
+
+ int order = 0;
+ for (std::vector<Object*>::iterator file = _buildFile.objects.begin(); file !=_buildFile.objects.end(); ++file) {
+ if (!producesObjectFileOnOSX((*file)->name)) {
+ continue;
+ }
+ std::string comment = (*file)->name + " in Sources";
+ ADD_SETTING_ORDER_NOVALUE(files, getHash((*file)->id), comment, order++);
+ }
+
+ source->properties["files"] = files;
+
+ source->addProperty("runOnlyForDeploymentPostprocessing", "0", "", SettingsNoValue);
+
+ _sourcesBuildPhase.add(source);
+ }
}
// Setup all build configurations
-void XCodeProvider::setupBuildConfiguration() {
+void XcodeProvider::setupBuildConfiguration() {
_buildConfiguration.comment = "XCBuildConfiguration";
_buildConfiguration.flags = SettingsAsList;
@@ -516,9 +708,9 @@ void XCodeProvider::setupBuildConfiguration() {
///****************************************
// * iPhone
// ****************************************/
-
+#ifdef ENABLE_IOS
// Debug
- Object *iPhone_Debug_Object = new Object(this, "XCBuildConfiguration_" PROJECT_DESCRIPTION "-iPhone_Debug", _targets[0] /* ScummVM-iPhone */, "XCBuildConfiguration", "PBXNativeTarget", "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");
@@ -539,10 +731,10 @@ void XCodeProvider::setupBuildConfiguration() {
ADD_SETTING(iPhone_Debug, "GCC_THUMB_SUPPORT", "NO");
ADD_SETTING(iPhone_Debug, "GCC_UNROLL_LOOPS", "YES");
ValueList iPhone_HeaderSearchPaths;
- iPhone_HeaderSearchPaths.push_back("../../engines/");
- iPhone_HeaderSearchPaths.push_back("../../");
+ 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|SettingsNoQuote, 5);
+ 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)");
@@ -560,7 +752,7 @@ void XCodeProvider::setupBuildConfiguration() {
iPhone_Debug_Object->properties["buildSettings"] = iPhone_Debug;
// Release
- Object *iPhone_Release_Object = new Object(this, "XCBuildConfiguration_" PROJECT_DESCRIPTION "-iPhone_Release", _targets[0] /* ScummVM-iPhone */, "XCBuildConfiguration", "PBXNativeTarget", "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");
@@ -572,7 +764,7 @@ void XCodeProvider::setupBuildConfiguration() {
_buildConfiguration.add(iPhone_Debug_Object);
_buildConfiguration.add(iPhone_Release_Object);
-
+#endif
/****************************************
* scummvm
****************************************/
@@ -581,13 +773,14 @@ void XCodeProvider::setupBuildConfiguration() {
Object *scummvm_Debug_Object = new Object(this, "XCBuildConfiguration_" PROJECT_NAME "_Debug", PROJECT_NAME, "XCBuildConfiguration", "PBXProject", "Debug");
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", "");
ADD_SETTING(scummvm_Debug, "GCC_C_LANGUAGE_STANDARD", "c99");
ADD_SETTING(scummvm_Debug, "GCC_ENABLE_CPP_EXCEPTIONS", "NO");
- ADD_SETTING(scummvm_Debug, "GCC_ENABLE_CPP_RTTI", "NO");
+ ADD_SETTING(scummvm_Debug, "GCC_ENABLE_CPP_RTTI", "YES");
ADD_SETTING(scummvm_Debug, "GCC_INPUT_FILETYPE", "automatic");
ADD_SETTING(scummvm_Debug, "GCC_OPTIMIZATION_LEVEL", "0");
ValueList scummvm_defines(_defines);
@@ -601,15 +794,15 @@ void XCodeProvider::setupBuildConfiguration() {
ADD_SETTING(scummvm_Debug, "GCC_WARN_UNUSED_VARIABLE", "YES");
ValueList scummvm_HeaderPaths;
scummvm_HeaderPaths.push_back("include/");
- scummvm_HeaderPaths.push_back("../../engines/");
- scummvm_HeaderPaths.push_back("../../");
- ADD_SETTING_LIST(scummvm_Debug, "HEADER_SEARCH_PATHS", scummvm_HeaderPaths, SettingsNoQuote|SettingsAsList, 5);
+ 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_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", "macosx10.6");
+ ADD_SETTING(scummvm_Debug, "SDKROOT", "macosx");
scummvm_Debug_Object->addProperty("name", "Debug", "", SettingsNoValue);
scummvm_Debug_Object->properties["buildSettings"] = scummvm_Debug;
@@ -633,7 +826,7 @@ void XCodeProvider::setupBuildConfiguration() {
****************************************/
// Debug
- Object *scummvmOSX_Debug_Object = new Object(this, "XCBuildConfiguration_" PROJECT_DESCRIPTION "-OSX_Debug", _targets[1] /* ScummVM-OS X */, "XCBuildConfiguration", "PBXNativeTarget", "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, "COMPRESS_PNG_FILES", "NO");
@@ -642,7 +835,7 @@ void XCodeProvider::setupBuildConfiguration() {
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");
- ADD_SETTING(scummvmOSX_Debug, "GCC_ENABLE_CPP_RTTI", "NO");
+ ADD_SETTING(scummvmOSX_Debug, "GCC_ENABLE_CPP_RTTI", "YES");
ADD_SETTING(scummvmOSX_Debug, "GCC_DYNAMIC_NO_PIC", "NO");
ADD_SETTING(scummvmOSX_Debug, "GCC_ENABLE_FIX_AND_CONTINUE", "NO");
ADD_SETTING(scummvmOSX_Debug, "GCC_OPTIMIZATION_LEVEL", "0");
@@ -656,11 +849,12 @@ void XCodeProvider::setupBuildConfiguration() {
ValueList scummvmOSX_HeaderPaths;
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("../../engines/");
- scummvmOSX_HeaderPaths.push_back("../../");
- ADD_SETTING_LIST(scummvmOSX_Debug, "HEADER_SEARCH_PATHS", scummvmOSX_HeaderPaths, SettingsNoQuote|SettingsAsList, 5);
- ADD_SETTING_QUOTE(scummvmOSX_Debug, "INFOPLIST_FILE", "$(SRCROOT)/../macosx/Info.plist");
+ 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_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");
@@ -671,6 +865,10 @@ void XCodeProvider::setupBuildConfiguration() {
ValueList scummvmOSX_LdFlags;
scummvmOSX_LdFlags.push_back("-lSDLmain");
scummvmOSX_LdFlags.push_back("-logg");
+ scummvmOSX_LdFlags.push_back("-lpng");
+ scummvmOSX_LdFlags.push_back("-ljpeg");
+ scummvmOSX_LdFlags.push_back("-ltheora");
+ scummvmOSX_LdFlags.push_back("-lfreetype");
scummvmOSX_LdFlags.push_back("-lvorbisfile");
scummvmOSX_LdFlags.push_back("-lvorbis");
scummvmOSX_LdFlags.push_back("-lmad");
@@ -685,7 +883,7 @@ void XCodeProvider::setupBuildConfiguration() {
scummvmOSX_Debug_Object->properties["buildSettings"] = scummvmOSX_Debug;
// Release
- Object *scummvmOSX_Release_Object = new Object(this, "XCBuildConfiguration_" PROJECT_DESCRIPTION "-OSX_Release", _targets[1] /* ScummVM-OS X */, "XCBuildConfiguration", "PBXNativeTarget", "Release");
+ Object *scummvmOSX_Release_Object = new Object(this, "XCBuildConfiguration_" PROJECT_DESCRIPTION "-OSX_Release", _targets[OSX_TARGET] /* ScummVM-OS X */, "XCBuildConfiguration", "PBXNativeTarget", "Release");
Property scummvmOSX_Release(scummvmOSX_Debug);
ADD_SETTING(scummvmOSX_Release, "COPY_PHASE_STRIP", "YES");
REMOVE_SETTING(scummvmOSX_Release, "GCC_DYNAMIC_NO_PIC");
@@ -697,13 +895,13 @@ void XCodeProvider::setupBuildConfiguration() {
_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[2] /* ScummVM-Simulator */, "XCBuildConfiguration", "PBXNativeTarget", "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);
@@ -715,7 +913,7 @@ void XCodeProvider::setupBuildConfiguration() {
scummvmSimulator_Debug_Object->properties["buildSettings"] = scummvmSimulator_Debug;
// Release
- Object *scummvmSimulator_Release_Object = new Object(this, "XCBuildConfiguration_" PROJECT_DESCRIPTION "-Simulator_Release", _targets[2] /* ScummVM-Simulator */, "XCBuildConfiguration", "PBXNativeTarget", "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");
@@ -732,7 +930,7 @@ void XCodeProvider::setupBuildConfiguration() {
// 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++) {
@@ -758,7 +956,7 @@ void XCodeProvider::setupBuildConfiguration() {
//////////////////////////////////////////////////////////////////////////
// Setup global defines
-void XCodeProvider::setupDefines(const BuildSetup &setup) {
+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?)
@@ -772,7 +970,6 @@ void XCodeProvider::setupDefines(const BuildSetup &setup) {
ADD_DEFINE(_defines, "SCUMM_LITTLE_ENDIAN");
ADD_DEFINE(_defines, "UNIX");
ADD_DEFINE(_defines, "SCUMMVM");
- ADD_DEFINE(_defines, "USE_TREMOR");
}
//////////////////////////////////////////////////////////////////////////
@@ -780,7 +977,7 @@ void XCodeProvider::setupDefines(const BuildSetup &setup) {
//////////////////////////////////////////////////////////////////////////
// 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) {
+std::string XcodeProvider::getHash(std::string key) {
#if DEBUG_XCODE_HASH
return key;
@@ -800,7 +997,7 @@ std::string XCodeProvider::getHash(std::string key) {
bool isSeparator (char s) { return (s == '-'); }
-std::string XCodeProvider::newHash() const {
+std::string XcodeProvider::newHash() const {
std::string hash = createUUID();
// Remove { and - from UUID and resize to 96-bits uppercase hex string
@@ -832,7 +1029,7 @@ std::string replace(std::string input, const std::string find, std::string repla
return input;
}
-std::string XCodeProvider::writeProperty(const std::string &variable, Property &prop, int flags) const {
+std::string XcodeProvider::writeProperty(const std::string &variable, Property &prop, int flags) const {
std::string output;
output += (flags & SettingsSingleItem ? "" : "\t\t\t") + variable + " = ";
@@ -847,7 +1044,9 @@ std::string XCodeProvider::writeProperty(const std::string &variable, Property &
output += writeSetting((*setting).first, (*setting).second);
- if ((prop.flags & SettingsAsList) && prop.settings.size() > 1) {
+ // The combination of SettingsAsList, and SettingsSingleItem 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";
} else {
output += ";";
@@ -861,13 +1060,13 @@ std::string XCodeProvider::writeProperty(const std::string &variable, Property &
return output;
}
-std::string XCodeProvider::writeSetting(const std::string &variable, std::string value, std::string comment, int flags, int indent) const {
+std::string XcodeProvider::writeSetting(const std::string &variable, std::string value, std::string comment, int flags, int indent) const {
return writeSetting(variable, Setting(value, comment, flags, indent));
}
// Heavily modified (not in a good way) function, imported from the QMake
// 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 XcodeProvider::writeSetting(const std::string &variable, const Setting &setting) const {
std::string output;
const std::string quote = (setting.flags & SettingsNoQuote) ? "" : "\"";
const std::string escape_quote = quote.empty() ? "" : "\\" + quote;
diff --git a/devtools/create_project/xcode.h b/devtools/create_project/xcode.h
index f86e7c555c..2686d14986 100644
--- a/devtools/create_project/xcode.h
+++ b/devtools/create_project/xcode.h
@@ -30,9 +30,9 @@
namespace CreateProjectTool {
-class XCodeProvider : public ProjectProvider {
+class XcodeProvider : public ProjectProvider {
public:
- XCodeProvider(StringList &global_warnings, std::map<std::string, StringList> &project_warnings, const int version = 0);
+ XcodeProvider(StringList &global_warnings, std::map<std::string, StringList> &project_warnings, const int version = 0);
protected:
@@ -45,7 +45,6 @@ protected:
void writeFileListToProject(const FileNode &dir, std::ofstream &projectFile, const int indentation,
const StringList &duplicate, const std::string &objPrefix, const std::string &filePrefix);
-
private:
enum {
SettingsAsList = 0x01,
@@ -169,7 +168,7 @@ private:
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 = "")
+ 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) {
assert(objectParent);
assert(!objectId.empty());
@@ -210,9 +209,10 @@ private:
return output;
}
+ // Slight hack, to allow Group access to parent.
+ protected:
+ XcodeProvider *parent;
private:
- XCodeProvider *parent;
-
// Returns the type property (should always be the first in the properties map)
std::string getType() {
assert(!properties.empty());
@@ -258,6 +258,36 @@ private:
}
};
+ // A class to maintain a folder-reference group-hierarchy, which together with the functionality below
+ // allows for breaking up sub-paths into a chain of groups. This helps with merging engines into the
+ // overall group-layout.
+ class Group : public Object {
+ int _childOrder;
+ std::map<std::string, Group *> _childGroups;
+ std::string _treeName;
+ void addChildInternal(const std::string &id, const std::string &comment);
+ public:
+ Group(XcodeProvider *objectParent, const std::string &groupName, const std::string &uniqueName, const std::string &path);
+ 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 ensureChildExists(const std::string &name);
+ Group *getChildGroup(const std::string &name);
+ std::string getHashRef() const { return parent->getHash(id); }
+ };
+
+ // The path used by the root-source group
+ std::string _projectRoot;
+ // The base source group, currently also re-purposed for containing the various support-groups.
+ Group *_rootSourceGroup;
+ // Helper function to create the chain of groups for the various subfolders. Necessary as
+ // create_project likes to start in engines/
+ Group *touchGroupsForPath(const std::string &path);
+ // Functionality for adding file-refs and build-files, as Group-objects need to be able to do this.
+ void addFileReference(const std::string &id, const std::string &name, FileProperty properties);
+ void addProductFileReference(const std::string &id, const std::string &name);
+ void addBuildFile(const std::string &id, const std::string &name, const std::string &fileRefId, const std::string &comment);
// All objects
std::map<std::string, std::string> _hashDictionnary;
ValueList _defines;
diff --git a/devtools/credits.pl b/devtools/credits.pl
index f82d0d4212..41c2d4f162 100755
--- a/devtools/credits.pl
+++ b/devtools/credits.pl
@@ -789,7 +789,7 @@ begin_credits("Credits");
add_person("Tobia Tesan", "t0by", "");
end_section();
- begin_section("ZVision");
+ begin_section("Z-Vision");
add_person("Adrian Astley", "RichieSams", "");
add_person("Filippos Karapetis", "[md5]", "");
add_person("Anton Yarcev", "Zidane", "");
@@ -1053,7 +1053,7 @@ begin_credits("Credits");
end_section();
begin_section("German");
add_person("Simon Sawatzki", "SimSaw", "");
- add_person("Lothar Serra Mari", "Lothar93", "(retired)");
+ add_person("Lothar Serra Mari", "rootfather", "");
end_section();
begin_section("Hungarian");
add_person("Alex Bevilacqua", "", "");
@@ -1224,7 +1224,7 @@ begin_credits("Credits");
add_person("Jimmi Th&oslash;gersen", "", "For ScummRev, and much obscure code/documentation");
add_person("", "Tristan", "For additional work on the original MT-32 emulator");
add_person("James Woodcock", "", "Soundtrack enhancements");
- add_person("Anton Yartsev", "Zidane", "For the original re-implementation of the ZVision engine");
+ add_person("Anton Yartsev", "Zidane", "For the original re-implementation of the Z-Vision engine");
end_persons();
add_paragraph(
diff --git a/devtools/scumm-md5.txt b/devtools/scumm-md5.txt
index 305c1724ed..ffde276a3d 100644
--- a/devtools/scumm-md5.txt
+++ b/devtools/scumm-md5.txt
@@ -627,12 +627,12 @@ airport Let's Explore the Airport with Buzzy
86c9902b7bec1a17926d4dae85beaa45 -1 en Windows HE 71 Demo - khalek
farm Let's Explore the Farm with Buzzy
- fbbbb38a81fc9d6a61d509278390a290 -1 en Mac - - - khalek
a5c5388da9bf0e6662fdca8813a79d13 86962 en Windows - - - George Kormendi
- a85856675429fe88051744f755b72f93 -1 en Windows - - - Kirben
- a2386da005672cbd5136f4f27a626c5f 87061 nl Windows - - - George Kormendi
- eeb606c2d2ec877a712a9f20c10bcdda 87034 nl Mac - - - Ben Castricum
- 5dda73606533d66a4c3f4f9ea6e842af 87061 ru Windows - - - sev
+ fbbbb38a81fc9d6a61d509278390a290 -1 en Mac HE 73 - - khalek
+ a85856675429fe88051744f755b72f93 -1 en Windows HE 73 - - Kirben
+ a2386da005672cbd5136f4f27a626c5f 87061 nl Windows HE 73 - - George Kormendi
+ eeb606c2d2ec877a712a9f20c10bcdda 87034 nl Mac HE 73 - - Ben Castricum
+ 5dda73606533d66a4c3f4f9ea6e842af 87061 ru Windows HE 73 - - sev
39fd6db10d0222d817025c4d3346e3b4 -1 en Mac - Demo - Joachim Eberhard
6c375c2236d99f56e6c2cf540e74e474 34333 nl Windows - Demo - Kirben
diff --git a/doc/cz/PrectiMe b/doc/cz/PrectiMe
index 0f475b9539..2baf145cd9 100644
--- a/doc/cz/PrectiMe
+++ b/doc/cz/PrectiMe
@@ -14,26 +14,27 @@ Obsah:
* 2.1 HlУЁХЁenУ­ chyb
3.0) PodporovanУЉ hry
* 3.1 Ochrana proti kopУ­rovУЁnУ­
- * 3.2 PoznУЁmky ke hrУЁm Commodore64
- * 3.3 PoznУЁmky k Maniac Mansion NES
- * 3.4 PoznУЁmky ke hrУЁm Macintosh
- * 3.5 PoznУЁmky ke hrУЁm Multi-CD
- * 3.6 PoznУЁmky k The Curse of Monkey Island
- * 3.7 PoznУЁmky ke hrУЁm Broken Sword
- * 3.8 PoznУЁmky k Beneath a Steel Sky
- * 3.9 PoznУЁmky k Flight of the Amazon Queen
- * 3.10 PoznУЁmky ke Gobliiins
- * 3.11 PoznУЁmky k Inherit the Earth: Quest for the Orb
- * 3.12 PoznУЁmky k Simon the Sorcerer
- * 3.13 PoznУЁmky k The Feeble Files
- * 3.14 PoznУЁmky k The Legend of Kyrandia
- * 3.15 PoznУЁmky k PХ™edvУ­davУЉmu VstupnУ­mu Dialogu her Sierra AGI
- * 3.16 PoznУЁmky k Mickey's Space Adventure
- * 3.17 PoznУЁmky k Winnie the Pooh
- * 3.18 PoznУЁmky k Troll's Tale
- * 3.19 PoznУЁmky k DraФУ­ Historie
- * 3.20 Titulky a hlasy soubФ›ХОnФ› v hrУЁch Sierra SCI
- * 3.21 ZnУЁmУЉ problУЉmy
+ * 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.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
4.0) PodporovanУЉ platformy
5.0) SpuХЁtФ›nУ­ ScummVM
* 5.1 MoХОnosti pХ™У­kazovУЉho Х™УЁdku
@@ -51,7 +52,7 @@ Obsah:
* 7.3 Emulace MT-32
* 7.4 Emulace MIDI
* 7.5 PХ™irozenУЁ podpora MIDI
- * 7.6 Podpora nativnУ­ho UNIX, ALSA a sekvencУЉru dmedia
+ * 7.6 Podpora nativnУ­ho UNIX, ALSA a sekvenceru dmedia
* 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
@@ -71,8 +72,7 @@ ScummVM je program, kterУН VУЁm umoХОХˆuje spouХЁtФ›t urФitУЉ klasickУЉ grafick
PХЏvodnФ› byl navrХОen pro spouХЁtФ›nУ­ her SCUMM od LucasArts SCUMM, jako napХ™. Maniac Mansion, Monkey Island, Day of the Tentacle nebo Sam and Max. SCUMM znamenУЁ 'NУЁstroj pro VytvУЁХ™enУ­ Skriptu pro Maniac Mansion', coХО byla prvnУ­ hra, pro kterou LucasArts tento systУЉm navrhl. A mnohem pozdФ›ji dal svУЉ jmУЉno ScummVM ('VM' znamenУЁ VirtuУЁlnУ­ Stroj).
Postupem Фasu byla pХ™idУЁna podpora pro spoustu her mimo SCUMM a
-ScummVM nynУ­ takУЉ podporuje mnoho AGI a SCI her od Sierra (napХ™. King's
-Quest 1-6, Space Quest 1-5, ...), Discworld 1 a 2, Simon the Sorcerer 1 and 2, Beneath A Steel Sky, Lure of the Temptress, Broken Sword I a II, Flight of the Amazon Queen, Gobliiins 1-3, sУЉrie The Legend of Kyrandia, mnoho ze SCUMMТ her pro dФ›ti od Humongous Entertainment (vФetnФ› her Freddi Fish a Putt Putt) a mnoho dalХЁУ­ch. Na strУЁnce kompatibility mХЏХОete najУ­t УКplnУН seznam sТ podrobnostmi, kterУЉ adventury jsou podporovУЁny a jak dobХ™e. ScummVM je neustУЁle zlepХЁovУЁn a proto navХЁtФ›vujte naХЁe strУЁnky Фasto.
+ScummVM nynУ­ takУЉ podporuje mnoho AGI a SCI her od Sierra (napХ™. King's Quest 1-6, Space Quest 1-5, ...), Discworld 1 a 2, Simon the Sorcerer 1 and 2, Beneath A Steel Sky, Lure of the Temptress, Broken Sword I a II, Flight of the Amazon Queen, Gobliiins 1-3, sУЉrie The Legend of Kyrandia, mnoho ze SCUMMТ her pro dФ›ti od Humongous Entertainment (vФetnФ› her Freddi Fish a Putt Putt) a mnoho dalХЁУ­ch. Na strУЁnce kompatibility mХЏХОete najУ­t УКplnУН seznam sТ podrobnostmi, kterУЉ adventury jsou podporovУЁny a jak dobХ™e. ScummVM je neustУЁle zlepХЁovУЁn a proto navХЁtФ›vujte naХЁe strУЁnky Фasto.
Mezi systУЉmy, na kterУНch mХЏХОete tyto hrУЁt, jsou bФ›ХОnУЉ stolnУ­ poФУ­taФe (majУ­cУ­ Windows, Linux, Mac OS X, ...), hernУ­ konzole
(Dreamcast, Nintendo DS a Wii, PS2, PSP, ...), chytrУЉ telefony (Android,
@@ -80,7 +80,7 @@ iPhone, PocketPC, Symbian ...) a dalХЁУ­.
VТ souФasnosti je ScummVM stУЁle velkou ФУЁstУ­ ve vУНvoji. NezapomeХˆte, ХОe i kdyХО se snaХОУ­me zajistit, aby mnoho her bylo moХОno dokonФit pouze sТ pУЁr vУЁХОnУНmi chybami, pУЁdy programu mohou nastat a my neposkytujeme ХОУЁdnУЉ zУЁruky. PХ™es to vХЁechno, nФ›kterУЉ hry byly podporovУЁny po dlouhou dobu
A mФ›ly by fungovat vТ poХ™УЁdku seТ vХЁemi novФ›jХЁУ­mi stabilnУ­mi verzemi. Jak dobХ™e bude hra ve ScummVM fungovat mХЏХОete zjistit prohlУЉdnutУ­m strУЁnky kompatibility.
-VlastnФ›, pokud troХЁiФku zahledУЁte, mХЏХОete zjistit, ХОe ScummVM je pouХОУ­vУЁn i komerФnФ› pro znovu vydУЁnУ­ nФ›kterУНch podporovanУНch her na modernУ­ch platformУЁch. To ukazuje, ХОe i nФ›kolik spoleФnostУ­ je spokojeno sТ kvalitou softwaru a jako moc dobХ™e mХЏХОe nФ›kterУЉ hry spouХЁtФ›t.
+VlastnФ›, pokud budete troХЁiФku hledat, mХЏХОete zjistit, ХОe ScummVM je pouХОУ­vУЁn i komerФnФ› pro znovu vydУЁnУ­ nФ›kterУНch podporovanУНch her na modernУ­ch platformУЁch. To ukazuje, ХОe i nФ›kolik spoleФnostУ­ je spokojeno sТ kvalitou softwaru a jako moc dobХ™e mХЏХОe nФ›kterУЉ hry spouХЁtФ›t.
Pokud mУЁte ScummVM rУЁdi, mХЏХОete ho podpoХ™it dotacУ­ pomocУ­ tlaФУ­tka PayPal na strУЁnce ScummVM. To nУЁm pomХЏХОe zakoupit nУЁstroje potХ™ebnУЉ ke snadnФ›jХЁУ­mu a rychlejХЁУ­mu vУНvoji ScummVM. Pokud nemХЏХОete podpoХ™it dotacУ­, pomozte a pХ™ispФ›jte zУЁplatou!
@@ -107,7 +107,7 @@ Rada: Pokud chcete pХ™idat vУ­ce her najednou, zkuste stisknout a drХОet klУЁves
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 .
-MХЏХОete se takУЉ pХ™ipojit a odesУ­lat a e-maily na korespondenФnУ­ seznam scummvm-devel, nebo s nУЁmi chatovat 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
+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:
---- -------------
@@ -147,7 +147,7 @@ Hry SCUMM od LucasArts:
The Dig [dig]
The Curse of Monkey Island [comi]
-Hry AGI od Sierra:
+Hry AGI a pХ™ed AGI od Sierra:
The Black Cauldron [bc]
Gold Rush! [goldrush]
King's Quest I [kq1]
@@ -164,6 +164,9 @@ Hry AGI od Sierra:
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 AGOS od Adventuresoft/Horrorsoft:
Elvira - Mistress of the Dark [elvira1]
@@ -181,6 +184,13 @@ 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]
Hry GOB od Coktel Vision:
Bambou le sauveur de la jungle [bambou]
@@ -196,6 +206,22 @@ Hry GOB od Coktel Vision:
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]
@@ -204,34 +230,106 @@ Hry MADE od Activision:
The Manhole [manhole]
DalХЁУ­ hry:
+ 3 Skulls of the Toltecs [toltecs]
+ Blue Force [blueforce]
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
+ 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]
- Touche: The Adventures of the Fifth
- Musketeer [touche]
+ 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:
+ Castle of Dr. Brain [castlebrain]
+ Codename: ICEMAN [iceman]
+ Conquests of Camelot [camelot]
+ Conquests of the Longbow [longbow]
+ EcoQuest: The Search for Cetus [ecoquest]
+ EcoQuest 2: Lost Secret of the Rainforest [ecoquest2]
+ Freddy Pharkas: Frontier Pharmacist [freddypharkas]
+ Hoyle's Book of Games 1 [hoyle1]
+ Hoyle's Book of Games 2 [hoyle2]
+ Hoyle's Book of Games 3 [hoyle3]
+ Hoyle Classic Card Games [hoyle4]
+ Jones in the Fast Lane [jones]
+ King's Quest I [kq1sci]
+ King's Quest IV [kq4sci]
+ King's Quest V [kq5]
+ King's Quest VI [kq6]
+ Laura Bow: The Colonel's Bequest [laurabow]
+ Laura Bow 2: The Dagger of Amon Ra [laurabow2]
+ Leisure Suit Larry 1 [lsl1sci]
+ Leisure Suit Larry 2 [lsl2]
+ Leisure Suit Larry 3 [lsl3]
+ Leisure Suit Larry 5 [lsl5]
+ Leisure Suit Larry 6 [lsl6]
+ Mixed-up Fairy Tales [fairytales]
+ Mixed-up Mother Goose [mothergoose]
+ Pepper's Adventures in Time [pepper]
+ Police Quest 1 [pq1sci]
+ Police Quest 2 [pq2]
+ Police Quest 3 [pq3]
+ Quest for Glory 1/Hero's Quest [qfg1]
+ Quest for Glory 1 [qfg1vga]
+ Quest for Glory 2 [qfg2]
+ Quest for Glory 3 [qfg3]
+ Slater & Charlie Go Camping [slater]
+ Space Quest I [sq1sci]
+ Space Quest III [sq3]
+ Space Quest IV [sq4]
+ Space Quest V [sq5]
+ The Island of Dr. Brain [islandbrain]
+
+Hry Wintermute:
+ Chivalry is Not Dead [chivalry]
+
+Hry ZVISION od Activision:
+ Zork Nemesis: The Forbidden Lands [znemesis]
+ Zork: Grand Inquisitor [zgi]
Hry SCUMM od Humongous Entertainment:
Backyard Baseball [baseball]
Backyard Baseball 2001 [baseball2001]
Backyard Baseball 2003 [baseball2003]
Backyard Football [football]
+ Backyard Football 2002 [football2002]
+ Bear Stormin' [brstorm]
Big Thinkers First Grade [thinker1]
Big Thinkers Kindergarten [thinkerk]
Blue's 123 Time Activities [Blues123Time]
@@ -256,6 +354,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 1: No Need to Hide When It's
Dark Outside [pajama]
Pajama Sam 2: Thunder and Lightning
@@ -280,35 +379,17 @@ Hry SCUMM od Humongous Entertainment:
SPY Fox in Cheese Chase [chase]
SPY Fox in Hold the Mustard [mustard]
-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 by mФ›ly jУ­t spustit, ale zatУ­m nejsou УКplnФ› hratelnУЉ. Hrajte je pouze na vlastnУ­ riziko a prosУ­me, abyste pro tyto hry nenahlaХЁovali chyby.
Pokud chcete mУ­t nejnovФ›jХЁУ­ zprУЁvy o kompatibilitУЁch her, navХЁtivte naХЁУ­ strУЁnku a prohlУЉdnФ›te si tabulku kompatibilit.
- Backyard Football 2002 [football2002]
Backyard Soccer [soccer]
Backyard Soccer MLS [soccermls]
Backyard Soccer 2004 [soccer2004]
Blue's Treasure Hunt [BluesTreasureHunt]
- Pajama Sam: Games to Play on Any Day [pjgames]
NУЁsledujУ­cУ­ hry jsou odvozeny od jУЁdra SCUMM, ale ScummVM je nepodporuje (zatУ­m):
- OstatnУ­ hry od Humongous Entertainment
+ Moonbase Commander
NezapomeХˆte, prosУ­m, ХОe jУЁdra mohou obsahovat chyby a nezavedenУЉ funkce, kterУЉ nФ›kdy zabrУЁnУ­ hru dokonФit. UklУЁdejte Фasto a nahlaste chyby, prosУ­m (instrukce pro hlУЁХЁenУ­ chyb jsou vУНХЁe), pokud na takovou chybu narazУ­te v 'podporovanУЉ' hХ™e.
@@ -335,14 +416,33 @@ ScummVM pХ™eskakuje ochranu vТ nУЁsledujУ­cУ­ch hrУЁch:
* Monkey Island 2: LeChuck's Revenge
* Simon the Sorcerer 1 (Floppy version)
* Simon the Sorcerer 2 (Floppy version)
- -- potlaФeno sТ laskavУНm svolenУ­m from Adventure Soft,
+ -- potlaФeno sТ laskavУНm svolenУ­m Adventure Soft,
protoХОe byla potlaФena ve vХЁech vydУЁnУ­ch hry na CD.
* The Secret of Monkey Island (VGA)
* 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) PoznУЁmky keТ hrУЁm Commodore64:
+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".
+
+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.
@@ -350,7 +450,7 @@ Jak Maniac Mansion tak Zak McKracken mohou bУНt spuХЁtФ›ny, ale Maniac Mansion n
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.
-3.3) PoznУЁmky ke Maniac Mansion NES:
+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.
@@ -367,7 +467,7 @@ NejbФ›ХОnФ›jХЁУ­ chyby, kterУЉ zabraХˆujУ­ spuХЁtФ›nУ­ hry:
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.4) PoznУЁmky ke hrУЁm Macintosh:
+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.
@@ -380,14 +480,14 @@ Pro dalХЁУ­ informace o kopУ­rovУЁnУ­ hernУ­ch souborХЏ Macintosh na VУЁХЁ pevnУ
http://wiki.scummvm.org/index.php/HOWTO-Mac_Games
-3.5) PoznУЁmky ke hrУЁm Multi-CD:
+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.
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.6) PoznУЁmky k The Curse of Monkey Island:
+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.
@@ -395,12 +495,12 @@ Soubor comi.la0 mХЏХОete nalУЉzt na vХЁech CD hry, ale protoХОe jsou stejnУЉ, mХ
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.7) PoznУЁmky ke hrУЁm Broken Sword:
+3.8) 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.7.1) Videa zТ her Broken Sword:
+3.8.1) 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ФУ­.
@@ -419,7 +519,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.7.2) Videa her Broken Sword ve zpФ›tnУЉm pohledu:
+3.8.2) 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У­.
@@ -431,14 +531,14 @@ 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.7.3) Broken Sword:
+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.
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.7.4) Broken Sword II:
+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,
@@ -447,7 +547,7 @@ speech2.clu, music1.clu a music2.clu, aby ScummVM mohl zjistit, kterУЉ jsou z CD
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 Beneath a Steel Sky:
+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.
@@ -455,7 +555,7 @@ 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.9) PoznУЁmky k Flight of the Amazon Queen:
+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'
@@ -464,12 +564,12 @@ Abyste mohli pouХОУ­t tu verzi, kterУЁ nenУ­ volnФ› ХЁiХ™itelnУЁ
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.10) PoznУЁmky ke Gobliiins:
+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.
-3.11) PoznУЁmky k Inherit the Earth: Quest for the Orb:
+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:
@@ -482,12 +582,12 @@ I kdyХО se vТ tomto ФlУЁnku pУ­ХЁe hlavnФ› o hrУЁch SCUMM, je zde takУЉ zmУ­nФ›
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.12) PoznУЁmky k Simon the Sorcerer 1 a 2:
+3.13) 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.13) PoznУЁmky k The Feeble Files:
+3.14) PoznУЁmky k The Feeble Files:
----- ----------------------------
Pokud mУЁte verzi pro Windows, je tХ™eba si uvФ›domit pУЁr vФ›cУ­.
@@ -499,21 +599,21 @@ 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.14) PoznУЁmky k The Legend of Kyrandia:
+3.15) 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ХОdykcy souФУЁstУ­ oficiУЁlnУ­ch balУ­ФkХЏ ScummVM. V pХ™У­padФ›, ХОe ScummVM
-hlУЁsУ­, ХОe soubor chybУЁ, mХЏХОete ho najУ­t na strУЁnce ScummVM v sekci 'Downloads'.
+Soubor by mФ›l bУНt vХОdycky souФУЁstУ­ oficiУЁlnУ­ch balУ­ФkХЏ ScummVM. V pХ™У­padФ›, ХОe ScummVM
+nahlУЁsУ­, ХОe soubor chybУ­, mХЏХОete ho najУ­t na strУЁnce ScummVM v sekci 'Downloads'.
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.15) PoznУЁmky kТ PХ™edvУ­davУЉmu VstupnУ­mu Dialogu her Sierra AGI:
+3.16) 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.
Abyste zapnuli pХ™edvУ­davУН vstup v hrУЁch AGI, potХ™ebujete zkopУ­rovat soubor pred.dic do dodateФnУЉ sloХОky ScummVM nebo do sloХОky hry, kterou chcete hrУЁt. Tento slovnУ­k byl vytvoХ™en analУНzou vХЁech znУЁmУНch her AGI a obsahuje maximУЁlnУ­ sadu bФ›ХОnУНch slov.
-Pokud je slovnУ­k zjiХЁtФ›n, je PХ™edvУ­davУН VstupnУ­ Dialog zobrazen buФ pХ™i klinutУ­ 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.
+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.
@@ -527,36 +627,36 @@ TХ™etУ­ vstupnУ­ metodou (Abc) je vstupnУ­ reХОim Alfa/opakovanУЉho stisknutУ­ t
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.16) PoznУЁmky k Mickey's Space Adventure:
+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.17) Winnie the Pooh notes:
+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.18) PoznУЁmky k Troll's Tale:
+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.19) PoznУЁmky k DraФУ­ Historie:
+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 stУЁhnuty z
+VХЁechny hernУ­ soubory a nУЁvody mХЏХОou bУНt staХОeny z
http://www.ucw.cz/draci-historie/index-en.html
-3.20) Titulky a hlasy soubФ›ХОnФ› v hrУЁch Sierra SCI:
+3.21) 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
@@ -602,58 +702,62 @@ Space Quest 4 CD:
nastavenУ­ hry, nebo pomocУ­ nastavenУ­ zvuku ve ScummVM.
-3.21) ZnУЁmУЉ ProblУЉmy:
+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
+ - 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
+ - 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
+ - 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
+ - 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У­.
+ - 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
+ - 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
+ - Ve verzi pro Atari ST nefunguje hudba
+ - Ve verzi pro PC nefungujУ­ zvukovУЉ efekty
+ - Ve verzi pro Atari ST jsou problУЉmy s paletou
Inherit the Earth: Quest for the Orb
-- Verze pro Amiga nejsou podporovУЁny
+ - Verze pro Amiga nejsou podporovУЁny
+
+ 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У­.
+ - VТ anglickУНch a nФ›meckУНch verzУ­ch na CD nejsou titulky dostupnУЉ, protoХОe jim vФ›tХЁina titulkХЏ chybУ­.
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).
+ - 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.
+ - ХНУЁ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.
The Feeble Files:
-- Titulky jsou Фasto nedokonФenУЉ. VТ pХЏvodnУ­ hХ™e byly vХОdy zakУЁzУЁny.
+ - Titulky jsou Фasto nedokonФenУЉ. VТ pХЏvodnУ­ hХ™e byly vХОdy zakУЁzУЁny.
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.
+ - 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.
@@ -903,6 +1007,7 @@ JУЁdra, kterУЁ vТ souФasnosti podporujУ­ nУЁvrat do spouХЁtФ›Фe, jsou:
TOUCHE
TSAGE
TUCKER
+ ZVISION
5.5) KlУЁvesovУЉ zkratky:
@@ -913,25 +1018,29 @@ 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 OR Alt-x - Quit (dalХЁУ­ platformy)
+ Ctrl-z NEBO Alt-x - 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 + and - - 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 320x240, nebo jeho nУЁsobky
+ 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
+ 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)
+ Ctrl-F7 - OtevХ™У­t virtuУЁlnУ­ klУЁvesnici (pokud povolena)
+ MХЏХОe bУНt takУЉ spuХЁtФ›na dlouhУНm stiskem
+ prostХ™ednУ­ho tlaФУ­tka nebo koleФka myХЁi.
SCUMM:
- Ctrl 0-9 and Alt 0-9 - NahrУЁt a uloХОit stav hry
+ 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
Ctrl-g - PХ™epnout do velmi VELMI rychlУЉho reХОimu
Ctrl-t - PХ™epУ­nat mezi 'Pouze Х™eФ',
'՘eФ a Titulky' a 'Pouze titulky'
Tilda (~) - Zobrazit/skrУНt konzoli ladФ›nУ­
- [ and ] - Hlasitost hudby, zvУНХЁit/snУ­ХОit
- - and + - Rychlost textu, pomalejХЁУ­/rychlejХЁУ­
+ [ a ] - Hlasitost hudby, zvУНХЁit/snУ­ХОit
+ - a + - Rychlost textu, pomalejХЁУ­/rychlejХЁУ­
F5 - ZobrazУ­ rУЁmeФek pro uloХОenУ­/naФtenУ­
Alt-F5 - ZobrazУ­ pХЏvodnУ­ rУЁmeФek pro uloХОenУ­/naФtenУ­, pokud hra nФ›jakУН mУЁ. Zde mХЏХОete hru naФУ­st i uloХОit, nicmУЉnФ› pro tento УКФel nenУ­ urФen a vТ nФ›kterУНch hrУЁch mХЏХОe zpХЏsobit pУЁd ScummVM.
i - ZobrazУ­ IQ body (Indiana Jones and the Last Crusade a Indiana Jones and the Fate of Atlantis)
@@ -946,7 +1055,7 @@ Ctrl-Alt a - PХ™epУ­nat korekci pomФ›ru stran. VФ›tХЁina her pouХОУ­
Ctrl-g - PХ™epnout do velmi VELMI rychlУЉho reХОimu
F5 - ZobrazУ­ rУЁmeФek pro uloХОenУ­/naФtenУ­
Escape - PХ™eskoФУ­ УКvod hry
- Period (.) - PХ™eskoФУ­ souФasnУН Х™УЁdek textu
+ TeФka (.) - PХ™eskoФУ­ souФasnУН Х™УЁdek textu
Broken Sword:
F5 nebo Escape - ZobrazУ­ rУЁmeФek pro uloХОenУ­/naФtenУ­
@@ -1026,7 +1135,7 @@ Ctrl-Alt a - PХ™epУ­nat korekci pomФ›ru stran. VФ›tХЁina her pouХОУ­
v - PХ™epУ­nat mezi titulky a kombinacУ­ Х™eФi a titulkХЏ
The Legend of Kyrandia:
- Ctrl 0-9 and Alt 0-9 - NaФУ­st a uloХОit stav hry
+ Ctrl 0-9 a Alt 0-9 - NaФУ­st a uloХОit stav hry
Ctrl-d - Spustit ladФ›nУ­
@@ -1041,7 +1150,27 @@ Ctrl-Alt a - PХ™epУ­nat korekci pomФ›ru stran. VФ›tХЁina her pouХОУ­
Escape - UkonФit
MezernУ­k - PХ™eskoФУ­ souФasnУН Х™УЁdek textu
t - PХ™epnout mezi 'Pouze ՘eФ',
- '՘eФ a Text' a ' Pouze Text'
+ '՘eФ a Text' a 'Pouze Text'
+
+ Zork: Grand Inquisitor
+ Ctrl-s - UloХОit
+ Ctrl-r - NaФУ­st
+ Ctrl-q - UkonФit
+ Ctrl-p - NastavenУ­
+ F1 - NУЁpovФ›da
+ F5 - InventУЁХ™
+ F6 - Kniha kouzel
+ F7 - SkУГre
+ F8 - Zahodit souФasnУН objekt/zapomenout kouzlo
+ F9 - Vyjmout minci (musУ­te mУ­t mФ›ХЁec)
+ Space - PХ™eskoФit videa
+
+ Zork Nemesis: The Forbidden Lands
+ Ctrl-s - UloХОit
+ Ctrl-r - NaФУ­st
+ Ctrl-q - UkonФit
+ Ctrl-p - NastavenУ­
+ Space - PХ™eskoФit videa
NezapomeХˆte, ХОe pouХОУ­vУЁnУ­ Ctrl-f nebo Ctrl-g nenУ­ doporuФeno: hry mohou spadnout, kdyХО bФ›ХОУ­ rychlostУ­ vyХЁХЁУ­ neХО jejich normУЁlnУ­, protoХОe skripty ztratУ­ synchronizaci.
@@ -1146,6 +1275,7 @@ Kde 'xxx' je ФУ­slo pozice uloХОenУЉ hry (tj. 001) ve ScummVM
TOUCHE
TSAGE
TUCKER
+ ZVISION
--save-slot/-x:
@@ -1153,7 +1283,7 @@ Kde 'xxx' je ФУ­slo pozice uloХОenУЉ hry (tj. 001) ve ScummVM
PouХОitУ­: --save-slot[POZICE] nebo -x[POZICE], kde [POZICE] je ФУ­slo uloХОenУЉ pozice.
- JУЁdra, kterУЁ vТ souФasnosti podporujУ­--save-slot/-x jsou:
+ JУЁdra, kterУЁ vТ souФasnosti podporujУ­ --save-slot/-x jsou:
AGI
CGE
@@ -1178,6 +1308,7 @@ Kde 'xxx' je ФУ­slo pozice uloХОenУЉ hry (tj. 001) ve ScummVM
TOUCHE
TSAGE
TUCKER
+ ZVISION
7.0) Hudba a Zvuk:
@@ -1193,12 +1324,12 @@ DostupnУЉ ve vХЁech operaФnУ­ch systУЉmech, nebo potХ™ebuje ruФnУ­ nastavenУ­.
pcspk - VnitХ™nУ­ emulace reproduktoru PC
towns - VnitХ™nУ­ emulace FM-TOWNS YM2612
(pouХОitelnУЉ pouze v hrУЁch SCUMM FM-TOWNS)
- alsa - VУНstup pomocУ­ zaХ™У­zenУ­ sekvencУЉru ALSA. Viz nУ­ХОe.
+ alsa - VУНstup pomocУ­ zaХ™У­zenУ­ sekvenceru ALSA. Viz nУ­ХОe.
core - Zvuk CoreAudio, pro uХОivatele Mac OS X.
- coremidi - Zvuk CoreMIDI, pro uХОivatele Mac OS X. PouХОУ­vejte pouze, pokud mУЁte hardwarovУН syntetizУЁtor MIDI.
+ coremidi - Zvuk CoreMIDI, pro uХОivatele Mac OS X. PouХОУ­vejte pouze, pokud mУЁte hardwarovУН syntezУЁtor MIDI.
seq - PouХОitУ­ /dev/sequencer pro MIDI v systУЉmu *nix. Viz nУ­ХОe
timidity - PХ™ipojenУ­ kТ MIDI serveru TiMidity++. Viz nУ­ХОe.
- windows - Windows MIDI. PouХОije zabudovanУН sekvencУЉr, pro Windows
+ windows - Windows MIDI. PouХОije zabudovanУН sekvencer, pro Windows
Abyste vybrali ovladaФ zvuku, zvolte ho ve spouХЁtФ›Фi, nebo pХ™edejte jeho jmУЉno ScummVM pomocУ­ moХОnosti '-e', napХ™У­klad:
@@ -1215,7 +1346,7 @@ StandardnФ› bude karta AdLib emulovУЁna a ScummVM hudbu pХ™ehrУЁvУЁ jako vzorkov
Pokud byl ScummVM sestaven s podporou libfluidsynth bude schopen pХ™ehrУЁvat hudbu MIDI pomocУ­ ovladaФe FluidSynth. Budete muset ale urФit, kterУН SoundFont pouХОУ­t.
ProtoХОe vУНchozУ­ hlasitost vУНstupu od FluidSynth mХЏХОe bУНt velmi nУ­zkУЁ,
-ScummVM standardnФ› nastavУ­ zvУНХЁenУ­, aby dostal silnФ›jХЁУ­ signУЁl. To mХЏХОe bУНt dУЁle upaveno pouХОitУ­m moХОnosti pХ™У­kazovУЉho Х™УЁdku --midi-gain, nebo nastavenУ­m "midi_gain" vТ konfiguraФnУ­m souboru.
+ScummVM standardnФ› nastavУ­ zvУНХЁenУ­, aby dostal silnФ›jХЁУ­ signУЁl. To mХЏХОe bУНt dУЁle upraveno pouХОitУ­m moХОnosti pХ™У­kazovУЉho Х™УЁdku --midi-gain, nebo nastavenУ­m "midi_gain" vТ konfiguraФnУ­m souboru.
NastavenУ­ mХЏХОe nabУНvat hodnoty od 0 po 1000 a vУНchozУ­ je 100. (Toto odpovУ­dУЁ nastavenУ­ zvУНХЁenУ­ FluidSynth's 0.0 aХО 10.0, coХО je pravdФ›podobnФ› mФ›Х™eno v decibelech.)
@@ -1224,7 +1355,7 @@ POZNУMKA: PoХОadavky na procesor pro FluidSynth mХЏХОou bУНt vТ nФ›kterУНch pХ™
7.3) PХ™ehrУЁvУЁnУ­ zvuku pomocУ­ emulace MT-32:
---- --------------------------------------
-NФ›kterУЉ hry, kterУЉ obsahujУ­ hudebnУ­ data MIDI, takУЉ majУ­ vylepХЁenУЉ stopuy urФenУЉ pro zvukovУН modul MT-32. ScummVM mХЏХОe toto zaХ™У­zenУ­ nynУ­ emulovat, nicmУЉnФ› aby toto zaХ™У­zenУ­ fungovalo, musУ­te mУ­t pХЏvodnУ­ ROMy MT-32:
+NФ›kterУЉ hry, kterУЉ obsahujУ­ hudebnУ­ data MIDI, takУЉ majУ­ vylepХЁenУЉ stopy urФenУЉ pro zvukovУН modul MT-32. ScummVM mХЏХОe toto zaХ™У­zenУ­ nynУ­ emulovat, nicmУЉnФ› aby toto zaХ™У­zenУ­ fungovalo, musУ­te mУ­t pХЏvodnУ­ ROMy MT-32:
MT32_PCM.ROM - IC21 (512KB)
MT32_CONTROL.ROM - IC26 (32KB) a IC27 (32KB), proklУЁdanУЉ podle bajtu
@@ -1260,18 +1391,18 @@ Pokud nenУ­ ani jedna zТ moХОnostУ­ vУНХЁe povolena, ScummVM VaХЁe zaХ™У­zenУ­ z
NФ›kterУЉ hry obsahujУ­ zvukovУЉ efekty pouze v AdLib. Pro tyto hry, byste mФ›li zadat --multi-midi, abyste zkombinovali hudbu MIDI se zvukovУНmi efekty AdLib.
-7.6) PХ™ehrУЁvУЁnУ­ zvuku pomocУ­ SekvencУЉru MIDI: [POUZE UNIX]
+7.6) PХ™ehrУЁvУЁnУ­ zvuku pomocУ­ Sekvenceru MIDI: [POUZE UNIX]
---- ----------------------------------------
-Pokud VУЁХЁ ovladaФ podporuje sekvencУЉr, mХЏХОete nastavit promФ›nnou prostХ™edУ­ "SCUMMVM_MIDI" na VaХЁem zaХ™У­zenУ­ sekvencУЉru т€“ napХ™У­klad na /dev/sequencer
+Pokud VУЁХЁ ovladaФ podporuje sekvencer, mХЏХОete nastavit promФ›nnou prostХ™edУ­ "SCUMMVM_MIDI" na VaХЁem zaХ™У­zenУ­ sekvenceru т€“ napХ™У­klad na /dev/sequencer
-Pokud mУЁte problУЉm se zvukem vТ tomto nastavenУ­, moХОnУЁ budete muset nastavit promФ›nnou prostХ™edУ­ "SCUMMVM_MIDIPORT" na 1 nebo 2. Toto vybere port, kterУН bude pouХОit ve zvolenУЉm sekvencУЉru. Pak spusХЅte scummvm s parametrem -eseq. To by mФ›lo fungovat pro nФ›kolik karet a mХЏХОe nabУ­zet lepХЁУ­ vУНkon a kvalitu, neХО emulace AdLib. NicmУЉnФ› pro systУЉmy, kde podpora sekvencУЉru nefunguje, mХЏХОete vХОdycky pХ™ejУ­t na emulaci AdLib.
+Pokud mУЁte problУЉm se zvukem vТ tomto nastavenУ­, moХОnУЁ budete muset nastavit promФ›nnou prostХ™edУ­ "SCUMMVM_MIDIPORT" na 1 nebo 2. Toto vybere port, kterУН bude pouХОit ve zvolenУЉm sekvenceru. Pak spusХЅte scummvm s parametrem -eseq. To by mФ›lo fungovat pro nФ›kolik karet a mХЏХОe nabУ­zet lepХЁУ­ vУНkon a kvalitu, neХО emulace AdLib. NicmУЉnФ› pro systУЉmy, kde podpora sekvenceru nefunguje, mХЏХОete vХОdycky pХ™ejУ­t na emulaci AdLib.
-7.6.1) PХ™ehrУЁvУЁnУ­ zvuku pomocУ­ SekvencУЉru ALSA: [POUZE UNIX]
+7.6.1) PХ™ehrУЁvУЁnУ­ zvuku pomocУ­ Sekvenceru ALSA: [POUZE UNIX]
------ ----------------------------------------
-Pokud MУЁte nainstalovУЁn ovladaФ ALSA sТ podporou sekvencУЉru, pak mХЏХОete nastavit promФ›nnou prostХ™edУ­ "SCUMMVM_PORT" nebo promФ›nnou souboru s nastavenУ­m "alsa_port" pro urФenУ­ portu VaХЁeho sekvencУЉru. Pokud ani jedno nenУ­ nastaveno, jsou standardnФ› vyzkouХЁeny oba porty "65:0" a "17:0".
+Pokud MУЁte nainstalovУЁn ovladaФ ALSA sТ podporou sekvenceru, pak mХЏХОete nastavit promФ›nnou prostХ™edУ­ "SCUMMVM_PORT" nebo promФ›nnou souboru s nastavenУ­m "alsa_port" pro urФenУ­ portu VaХЁeho sekvenceru. Pokud ani jedno nenУ­ nastaveno, jsou standardnФ› vyzkouХЁeny oba porty "65:0" a "17:0".
-Zde je krУЁtkУН nУЁvod, jak sekvencУЉr pouХОУ­t sТ VaХЁУ­ zvukovou kartou. Ve vХЁech pХ™У­padech, pro zУ­skУЁnУ­ seznamu vХЁech portХЏ sekvencУЉru, zkuste pХ™У­kaz "aconnect -o -l". To by mФ›lo mУ­t vУНstup podobnУН tomuto:
+Zde je krУЁtkУН nУЁvod, jak sekvencer pouХОУ­t sТ VaХЁУ­ zvukovou kartou. Ve vХЁech pХ™У­padech, pro zУ­skУЁnУ­ seznamu vХЁech portХЏ sekvenceru, zkuste pХ™У­kaz "aconnect -o -l". To by mФ›lo mУ­t vУНstup podobnУН tomuto:
client 14: 'Midi Through' [type=kernel]
0 'Midi Through Port-0'
@@ -1302,22 +1433,22 @@ Pokud VaХЁe karta neumУ­ sТ MIDI pracovat, existujУ­ dvФ› moХОnosti: FluidSynth
iMUSE, kterУН pouХОУ­vУЁ rychlУЉ a dynamickУЉ pХ™echody hudby.
SpuХЁtФ›nУ­m TiMidity jako root mu umoХОnУ­ nastavit prioritu vТ reУЁlnУЉm Фase, coХО mХЏХОe zaostУЁvУЁnУ­ snУ­ХОit.
-PХ™У­kaz pro TiMidity, aby se stal sekvencУЉrem ALSA:
+PХ™У­kaz pro TiMidity, aby se stal sekvencerem ALSA:
timidity -iAqqq -B2,8 -Os1S -s 44100 &
(Pokud sТ tУ­mto nastavenУ­m dostУЁvУЁte zkreslenУН vУНstup, mХЏХОete zkusit vynechat -B2,8 nebo zmФ›nit hodnotu.)
-PХ™У­kaz pro TiMidity, aby se stal sekvencУЉrem ALSA (pouХОitУ­m SoundFonts):
+PХ™У­kaz pro TiMidity, aby se stal sekvencerem ALSA (pouХОitУ­m SoundFonts):
fluidsynth -m alsa_seq /cesta/k/8mbgmsfx.sf2
Jakmile je TiMidity nebo FluidSynth spuХЁtФ›n, pouХОijte pХ™У­kaz 'aconnect -o -l' jak je pospУЁno vУНХЁe vТ tУЉto ФУЁsti.
-7.6.2) PХ™ehrУЁvУЁnУ­ zvuku pomocУ­ SekvencУЉru IRIX dmedia: [POUZE UNIX]
+7.6.2) PХ™ehrУЁvУЁnУ­ zvuku pomocУ­ Sekvenceru IRIX dmedia: [POUZE UNIX]
------ -----------------------------------------------
-Pokud pouХОУ­vУЁte IRIX a ovladaФ dmedia s podporou sekvencУЉru, mХЏХОete nastavit promФ›nnou prostХ™edУ­ "SCUMMVM_MIDIPORT" nebo promФ›nnou souboru sТ nastavenУ­m "dmedia_port" pro urФenУ­ portu VaХЁeho sekvencУЉru. StandardnФ› je pouХОit prvnУ­ port.
+Pokud pouХОУ­vУЁte IRIX a ovladaФ dmedia s podporou sekvenceru, mХЏХОete nastavit promФ›nnou prostХ™edУ­ "SCUMMVM_MIDIPORT" nebo promФ›nnou souboru sТ nastavenУ­m "dmedia_port" pro urФenУ­ portu VaХЁeho sekvenceru. StandardnФ› je pouХОit prvnУ­ port.
Abyste zУ­skali seznam nastavenУНch rozhranУ­ midi ve VaХЁem systУЉmu, spusХЅte pХ™У­kaz "startmidi" bez parametrХЏ. VzorovУН vУНstup:
@@ -1334,7 +1465,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 sekvencУЉr 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:
@@ -1583,14 +1714,20 @@ Jsou rozpoznУЁvУЁna nУЁsledujУ­cУ­ klУ­ФovУЁ slova:
Hry Sierra pouХОУ­vajУ­cУ­ jУЁdro AGI pХ™idУЁvajУ­ nУЁsledujУ­cУ­ nestandardnУ­ klУ­ФovУЉ slovo:
-originalsaveload boolean Pokud true, jsou pouХОity pХЏvodnУ­ obrazovky nahrУЁvУЁnУ­/uloХОenУ­ mУ­sto vylepХЁenУНch ze ScummVM
+ originalsaveload boolean Pokud true, jsou pouХОity pХЏvodnУ­ obrazovky nahrУЁvУЁnУ­/uloХОenУ­ mУ­sto vylepХЁenУНch ze ScummVM
+ altamigapalette boolean PouХОУ­t alternativnУ­ paletu, bФ›ХОnУЉ pro hry Amiga. Toto byl pХЏvodnУ­ starУН standard
+ mousesupport boolean PovolУ­ podporu myХЁi. UmoХОnУ­ pouХОУ­t myХЁ pro pohyb a pro ovlУЁdУЁnУ­ hernУ­ch nabУ­dek
Hry Sierra pouХОУ­vajУ­cУ­ jУЁdro SCI pХ™idУЁvajУ­ nУЁsledujУ­cУ­ nestandardnУ­ klУ­ФovУЁ slova:
disable_dithering boolean Odstranit artefakty chvФ›nУ­ vТ nФ›kterУНch hrУЁch EGA
prefer_digitalsfx boolean Pokud true, jsou upХ™ednostХˆovУЁny digitУЁlnУ­ zvukovУЉ efekty pХ™ed syntetizovanУНmi
originalsaveload boolean Pokud true, jsou pouХОity pХЏvodnУ­ obrazovky nahrУЁvУЁnУ­/uloХОenУ­ mУ­sto vylepХЁenУНch ze ScummVM
- native_fb01 bool Pokud true, je ovladaФ hudby pro kartu IBM Music Feature nebo modul syntetizУЁtoru Yahama FB-01 FM pouХОit jako vУНstup MIDI
+ native_fb01 boolean Pokud true, je ovladaФ hudby pro kartu IBM Music Feature nebo modul syntezУЁtoru Yahama FB-01 FM pouХОit jako vУНstup MIDI
+ 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)
@@ -1605,7 +1742,7 @@ Flight of the Amazon Queen pХ™idУЁvУЁ nУЁsledujУ­cУ­ nestandardnУ­ klУ­ФovУЁ sl
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УЉ nepivnnУЉ krvavУЉ scУЉny ve hХ™e
+ 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:
@@ -1662,11 +1799,30 @@ The Neverhood pХ™idУЁvУЁ nУЁsledujУ­cУ­ nestandardnУ­ klУ­ФovУЁ slova:
The 7th Guest pХ™idУЁvУЁ nУЁsledujУ­cУ­ nestandardnУ­ klУ­ФovУЉ slovo:
fast_movie_speed boolean Pokud true, jsou videa pХ™ehrУЁvУЁna pХ™i zvУНХЁenУЉ
- rychlosti, stejnУЉ jako ve verzi pro iOS.
+ rychlosti, stejnУЉ jako ve verzi pro iOS
Videa bez zvuku jsou stУЁle pХ™ehrУЁvУЁna pХ™i
normУЁlnУ­ rychlosti, aby nedoХЁlo k desynchronizaci
hudby
+Zork Nemesis: The Forbidden Lands pХ™idУЁvУЁ nУЁsledujУ­cУ­ nestandardnУ­ klУ­ФovУЉ slovo:
+
+ originalsaveload boolean Pokud true, jsou pro obrУЁzky pХ™i uloХОenУ­/naФtenУ­ her
+ pouХОity pХЏvodnУ­ mУ­sto vylepХЁenУНch ze ScummVM
+ doublefps boolean Pokud true, je hernУ­ rychlost zvУНХЁena z 30 snУ­mkХЏ za sekundu na 60
+ venusenabled boolean Pokud true, je povolen hernУ­ systУЉm nУЁpovФ›dy Venus
+ noanimwhileturning boolean Pokud true, jsou pХ™i otУЁФenУ­ v panoramatickУЉm reХОimu
+ zakУЁzУЁny
+
+Zork: Grand Inquisitor pХ™idУЁvУЁ nУЁsledujУ­cУ­ nestandardnУ­ klУ­ФovУЉ slovo:
+
+ originalsaveload boolean Pokud true, jsou pro obrУЁzky pХ™i uloХОenУ­/naФtenУ­ her
+ pouХОity pХЏvodnУ­ mУ­sto vylepХЁenУНch ze ScummVM
+ doublefps boolean Pokud true, je hernУ­ rychlost zvУНХЁena z 30 snУ­mkХЏ za sekundu na 60
+ noanimwhileturning boolean Pokud true, jsou pХ™i otУЁФenУ­ v panoramatickУЉm reХОimu
+ zakУЁzУЁny
+ 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У­
@@ -1695,15 +1851,15 @@ Na Win9x/NT/XP mХЏХОete urФit USE_WINDBG a pХ™ipojit WinDbg pro prochУЁzenУ­ la
Фi
http://wiki.scummvm.org/index.php/Compiling_ScummVM/MinGW
- Microsoft Visual C++ 8/9/10:
- * PХ™eФtФ›te si, jak vytvoХ™it soubory projektu ve "dists\msvc8",
- "dists\msvc9" pХ™У­sluХЁnФ› "dists\msvc10".
+ 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/VS2005
+ http://wiki.scummvm.org/index.php/Compiling_ScummVM/Visual_Studio
Windows Mobile:
* PХ™eФtФ›te si prosУ­m:
@@ -1715,7 +1871,7 @@ Na Win9x/NT/XP mХЏХОete urФit USE_WINDBG a pХ™ipojit WinDbg pro prochУЁzenУ­ la
(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 (to funguje pouze, kdyХО mУЁte SDL nainstalovУЁn do /sw, coХО se pХ™i instalaci Fink provede). Pokud jste SDL nainstalovali jinУНm zpХЏsobem, budete muset upravit ports.mk).
+ * 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
diff --git a/doc/de/Liesmich b/doc/de/Liesmich
index 9190bb0852..a962ae6baa 100644
--- a/doc/de/Liesmich
+++ b/doc/de/Liesmich
@@ -1,4 +1,4 @@
-ScummVM - Liesmich-Datei
+ScummVM т€“ Liesmich-Datei
------------------------------------------------------------------------
FУМr weitere Informationen, KompatibilitУЄtslisten, Einzelheiten zu Spenden, die
@@ -15,26 +15,27 @@ Inhaltsverzeichnis:
* 2.1 Fehler berichten
3.0) UnterstУМtzte Spiele
* 3.1 Kopierschutz
- * 3.2 Hinweise zu Commodore64-Spielen
- * 3.3 Hinweise zu Maniac Mansion NES
- * 3.4 Hinweise zu Macintosh-Spielen
- * 3.5 Hinweise zu Spielen auf mehren CDs
- * 3.6 Hinweise zu The Curse of Monkey Island
- * 3.7 Hinweise zu Baphomets Fluch I und II
- * 3.8 Hinweise zu Beneath a Steel Sky
- * 3.9 Hinweise zu Flight of the Amazon Queen
- * 3.10 Hinweise zu Gobliiins
- * 3.11 Hinweise zu Inherit the Earth: Quest for the Orb (Macintosh)
- * 3.12 Hinweise zu Simon the Sorcerer 1 und 2
- * 3.13 Hinweise zu Floyd - Es gibt noch Helden
- * 3.14 Hinweise zu The Legend of Kyrandia
- * 3.15 Hinweise zum vorhersagenden Eingabedialog bei Sierras AGI-Spielen
- * 3.16 Hinweise zu Mickey's Space Adventure
- * 3.17 Hinweise zu Winnie the Pooh
- * 3.18 Hinweise zu Troll's Tale
- * 3.19 Hinweise zu DraФi Historie
- * 3.20 Gleichzeitige Sprachausgabe und Untertitel in Sierra-SCI-Spielen
- * 3.21 Bekannte Probleme
+ * 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.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
4.0) UnterstУМtzte Plattformen
5.0) ScummVM verwenden
* 5.1 Kommandozeilenoptionen
@@ -43,16 +44,16 @@ Inhaltsverzeichnis:
* 5.4 Globales MenУМ
* 5.5 TastenkУМrzel
6.0) SpielstУЄnde
- * 6.1 Automatische SpielstУЄnde
+ * 6.1 Automatische Spielstand-Speicherung
* 6.2 SpielstУЄnde umwandeln
- * 6.3 SpielstУЄnde von Kommandozeile aus anzeigen/laden
+ * 6.3 SpielstУЄnde von der Kommandozeile aus anzeigen/laden
7.0) Musik und Sound
* 7.1 AdLib-Emulation
* 7.2 FluidSynth-MIDI-Emulation
* 7.3 MT-32-Emulation
* 7.4 MIDI-Emulation
* 7.5 Native MIDI-UnterstУМtzung
- * 7.6 UNIX-eigene, ALSA- und IRIX' Sequenzer-UnterstУМtzung
+ * 7.6 UNIX-eigene, ALSA- und Dmedia-Sequenzer-UnterstУМtzung
* 7.7 TiMidity++-MIDI-Server-UnterstУМtzung
* 7.8 Komprimierte Audio-Dateien verwenden (MP3, Ogg Vorbis, FLAC)
* 7.9 Ausgabefrequenzen
@@ -69,10 +70,10 @@ Inhaltsverzeichnis:
---- -------------
ScummVM ist ein Programm, welches es Ihnen ermУЖglicht, bestimmte klassische
Grafik-Adventure (unter anderem aus dem Point-and-Click-Bereich) zu spielen,
-vorausgesetzt, Sie sind im Besitz der Dateien des Spiels. Der Trick dabei ist:
-ScummVM ersetzt lediglich die Funktion der ausfУМhrbaren Dateien, die mit den
-Spielen kamen, was ermУЖglicht, diese Spiele auf Systemen zu spielen, fУМr welche
-sie nie erstellt wurden!
+vorausgesetzt, Sie sind im Besitz der entsprechenden Spieldateien. Der Trick
+dabei ist: ScummVM ersetzt lediglich die Funktion der ausfУМhrbaren Dateien, die
+mit den Spielen mitgeliefert wurden, was ermУЖglicht, diese Spiele auf Systemen
+zu spielen, fУМr welche sie nie erstellt wurden!
UrsprУМnglich wurde dieses Programm dafУМr entwickelt, um SCUMM-Spiele von
LucasArts auszufУМhren, wie beispielsweise Maniac Mansion, Monkey Island, Day of
@@ -82,15 +83,15 @@ Maniac Mansion), was das erste Spiel von LucasArts war, fУМr welches LucasArts
dieses System entworfen hatte. Und viel spУЄter verlieh es seinen Namen an
ScummVM (wobei т€žVMт€œ fУМr т€žVirtuelle Maschineт€œ steht).
-Mit der Zeit wurde UnterstУМtzung fУМr viele Nicht-SCUMM-Spiele hinzugefУМgt und
-ScummVM unterstУМtzt nun auch viele AGI- und SCI-Spiele von Sierra (wie
+Mit der Zeit wurde UnterstУМtzung fУМr viele Nicht-SCUMM-Spiele hinzugefУМgt, so
+unterstУМtzt ScummVM nun auch viele AGI- und SCI-Spiele von Sierra (wie
beispielsweise King's Quest 1-6, Space Quest 1-5, ...), Discworld 1 und 2, Simon
the Sorcerer 1 und 2, Beneath A Steel Sky, Lure of the Temptress, Baphomets
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 unterstУМtzt werden und wie gut. Gehen Sie
+Auskunft darУМber gibt, welche Spiele wie gut unterstУМtzt werden. Gehen Sie
hierfУМr auf die KompatibilitУЄtsseite. ScummVM wird fortlaufend verbessert, also
schauen Sie УЖfter einmal vorbei.
@@ -100,17 +101,17 @@ Mac OS X, ...), Spielekonsolen (Dreamcast, Nintendo DS & Wii, PS2, PSP, ...),
Smartphones (Android, iPhone, PocketPC, Symbian ...) und einige weitere.
Zurzeit befindet sich ScummVM immer noch stark in der Entwicklung. Seien Sie
-sich bewusst, dass wir zwar versuchen, dass viele Spiele mit wenigen erheblichen
-Fehlern durchgespielt werden kУЖnnen, aber es dennoch zu AbstУМrzen kommen kann
-und wir keine GewУЄhr УМbernehmen. Davon abgesehen: Einige Spiele werden seit
-lУЄngerer Zeit unterstУМtzt und sollten in jeder neusten stabilen verУЖffentlichten
-Version ohne grУЖУŸere Probleme laufen. Sie kУЖnnen sich einen Eindruck davon
-verschaffen, wie gut jedes Spiel unter ScummVM lУЄuft, indem Sie auf die
-KompatibilitУЄtsseite schauen. Wenn Sie sich ein wenig im Internet umsehen,
-kУЖnnen Sie feststellen, dass ScummVM sogar kommerziell genutzt wird, um einige
-der unterstУМtzen Spiele fУМr moderne Plattformen wiederzuverУЖffentlichen. Dies
-zeigt, dass mehrere Firmen mit der QualitУЄt der Software zufrieden sind und wie
-gut einige der Spiele mit Hilfe des Programms laufen.
+sich bewusst, dass wir zwar versuchen, viele Spiele ohne grУЖУŸere Probleme
+spielbar zu machen т€“ dennoch kann es zu AbstУМrzen kommen und wir УМbernehmen
+keinerlei GewУЄhr. Davon abgesehen: Einige Spiele werden seit lУЄngerer Zeit
+unterstУМtzt und sollten in jeder neusten stabilen verУЖffentlichten Version ohne
+grУЖУŸere Probleme laufen. Sie kУЖnnen sich einen Eindruck davon verschaffen, wie
+gut jedes Spiel unter ScummVM lУЄuft, indem Sie auf die KompatibilitУЄtsseite
+schauen. Wenn Sie sich ein wenig im Internet umsehen, kУЖnnen Sie feststellen,
+dass ScummVM sogar kommerziell genutzt wird, um einige der unterstУМtzen Spiele
+fУМr moderne Plattformen wiederzuverУЖffentlichen. Dies zeigt, dass mehrere Firmen
+mit der QualitУЄt der Software zufrieden sind und wie gut einige der Spiele mit
+Hilfe des Programms laufen.
Wenn Ihnen ScummVM gefУЄllt, kУЖnnen Sie uns gerne Geld spenden, indem Sie auf die
PayPal-SchaltflУЄche auf der ScummVM-Website klicken. Dies hilft uns dabei,
@@ -140,12 +141,12 @@ jedes Spiel ein eigenes Verzeichnis zu verwenden).
Sollte an diesem Punkt ScummVM auf Englisch statt auf Deutsch erscheinen, gehen
Sie wie folgt vor, um die Spracheinstellung zu УЄndern:
--Klicken Sie auf т€žOptionsт€œ.
--Klicken Sie auf den rechten Pfeil in der Reiterleiste und wУЄhlen den Reiter
+- Klicken Sie auf т€žOptionsт€œ.
+- Klicken Sie auf den rechten Pfeil in der Reiterleiste und wУЄhlen den Reiter
т€žMiscт€œ aus.
--WУЄhlen Sie im Feld т€žGUI Languageт€œ т€žDeutschт€œ aus und klicken auf т€žOKт€œ.
--BestУЄtigen Sie die erscheinende Nachricht, klicken auf т€žQuitт€œ, um ScummVM zu
- beenden, und starten dann das Programm erneut.
+- WУЄhlen Sie im Feld т€žGUI Languageт€œ т€žDeutschт€œ aus und klicken auf т€žOKт€œ.
+- BestУЄtigen Sie die erscheinende Nachricht, klicken auf т€žQuitт€œ, um ScummVM zu
+ beenden, und starten dann das Programm erneut.
Nun klicken Sie auf т€žSpiel hinzufУМgenт€œ, wУЄhlen das Verzeichnis mit den Dateien
des Spiels aus (versuchen Sie nicht, die Dateien des Spiels selbst auszuwУЄhlen!)
@@ -165,10 +166,10 @@ hinzugefУМgt haben, in der Liste angezeigt. Sie kУЖnnen somit direkt zu Schritt
Tipp: Wenn Sie mehrere Spiele auf einmal hinzufУМgen mУЖchten, drУМcken Sie die
Umschalt-Taste (Shift), bevor Sie auf т€žSpiel hinzufУМgenт€œ klicken. Diese
-SchaltflУЄche wird somit ihren Text zu т€žDurchsuchenт€œ umУЄndern und wenn Sie dann
-auf diese klicken, werden Sie auch dazu aufgefordert, ein Verzeichnis
-auszuwУЄhlen, nur dieses Mal wird ScummVM alle Unterverzeichnisse automatisch
-nach unterstУМtzen Spielen durchsuchen.
+SchaltflУЄche wird dann ihren Text zu т€žDurchsuchenт€œ УЄndern. Wenn Sie dann auf
+diese klicken, werden Sie auch dazu aufgefordert, ein Verzeichnis auszuwУЄhlen,
+nur dieses Mal wird ScummVM alle Unterverzeichnisse automatisch nach
+unterstУМtzen Spielen durchsuchen.
2.0) Kontakt:
@@ -189,8 +190,8 @@ sollte.
---- -----------------
Um einen Fehler zu berichten, erstellen Sie bitte ein SourceForge-Konto und
folgen Sie dem Link т€žBug Trackerт€œ auf der ScummVM-Website. Bitte stellen Sie
-sicher, dass sich der Bug wiedererzeugen lУЄsst und immer noch in der neusten
-Version von Git oder des Daily Builds auftritt. Bitte sehen Sie auch auf der
+sicher, dass sich der Bug reproduzieren lУЄsst und immer noch in der aktuellen
+Git-Version oder im Daily Build auftritt. Bitte sehen Sie auch auf der
KompatibilitУЄtsliste der ScummVM-Website fУМr dieses Spiel nach, um
sicherzustellen, dass das Problem nicht bereits bekannt ist:
@@ -209,22 +210,22 @@ Bitte liefern Sie folgende Informationen:
- Version des Spiels (Version mit Sprachausgabe [Talkie],
Diskettenversion, ...)
- Plattform und gegebenenfalls Compiler (Win32, Linux, FreeBSD, ...)
- - FУМgen Sie - wenn mУЖglich - einen Speicherstand hinzu.
+ - FУМgen Sie т€“ wenn mУЖglich т€“ einen Speicherstand hinzu.
- Wenn dieser Fehler erst seit kurzem Auftritt, teilen Sie bitte die letzte
Version ohne den Fehler mit und die erste Version mit diesem Fehler.
Auf diese Weise kУЖnnen wir diesen schneller beseitigen, indem wir die
vorgenommen VerУЄnderungen einsehen.
-Zum Schluss mУЖchten wir Sie noch bitten, jeden Punkt einzeln zu berichten. Bitte
-senden Sie nicht mehrere Punkte mit demselben Ticket ein, ansonsten wird es
+Zum Schluss mУЖchten wir Sie noch bitten, jeden Fehler einzeln zu melden. Bitte
+senden Sie nicht mehrere Fehler in demselben Ticket ein, ansonsten wird es
schwierig, den Status jedes einzelnen Fehlers zu verfolgen. Denken Sie bitte
auch daran, dass alle Fehlerberichte in Englisch verfasst sein mУМssen.
3.0) UnterstУМtzte Spiele:
---- --------------------
-Im Moment gelten folgende Spiele als funktionsfУЄhig gemeldet und sollten bis zum
-Ende spielbar sein:
+Im Moment gelten folgende Spiele als funktionsfУЄhig und sollten bis zum Ende
+spielbar sein:
SCUMM-Spiele von LucasArts:
Maniac Mansion [maniac]
@@ -240,7 +241,7 @@ SCUMM-Spiele von LucasArts:
The Dig [dig]
The Curse of Monkey Island [comi]
-AGI-Spiele von Sierra:
+AGI- und preAGI-Spiele von Sierra:
The Black Cauldron [bc]
Gold Rush! [goldrush]
King's Quest I [kq1]
@@ -256,7 +257,10 @@ AGI-Spiele von Sierra:
Angel [pq1]
Space Quest I: The Sarien Encounter [sq1]
Space Quest II: Vohaul's Revenge [sq2]
- Erstellte Spiele von Fans [agi-fanmade]
+ Von Fans erstellte Spiele [agi-fanmade]
+ Mickey's Space Adventure [mickey]
+ Troll's Tale [troll]
+ Winnie the Pooh in the Hundred Acre Wood [winnie]
AGOS-Spiele von Adventuresoft/Horrorsoft:
Elvira - Mistress of the Dark [elvira1]
@@ -275,6 +279,13 @@ AGOS-Spiele von Adventuresoft/Horrorsoft:
- 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]
+
GOB-Spiele von Coktel Vision:
Bambou le sauveur de la jungle [bambou]
Bargon Attack [bargon]
@@ -289,6 +300,22 @@ GOB-Spiele von Coktel Vision:
Woodruff and the Schnibble of Azimuth [woodruff]
Ween: The Prophecy [ween]
+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]
@@ -296,35 +323,105 @@ MADE-Spiele von Activision:
The Manhole [manhole]
Andere Spiele:
- Beneath a Steel Sky [sky]
+ 3 Skulls of the Toltecs [toltecs]
Baphomets Fluch [sword1]
Baphomets Fluch II:
Die Spiegel der Finsternis [sword2]
+ 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]
- Erben der Erde: Die groУŸe Suche [ite]
- Nippon Safes Inc. [nippon]
+ 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]
+ 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:
+ Codename: ICEMAN [iceman]
+ Conquests of Camelot [camelot]
+ Conquests of the Longbow [longbow]
+ Das SchloУŸ von Dr. Brain [castlebrain]
+ EcoQuest: Die Suche nach Cetus [ecoquest]
+ EcoQuest 2: Lost Secret of the Rainforest [ecoquest2]
+ Freddy Pharkas: Cowboy-Apotheker [freddypharkas]
+ Hoyle's Book of Games 1 [hoyle1]
+ Hoyle's Book of Games 2 [hoyle2]
+ Hoyle's Book of Games 3 [hoyle3]
+ Hoyle Classic Card Games [hoyle4]
+ Jones in the Fast Lane [jones]
+ King's Quest I [kq1sci]
+ King's Quest IV [kq4sci]
+ King's Quest V [kq5]
+ King's Quest VI [kq6]
+ Laura Bow: The Colonel's Bequest [laurabow]
+ Laura Bow 2: Der Dolch des Amon Ra [laurabow2]
+ Leisure Suit Larry 1 [lsl1sci]
+ Leisure Suit Larry 2 [lsl2]
+ Leisure Suit Larry 3 [lsl3]
+ Leisure Suit Larry 5 [lsl5]
+ Leisure Suit Larry 6 [lsl6]
+ Mixed-up Fairy Tales [fairytales]
+ Mixed-up Mother Goose [mothergoose]
+ Pepper's Adventures in Time [pepper]
+ Police Quest 1 [pq1sci]
+ Police Quest 2 [pq2]
+ Police Quest 3 [pq3]
+ Quest for Glory 1/Hero's Quest [qfg1]
+ Quest for Glory 1 [qfg1vga]
+ Quest for Glory 2 [qfg2]
+ Quest for Glory 3 [qfg3]
+ Slater & Charlie Go Camping [slater]
+ Space Quest I [sq1sci]
+ Space Quest III [sq3]
+ Space Quest IV [sq4]
+ Space Quest V [sq5]
+ The Island of Dr. Brain [islandbrain]
+
+Wintermute-Spiel von Deirdra Kiai Productions:
+ Chivalry is Not Dead [chivalry]
+
+ZVISION-Spiele von Activision:
+ Zork Nemesis: The Forbidden Lands [znemesis]
+ Zork: Grand Inquisitor [zgi]
SCUMM-Spiele von Humongous Entertainment:
Backyard Baseball [baseball]
Backyard Baseball 2001 [baseball2001]
+ Backyard Football 2002 [football2002]
Backyard Baseball 2003 [baseball2003]
Backyard Football [football]
+ Bear Stormin' [brstorm]
Big Thinkers First Grade [thinker1]
Big Thinkers Kindergarten [thinkerk]
Blue's 123 Time Activities [Blues123Time]
@@ -347,6 +444,7 @@ SCUMM-Spiele von 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]
Pyjama Pit: Keine Angst im Dunkeln [pajama]
Pyjama Sam: Donner und Blitz
machen mir nix [pajama2]
@@ -369,22 +467,6 @@ SCUMM-Spiele von Humongous Entertainment:
SPY Fox in Cheese Chase [chase]
SPY Fox in Hold the Mustard [mustard]
-Spiele von 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]
-
Die folgenden Spiele sollten geladen werden, sind aber noch nicht vollstУЄndig
spielbar. Spielen erfolgt auf eigenes Risiko. Bitte reichen Sie fУМr diese Spiele
keine Fehlerberichte ein.
@@ -392,17 +474,15 @@ Wenn Sie УМber den neusten Stand bezУМglich der KompatibilitУЄt des Spiels erfah
mУЖchten, besuchen Sie unsere Website und schauen Sie in der KompatibilitУЄtsliste
nach.
- Backyard Football 2002 [football2002]
Backyard Soccer [soccer]
Backyard Soccer MLS [soccermls]
Backyard Soccer 2004 [soccer2004]
Blue's Treasure Hunt [BluesTreasureHunt]
- Pajama Sam: Games to Play on Any Day [pjgames]
Die folgenden Spiele basieren auf der SCUMM-Engine, werden aber (noch) nicht von
ScummVM unterstУМtzt:
- Andere Spiele von Humongous Entertainment
+ Moonbase Commander
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
@@ -451,8 +531,31 @@ ScummVM wird den Kopierschutz in folgenden Spielen УМberspringen:
* Zak McKracken and the Alien Mindbenders
-3.2) Hinweise zu Commodore64-Spielen:
----- --------------------------------
+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.
+
+Um zu Day of the Tentacle zurУМckzukehren, drУМcken Sie F5 und wУЄhlen Sie т€žZurУМck
+zum HauptmenУМт€œ.
+
+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 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
@@ -461,13 +564,13 @@ das richtige Verzeichnis zeigen.
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 Commodore64 als
+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.3) Hinweise zu Maniac Mansion NES:
----- -------------------------------
+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.
@@ -496,7 +599,7 @@ extrahieren. Um dies zu tun, verwenden Sie das Dienstprogramm т€žextract_mm_nesт
aus dem Tools-Paket.
-3.4) Hinweise zu Macintosh-Spielen:
+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
@@ -526,7 +629,7 @@ Festplatte kopieren kУЖnnen, lesen Sie:
http://wiki.scummvm.org/index.php/HOWTO-Mac_Games
-3.5) Hinweise zu Spielen auf mehren CDs:
+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
@@ -543,7 +646,7 @@ vorkommt, ist es normalerweise egal, welche sie in das Verzeichnis
hineinkopieren.
-3.6) Hinweise zu The Curse of Monkey Island:
+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
@@ -555,7 +658,7 @@ dieser Dateien lassen sich auf beiden CDs vorfinden, jedoch sind sie auch in
diesem Fall identisch.
-3.7) Hinweise zu Baphomets Fluch I und II:
+3.8) 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
@@ -564,7 +667,7 @@ fУМr diese Spiele erlangte. Wir hoffen, dass sie allgemein ausreichend
ausfУМhrlich sind, um fУМr andere Ausgaben genauso hilfreich zu sein.
-3.7.1) Zwischensequenzen von Baphomets Fluch I und II:
+3.8.1) 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
@@ -610,7 +713,7 @@ funktioniert momentan nicht bei der Verwendung von PlayStation-Videos.
Arbeit notwendig.)
-3.7.2) Zwischensequenzen von Baphomets Fluch I und II im RУМckblick:
+3.8.2) 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
@@ -623,7 +726,7 @@ nie die alleinige LУЖsung fУМr eine stabile VerУЖffentlichung.
In ScummVM 0.6.0 verwendeten wir MPEG, das einen zumutbaren Kompromiss zwischen
GrУЖУŸe und QualitУЄt bot. In ScummVM 0.10.0 wurde dies durch DXA abgelУЖst (das
-ursprУМnglich fУМr Adventure Softs т€žFloyd - Es gibt noch Heldenт€œ hinzugefУМgt
+ursprУМnglich fУМr Adventure Softs т€žFloyd т€“ Es gibt noch Heldenт€œ hinzugefУМgt
wurde). Dies gab uns die MУЖglichkeit, die Zwischensequenzen mit genau derselben
QualitУЄt wie im Original anzubieten, zu dem Preis, dass die Dateien grУЖУŸer
waren.
@@ -636,7 +739,7 @@ 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.7.3) Baphomets Fluch:
+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
@@ -653,7 +756,7 @@ Unterschied macht. Die PlayStation-Version erfordert die Dateien tunes.dat und
tunes.tab.
-3.7.4) Baphomets Fluch II:
+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,
@@ -668,7 +771,7 @@ ZusУЄtzlich brauchen Sie die Datei cd.inf und optional die Datei startup.inf aus
dem Verzeichnis sword2 von CD 1.
-3.8) Hinweise zu Beneath a Steel Sky:
+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.
@@ -679,8 +782,8 @@ SKY.DSK) ablegen, in einem Extrapfad oder im Verzeichnis, in dem sich Ihre
ausfУМhrbare ScummVM-Datei befindet.
-3.9) Hinweise zu Flight of the Amazon Queen:
----- ---------------------------------------
+3.10) Hinweise zu Flight of the Amazon Queen:
+----- ---------------------------------------
Um eine Nicht-Freeware-Version von Flight of the Amazon Queen zu verwenden (von
einer Original-CD), mУМssen Sie die Datei т€žqueen.tblт€œ (erhУЄltlich von der Seite
т€žDownloadsт€œ auf unserer Website) entweder im Verzeichnis mit der Spieldatei
@@ -694,7 +797,7 @@ Datei т€žqueen.tblт€œ zu lУЖsen. Dieses Tool kann auch die Sprachausgabe und
GerУЄusch-Effekte mittels MP3, Ogg Vorbis oder FLAC komprimieren.
-3.10) Hinweise zu Gobliiins:
+3.11) Hinweise zu Gobliiins:
----- ----------------------
Die CD-Versionen der Gobliiins-Serie enthalten einen groУŸen Audio-Titel, den Sie
extrahieren mУМssen (siehe Abschnitt УМber die Verwendung komprimierter
@@ -704,11 +807,11 @@ Sprachausgabe ist auch in diesem Titel und ihre LautstУЄrke wird deshalb ebenso
УМber die MusiklautstУЄrke-Regelung geУЄndert.
-3.11) Hinweise zu Inherit the Earth: Quest for the Orb (Macintosh):
+3.12) Hinweise zu Inherit the Earth: Quest for the Orb (Macintosh):
----- -------------------------------------------------------------
-Um die Neuausgabe des Spiels fУМr Mac OS X von Wyrmkeep laufen zu lassen, mУМssen
-Sie die Daten von der CD auf die Festplatte kopieren. Wenn Sie an einem PC
-arbeiten, lesen Sie hierfУМr:
+Um die WiederverУЖffentlichung des Spiels fУМr Mac OS X von Wyrmkeep laufen zu
+lassen, mУМssen Sie die Daten von der CD auf die Festplatte kopieren. Wenn Sie an
+einem PC arbeiten, lesen Sie hierfУМr:
http://wiki.scummvm.org/index.php/HOWTO-Mac_Games
@@ -725,16 +828,16 @@ kopieren, da sie sowohl Ressourcen- als auch Datenverzweigungen beinhalten
sollten. Kopieren Sie alle т€žITE *т€œ-Dateien.
-3.12) Hinweise zu Simon the Sorcerer 1 und 2:
+3.13) 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.13) Hinweise zu Floyd - Es gibt noch Helden:
+3.14) Hinweise zu Floyd т€“ Es gibt noch Helden:
----- ----------------------------------------
-Wenn Sie die Windows-Version von Floyd - Es gibt noch Helden haben, sind einige
+Wenn Sie die Windows-Version von Floyd т€“ Es gibt noch Helden haben, sind einige
Dinge zu beachten.
Viele notwendige Dateien fУМr das Spiel sind in einer InstallShield-Datei namens
@@ -751,7 +854,7 @@ voices.wav von CD3 in voices3.wav
voices.wav von CD4 in voices4.wav
-3.14) Hinweise zu The Legend of Kyrandia:
+3.15) 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
@@ -762,7 +865,7 @@ eingebettet sein sollte. Also mУМssen Sie sich nur diese besorgen, wenn sich
ScummVM darУМber beschwert, dass diese Datei fehlt.
-3.15) Hinweise zum vorhersagenden Eingabedialog bei Sierras AGI-Spielen:
+3.16) 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
@@ -821,7 +924,7 @@ Ziffernblock zugewiesen wurde. Ebenso kУЖnnen die SchaltflУЄchen mittels der
Pfeiltasten und der Eingabetaste gesteuert werden.
-3.16) Hinweise zu Mickey's Space Adventure:
+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.
@@ -836,7 +939,7 @@ Ort zu wechseln, УЄhnlich wie in vielen Adventures, was einfacher und viel
unkomplizierter ist, als sich mit dem MenУМ umherzubewegen.
-3.17) Hinweise zu Winnie the Pooh:
+3.18) Hinweise zu Winnie the Pooh:
----- ----------------------------
Es ist mУЖglich, SpielstУЄnde vom Original-Interpreter des Spiels in ScummVM zu
importieren.
@@ -851,14 +954,14 @@ Ort zu wechseln, УЄhnlich wie in vielen Adventures, was einfacher und viel
unkomplizierter ist, als sich mit dem MenУМ umherzubewegen.
-3.18) Hinweise zu Troll's Tale:
+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.19) Hinweise zu DraФi Historie:
+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
@@ -876,7 +979,7 @@ Alle Spieldateien und die KomplettlУЖsung kУЖnnen von der folgenden Website
heruntergeladen werden: http://www.ucw.cz/draci-historie/index-en.html
-3.20) Gleichzeitige Sprachausgabe und Untertitel in Sierra-SCI-Spielen:
+3.21) 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
@@ -919,9 +1022,6 @@ Laura Bow 2 CD:
werden.
Leisure Suit Larry 6 CD:
- Either speech only or speech and text can be selected. There is no
- in-game option to toggle text only. Only ScummVM's audio options can
- be used to enable the text only mode.
Es kann zwischen alleiniger Sprachausgabe und Sprachausgabe und Untertitel
gewУЄhlt werden. Es gibt innerhalb des Spiels keine Option, um alleinige
Untertitel zu aktivieren. Dies ist nur УМber ScummVMs Audio-Optionen mУЖglich.
@@ -932,7 +1032,7 @@ Space Quest 4 CD:
deaktiviert und aktiviert werden.
-3.21) Bekannte Probleme:
+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,
@@ -996,7 +1096,7 @@ KompatibilitУЄtsseite der Website aufgefУМhrt ist, sehen Sie bitte im Abschnitt
- 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:
+ Floyd т€“ Es gibt noch Helden:
- Untertitel sind oft unvollstУЄndig und nur in Englisch, da sie im
Originalspiel immer ausgeschaltet waren.
@@ -1067,6 +1167,11 @@ mehr als einem Ort aus zu verwenden. Weitere Informationen, einschlieУŸlich
darУМber, wie man einen Pfad fУМr SpielstУЄnde bestimmt, um diesen Sachverhalt zu
vermeiden, befinden sich im Abschnitt 6.0.
+Hinweis: Wird ScummVM auf einem Rechner mit dem Betriebssystem Microsoft
+Windows NT4/2000/XP/Vista/7/8/10 ausgefУМhrt, werden die Spielstand-Dateien ab
+ScummVM 1.5.0 standardmУЄУŸig im Verzeichnis т€ž%APPDATA%/ScummVM/Saved Gamesт€œ
+gespeichert.
+
ScummVM kann direkt durch Aufruf der ausfУМhrbaren Datei gestartet werden. In
diesem Fall wird das eingebaute StartmenУМ aktiviert. Hier kУЖnnen Sie Spiele
hinzufУМgen, (klicken Sie auf т€žSpiel hinzufУМgenт€œ) oder Spiele starten, die
@@ -1274,6 +1379,12 @@ Die einzelnen Grafikoptionen im Уœberblick:
hq3x - Sehr hochwertiger, qualitativer Filter, aber langsam. Faktor 3.
tv2x - Zeilensprungfilter, emuliert FernsehgerУЄt. Faktor 2.
dotmatrix - Punktraster-Effekt. Faktor 2.
+ OpenGL - Verwendet OpenGL zur Darstellung. Wirkt bei AuflУЖsung 320x200
+ etwas verwaschen, fУМr Spiele in 640x400 und hУЖher jedoch
+ empfohlen
+ OpenGL (ohne Filter) - Kein Filter, sehr scharfe Darstellung wenn Bildschirm
+ auf nativer AuflУЖsung betrieben wird. FУМr 640x400 und
+ hУЖher vielleicht etwas zu scharf.
Um einen Grafikfilter auszuwУЄhlen, stellen Sie diesen im StartmenУМ ein oder
УМbergeben Sie dessen Namen УМber die Option т€ž-gт€œ an scummvm, z. B. mit der
@@ -1340,6 +1451,7 @@ Die Engines, die momentan das ZurУМckkehren zur Spieleliste unterstУМtzen, sind:
TOUCHE
TSAGE
TUCKER
+ ZVISION
5.5) TastenkУМrzel:
@@ -1365,6 +1477,9 @@ zwischen SCUMM-Spielen und anderen Spielen.
Vielfaches davon.
Alt+Enter - Wechselt zwischen Vollbild- und Fenstermodus.
Alt+s - Macht Bildschirmfoto (nur fУМr SDL-System).
+ Strg+F7 - У–ffnet virtuelle Tastatur (falls aktiviert).
+ Diese kann auch durch langes DrУМcken der mittleren
+ Maustaste bzw. des Mausrads aufgerufen werden.
SCUMM:
Strg 0-9 und Alt 0-9 - LУЄdt und speichert entsprechenden Speicherstand.
@@ -1442,6 +1557,9 @@ 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.
@@ -1544,8 +1662,8 @@ migration.bat kann verwendet werden, um die SpielstУЄnde vom alten
Standard-Verzeichnis in das neue zu kopieren.
-6.1) Automatische SpielstУЄnde:
----- -------------------------
+6.1) Automatische Speicherung der SpielstУЄnde:
+---- -----------------------------------------
Bei einigen Spielen (nУЄmlich т€žBeneath a Steel Skyт€œ, т€žFlight of the Amazon
Queenт€œ, allen AGI-Spielen und allen SCUMM-Spielen) wird ScummVM standardmУЄУŸig
automatisch alle fУМnf Minuten den momentanen Spielstand speichern (УМber die
@@ -1555,7 +1673,7 @@ 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 in einem versteckten
+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.
@@ -1683,7 +1801,7 @@ abhУЄngt.
null - Keine Ausgabe. Spielt keinerlei Musik ab.
adlib - Interne AdLib-Emulation
- fluidsynth - FluidSynth-MIDI-Emulation
+ fluidsynth т€“ FluidSynth-MIDI-Emulation
mt32 - Interne MT-32-Emulation
pcjr - Interne PCjr-Emulation (nur in SCUMM-Spielen verwendbar)
pcspk - Interne PC-Lautsprecher-Emulation
@@ -1760,7 +1878,7 @@ Einige Spiele (wie beispielsweise Sam & Max) beinhalten nur MIDI-Musikdaten.
Einst hat dies verhindert, Musik in diesen Spielen auf Plattformen
wiederzugeben, auf welchen MIDI nicht unterstУМtzt wird oder auf Soundkarten, die
keine MIDI-Treiber bereitstellen (z. B. kУЖnnen viele Soundkarten MIDI unter
-Linux nicht abspielen). ScummVM kann nun den MIDI-Modus emulieren mittels
+Linux nicht abspielen). ScummVM kann nun den MIDI-Modus emulieren, mittels
abgetasteter Wellen und AdLib, FluidSynth-MIDI-Emulation oder MT-32-Emulation
entsprechend УМber die Option -eadlib, -efluidsynth oder -emt32. Wenn Sie jedoch
in der Lage sind, natives MIDI zu verwenden, empfehlen wir zur Erzielung von
@@ -2289,11 +2407,16 @@ Die folgenden SchlУМsselwУЖrter werden erkannt:
boot_param Zahl Ruft Boot-Skript mit dieser Nummer auf.
Sierra-Spiele, welche die AGI-Engine verwenden, verfУМgen zusУЄtzlich УМber
-folgendes nicht standardmУЄУŸiges SchlУМsselwort:
+folgende nicht standardmУЄУŸige SchlУМsselwУЖrter:
originalsaveload Bool Falls т€žtrueт€œ, werden die originalen MenУМs zum
- Speichern und Laden statt der
- erweiterten von ScummVM verwendet.
+ Speichern und Laden statt der erweiterten
+ von ScummVM verwendet.
+ altamigapalette Bool Verwendet eine alternative Farbpalette fУМr alle
+ Amiga-Spiele. Dies war das alte Verhalten.
+ mousesupport Bool Aktiviert Maus-UnterstУМtzung. Erlaubt die
+ Verwendung einer Maus zur Bewegung und innerhalb
+ von Spiele-MenУМs.
Sierra-Spiele, welche die SCI-Engine verwenden, verfУМgen zusУЄtzlich УМber
folgende nicht standardmУЄУŸige SchlУМsselwУЖrter:
@@ -2309,6 +2432,15 @@ folgende nicht standardmУЄУŸige SchlУМsselwУЖrter:
der Musiktreiber fУМr eine Music-Feature-Karte
von IBM oder fУМr ein Yamaha-FB-01-FM-
Synthetisierungsmodul verwendet.
+ use_cdaudio Bool Verwende Ton von CD anstelle des spieleigenen,
+ sofern verfУМgbar.
+ windows_cursors Bool Falls т€žtrueт€œ, werden die originalen
+ unskalierten, schwarz-weiУŸen Windows-Zeiger
+ anstatt der von DOS verwendet (King's Quest 6).
+ silver_cursors Bool Falls т€žtrueт€œ, wird ein alternativer Satz
+ silberner Mauszeiger verwendet anstatt der
+ originalen goldenen (Space Quest 4).
+
Baphomets Fluch II verfУМgt zusУЄtzlich УМber folgende nicht standardmУЄУŸige
SchlУМsselwУЖrter:
@@ -2422,6 +2554,20 @@ 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
+standardmУЄУŸige SchlУМsselwУЖrter:
+
+ 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
---- ---------------------------------------------------------------
@@ -2464,24 +2610,24 @@ Debug-Nachrichten zu durchsuchen
GCC und MinGW32:
* Geben Sie т€ž./configureт€œ ein.
- * Geben Sie т€žmakeт€œ ein (oder т€žgmakeт€œ bzw. т€žgnumakeт€œ, abhУЄngig davon, auf
- welchem GNU der Befehl т€žmakeт€œ auf Ihrem System aufgerufen wird) und mit
+ * 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++ 8/9/10:
- * Lesen Sie nach, wie man die Projektmappendatei in т€ždists\msvc8т€œ bzw.
- entsprechend in т€ždists\msvc9т€œ oder т€ždists\msvc10т€œ erstellt.
+ 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:
- http://wiki.scummvm.org/index.php/Compiling_ScummVM/VS2005
+ http://wiki.scummvm.org/index.php/Compiling_ScummVM/Visual_Studio
Windows Mobile:
* Bitte lesen Sie:
diff --git a/doc/de/Neues b/doc/de/Neues
index 8858e86c02..2b67913359 100644
--- a/doc/de/Neues
+++ b/doc/de/Neues
@@ -2,6 +2,60 @@ Umfangreichere У„nderungsaufzeichnungen des neusten experimentellen Codes finden
Sie auf Englisch unter:
https://github.com/scummvm/scummvm/commits/
+1.8.0 (??.??.????)
+ 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.
+
+ Allgemein:
+ - Code fУМr Munt-MT-32-Emulation auf Version 1.5.0 aktualisiert.
+
+ 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).
+
+ AGOS:
+ - Arpeggio-Effekt in der Musik der Amiga-Version von Elvira 1 repariert.
+ - Lade- und Speicherfortschritt in der PC-Version von Waxworks repariert.
+ - 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)
+
+ 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.
+
+ MADE:
+ - UnterstУМtzung fУМr AdLib-Musik in Return to Zork verbessert.
+
+ SAGA:
+ - UnterstУМtzung fУМr AdLib-Musik verbessert.
+
+ 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)
+ - RУМckkehr aus dem ScummVM-MenУМ im Spiel sollte nun immer funktionieren.
+ - Verbesserte UnterstУМtzung fУМr japanische PC-9801-Spiele
+
+ SCUMM:
+ - Es ist nun mУЖglich, Maniac Mansion innerhalb von Day of the
+ Tentacle zu spielen. Bitte Liesmich-Datei fУМr weitere Details lesen.
+
+ Tinsel:
+ - UnterstУМtzung fУМr AdLib-Musik in Discworld 1 verbessert.
+
1.7.0 (21.07.2014)
Neue Spiele:
- UnterstУМtzung fУМr Chivalry is Not Dead hinzugefУМgt.
@@ -11,17 +65,27 @@ Sie auf Englisch unter:
- UnterstУМtzung fУМr Voyeur hinzugefУМgt.
Allgemein:
- - Munt-MT-32-Emulationscode zu Version 1.3.0 aktualisiert.
+ - Munt-MT-32-Emulationscode zu Version 1.4.0 aktualisiert.
- Von unseren eigenen JPEG- und PNG-Dekodieren zu libjpeg(-turbo) und libpng
gewechselt, welche schneller sind und mehr Bilder verarbeiten kУЖnnen.
(HINWEIS: Der Wechsel zu libpng fand bereits in Version 1.6.0 statt, wurde
jedoch nicht in der Datei NEUES erwУЄhnt.)
+ - Allgemeine Ausgabe fУМr OpenGL (ES) hinzugefУМgt (basierend auf
+ GSoC-Aufgabe).
+ - Die BenutzeroberflУЄche kann jetzt mit 32 Bit Farbentiefe gerendert werden.
+ - Das Kompilierungssystem wurde baukastenartiger gemacht, damit es einfacher
+ ist, neue Engines hinzuzufУМgen.
+
+ SDL:
+ - OpenGL-Grafikmodus hinzugefУМgt, der auf unserer allgemeinen OpenGL-Ausgabe
+ basiert. Damit ist Grafikausgabe in beliebiger GrУЖУŸe mУЖglich. Dieser
+ unterstУМtzt jedoch nicht Spezialfilter wie AdvMAME, HQ usw.
AGOS:
- UnterstУМtzung fУМr Mausrad bei Inventar und Spielstandliste hinzugefУМgt.
- Anzeige der Interaktionsverben in Simon the Sorcerer 2 aktiviert.
- Fehler bei LoyalitУЄtseinstufung in englischer 4CD-Version von
- Floyd - Es gibt noch Helden beseitigt. (Dies war offensichtlich ein Fehler
+ Floyd т€“ Es gibt noch Helden beseitigt. (Dies war offensichtlich ein Fehler
im ursprУМnglichen Spiel. Es ist zurzeit nicht bekannt, ob noch weitere
Versionen hiervon betroffen sind.)
@@ -42,6 +106,11 @@ Sie auf Englisch unter:
- Fehler beseitigt, durch welchen die Musik manchmal vorzeitig zu spielen
aufhУЖrte.
+ Pegasus:
+ - Mehrere seltene AbstУМrze und StУЖrungen beseitigt
+ - Mehrere Fehler beseitigt, die aus der ausfУМhrbaren Datei des Originalspiels
+ УМbernommen wurden.
+
SCI:
- UnterstУМtzung fУМr die detailreicheren RAVE-Lippensynchronisationsdaten in
der Windows-Version von Kingт€™s Quest 6 hinzugefУМgt. Portraits wirken beim
@@ -62,10 +131,31 @@ SCUMM:
- AdLib-UnterstУМtzung fУМr Loom und Indiana Jones and the Last Crusade
verbessert. Dadurch klingen GerУЄusch-Effekte wie beispielsweise von der
Schreibmaschine und vom Wasserfall wie im Original.
+ - UnterstУМtzung fУМr Steam-Versionen von Indiana Jones and the Last Crusade,
+ Indiana Jones and the Fate of Atlantis, Loom und The Dig hinzugefУМgt.
+ Sowohl Windows- als auch Macintosh-Versionen werden unterstУМtzt.
+
+ TONY:
+ - SpielstУЄnde von Tony Tough funktionieren nun auf Big-Endian-Systemen.
Tinsel:
- Discworld 1 und 2 stУМrzen nicht mehr auf Big-Endian-Systemen ab.
+ Android-Portierung:
+ - Experimentelle UnterstУМtzung fУМr die OUYA-Konsole hinzugefУМgt.
+
+ PS2-Portierung:
+ - Konfigurierbare TV-Modi hinzugefУМgt: NTSC und PAL.
+ - Konfigurierbare Grafikmodi hinzugefУМgt: SDTV stufenweise, SDTV
+ Zeilensprung, EDTV stufenweise und VESA.
+ - Konfigurierbare Option fУМr zu verwendende Festplattenpartition hinzugefУМgt
+ - Konfigurierbare Option fУМr zu verwendende IP-Adresse hinzugefУМgt.
+ - Konfigurierbare Option zum Aktivieren und Deaktivieren von
+ USB-MassenspeichergerУЄten hinzugefУМgt.
+
+ Tizen-Portierung:
+ - Die BADA-Portierung wurde mit Tizen zusammengefУМhrt/aktualisiert.
+
1.6.0 (31.05.2013)
Neue Spiele:
- UnterstУМtzung fУМr 3 Skulls of the Toltecs hinzugefУМgt.
@@ -555,7 +645,7 @@ SCUMM:
- UnterstУМtzung fУМr King's Quest VI (hohe und niedrige AuflУЖsung)
hinzugefУМgt.
- UnterstУМtzung fУМr Laura Bow: The Colonel's Bequest hinzugefУМgt.
- - UnterstУМtzung fУМr Laura Bow 2: The Dagger of Amon Ra hinzugefУМgt.
+ - UnterstУМtzung fУМr Laura Bow 2: Der Dolch des Amon Ra hinzugefУМgt.
- UnterstУМtzung fУМr Leisure Suit Larry 1 (SCI-Remake) (EGA und VGA)
hinzugefУМgt.
- UnterstУМtzung fУМr Leisure Suit Larry 2 hinzugefУМgt.
diff --git a/doc/de/Spieletitel Original-Deutsch Deutsch-Original b/doc/de/Spieletitel Original-Deutsch Deutsch-Original
new file mode 100644
index 0000000000..80719079cf
--- /dev/null
+++ b/doc/de/Spieletitel Original-Deutsch Deutsch-Original
@@ -0,0 +1,61 @@
+яЛПOriginal - Deutsch (bzw. Titel in Deutschland):
+Broken Sword: The Shadow of the Templars = Baphomets Fluch
+Broken Sword II: The Smoking Mirror = Baphomets Fluch II: Die Spiegel der Finsternis
+Castle of Dr. Brain = Das SchloУŸ von Dr. Brain
+Darby the Dragon = Darby der Drache
+Discworld 2: Missing Presumed ...!? = Discworld 2: Vermutlich vermisst
+EcoQuest: The Search for Cetus = EcoQuest: Die Suche nach Cetus
+Freddi Fish 1: The Case of the Missing Kelp Seeds = Fritzi Fisch und der verschwundene Schatz
+Freddi Fish 2: The Case of the Haunted Schoolhouse = Fritzi Fisch und das Flossengespenst
+Freddi Fish 3: The Case of the Stolen Conch Shell = Fritzi Fisch und der Fall der gestohlenen Trompetenschnecke
+Freddi Fish 4: The Case of the Hogfish Rustlers of Briny Gulch = Freddi Fisch und das Geheimnis der Salzwasserschlucht
+Freddi Fish 5: The Case of the Creature of Coral Cove = Freddi Fisch und das RУЄtsel der Korallenbucht
+Freddy Pharkas: Frontier Pharmacist = Freddy Pharkas: Cowboy-Apotheker
+Full Throttle = Vollgas
+Inherit the Earth: Quest for the Orb = Erben der Erde: Die groУŸe Suche
+Laura Bow 2: The Dagger of Amon Ra = Laura Bow 2: Der Dolch des Amon Ra
+Pajama Sam 1: No Need to Hide When It's Dark Outside = Pyjama Pit: Keine Angst im Dunkeln
+Pajama Sam 2: Thunder and Lightning Aren't so Frightening = Pyjama Sam: Donner und Blitz machen mir nix
+Pajama Sam 3: You Are What You Eat From Your Head to Your Feet = Pyjama Sam 3: SУМУŸigkeiten kriegen Saures
+Putt-Putt Enters the Race = TУЖff-TУЖff und das groУŸe Rennen
+Putt-Putt Joins the Circus = TУЖff-TУЖff geht zum Zirkus
+Putt-Putt Saves the Zoo = TУЖff-TУЖff rettet den Zoo
+Putt-Putt Travels Through Time = TУЖff-TУЖff reist durch die Zeit
+Simon the Sorcerer's Puzzle Pack = Simon the Sorcerer's Game Pack
+SPY Fox 1: Dry Cereal = SPY Fox: Das Milchkartell
+SPY Fox 2: Some Assembly Required = SPY Fox: Operation Robohund
+SPY Fox 3: Operation Ozone = SPY Fox: Alarm im Weltall
+The Bizarre Adventures of Woodruff and the Schnibble = Woodruff and the Schnibble of Azimuth
+The Feeble Files = Floyd - Es gibt noch Helden
+Touche: The Adventures of the Fifth Musketeer = TouchУЉ: Die Abenteuer des fУМnften Musketiers
+
+Deutsch (bzw. Titel in Deutschland) - Original:
+Baphomets Fluch = Broken Sword: The Shadow of the Templars
+Baphomets Fluch II: Die Spiegel der Finsternis = Broken Sword II: The Smoking Mirror
+Darby der Drache = Darby the Dragon
+Das SchloУŸ von Dr. Brain = Castle of Dr. Brain
+Discworld 2: Vermutlich vermisst = Discworld 2: Missing Presumed ...!?
+EcoQuest: Die Suche nach Cetus = EcoQuest: The Search for Cetus
+Erben der Erde: Die groУŸe Suche = Inherit the Earth: Quest for the Orb
+Floyd - Es gibt noch Helden = The Feeble Files
+Freddi Fisch und das Geheimnis der Salzwasserschlucht = Freddi Fish 4: The Case of the Hogfish Rustlers of Briny Gulch
+Freddi Fisch und das RУЄtsel der Korallenbucht = Freddi Fish 5: The Case of the Creature of Coral Cove
+Freddy Pharkas: Cowboy-Apotheker = Freddy Pharkas: Frontier Pharmacist
+Fritzi Fisch und das Flossengespenst = Freddi Fish 2: The Case of the Haunted Schoolhouse
+Fritzi Fisch und der Fall der gestohlenen Trompetenschnecke = Freddi Fish 3: The Case of the Stolen Conch Shell
+Fritzi Fisch und der verschwundene Schatz = Freddi Fish 1: The Case of the Missing Kelp Seeds
+Laura Bow 2: Der Dolch des Amon Ra = Laura Bow 2: The Dagger of Amon Ra
+Pyjama Pit: Keine Angst im Dunkeln = Pajama Sam 1: No Need to Hide When It's Dark Outside
+Pyjama Sam 3: SУМУŸigkeiten kriegen Saures = Pajama Sam 3: You Are What You Eat From Your Head to Your Feet
+Pyjama Sam: Donner und Blitz machen mir nix = Pajama Sam 2: Thunder and Lightning Aren't so Frightening
+Simon the Sorcerer's Game Pack = Simon the Sorcerer's Puzzle Pack
+SPY Fox: Alarm im Weltall = SPY Fox 3: Operation Ozone
+SPY Fox: Das Milchkartell = SPY Fox 1: Dry Cereal
+SPY Fox: Operation Robohund = SPY Fox 2: Some Assembly Required
+TУЖff-TУЖff geht zum Zirkus = Putt-Putt Joins the Circus
+TУЖff-TУЖff reist durch die Zeit = Putt-Putt Travels Through Time
+TУЖff-TУЖff rettet den Zoo = Putt-Putt Saves the Zoo
+TУЖff-TУЖff und das groУŸe Rennen = Putt-Putt Enters the Race
+TouchУЉ: Die Abenteuer des fУМnften Musketiers = Touche: The Adventures of the Fifth Musketeer
+Vollgas = Full Throttle
+Woodruff and the Schnibble of Azimuth = The Bizarre Adventures of Woodruff and the Schnibble
diff --git a/engines/access/access.cpp b/engines/access/access.cpp
index 0a4e519c91..56fa6c7533 100644
--- a/engines/access/access.cpp
+++ b/engines/access/access.cpp
@@ -52,11 +52,10 @@ AccessEngine::AccessEngine(OSystem *syst, const AccessGameDescription *gameDesc)
_destIn = nullptr;
_current = nullptr;
_mouseMode = 0;
+ _playerDataCount = 0;
_currentMan = 0;
_currentManOld = -1;
_converseMode = 0;
- _startAboutBox = 0;
- _startTravelBox = 0;
_numAnimTimers = 0;
_startup = 0;
_currentCharFlag = false;
@@ -97,11 +96,33 @@ AccessEngine::AccessEngine(OSystem *syst, const AccessGameDescription *gameDesc)
for (int i = 0; i < 100; i++)
_objectsTable[i] = nullptr;
_clearSummaryFlag = false;
+
+ for (int i = 0; i < 60; i++)
+ _travel[i] = 0;
+ _startTravelItem = _startTravelBox = 0;
+ for (int i = 0; i < 33; i++)
+ _ask[i] = 0;
+ _startAboutItem = _startAboutBox = 0;
+ _byte26CB5 = 0;
+ _bcnt = 0;
+ _boxDataStart = 0;
+ _boxDataEnd = false;
+ _boxSelectY = 0;
+ _boxSelectYOld = -1;
+ _numLines = 0;
+ _tempList = nullptr;
+ _pictureTaken = 0;
+
+ _vidEnd = false;
}
AccessEngine::~AccessEngine() {
delete _animation;
delete _bubbleBox;
+ delete _helpBox;
+ delete _travelBox;
+ delete _invBox;
+ delete _aboutBox;
delete _char;
delete _debugger;
delete _events;
@@ -147,7 +168,18 @@ void AccessEngine::initialize() {
// Create sub-objects of the engine
_animation = new AnimationManager(this);
- _bubbleBox = new BubbleBox(this);
+ _bubbleBox = new BubbleBox(this, TYPE_2, 64, 32, 130, 122, 0, 0, 0, 0, "");
+ if (getGameID() == GType_MartianMemorandum) {
+ _helpBox = new BubbleBox(this, TYPE_1, 64, 24, 146, 122, 1, 32, 2, 76, "HELP");
+ _travelBox = new BubbleBox(this, TYPE_1, 64, 32, 194, 122, 1, 24, 2, 74, "TRAVEL");
+ _invBox = new BubbleBox(this, TYPE_1, 64, 32, 146, 122, 1, 32, 2, 76, "INVENTORY");
+ _aboutBox = new BubbleBox(this, TYPE_1, 64, 32, 194, 122, 1, 32, 2, 76, "ASK ABOUT");
+ } else {
+ _helpBox = nullptr;
+ _travelBox = nullptr;
+ _invBox = nullptr;
+ _aboutBox = nullptr;
+ }
_char = new CharManager(this);
_debugger = Debugger::init(this);
_events = new EventsManager(this);
@@ -416,10 +448,6 @@ void AccessEngine::playVideo(int videoNum, const Common::Point &pt) {
}
}
-void AccessEngine::doLoadSave() {
- error("TODO: doLoadSave");
-}
-
void AccessEngine::freeChar() {
_scripts->freeScriptData();
_animation->clearTimers();
@@ -572,6 +600,36 @@ void AccessEngine::writeSavegameHeader(Common::OutSaveFile *out, AccessSavegameH
out->writeUint32LE(_events->getFrameCounter());
}
+void AccessEngine::SPRINTCHR(char c, int fontNum) {
+ warning("TODO: SPRINTCHR");
+ _fonts._font1.drawChar(_screen, c, _screen->_printOrg);
+}
+
+void AccessEngine::PRINTCHR(Common::String msg, int fontNum) {
+ _events->hideCursor();
+ warning("TODO: PRINTCHR - Handle fontNum");
+
+ for (int i = 0; msg[i]; i++) {
+ if (!(_fonts._charSet._hi & 8)) {
+ _fonts._font1.drawChar(_screen, msg[i], _screen->_printOrg);
+ continue;
+ } else if (_fonts._charSet._hi & 2) {
+ Common::Point oldPos = _screen->_printOrg;
+ int oldFontLo = _fonts._charFor._lo;
+
+ _fonts._charFor._lo = 0;
+ _screen->_printOrg.x++;
+ _screen->_printOrg.y++;
+ SPRINTCHR(msg[i], fontNum);
+
+ _screen->_printOrg = oldPos;
+ _fonts._charFor._lo = oldFontLo;
+ }
+ SPRINTCHR(msg[i], fontNum);
+ }
+ _events->showCursor();
+}
+
bool AccessEngine::shouldQuitOrRestart() {
return shouldQuit() || _restartFl;
}
diff --git a/engines/access/access.h b/engines/access/access.h
index be007e0cb8..37b9fec5a5 100644
--- a/engines/access/access.h
+++ b/engines/access/access.h
@@ -137,6 +137,10 @@ protected:
public:
AnimationManager *_animation;
BubbleBox *_bubbleBox;
+ BubbleBox *_helpBox;
+ BubbleBox *_travelBox;
+ BubbleBox *_invBox;
+ BubbleBox *_aboutBox;
CharManager *_char;
Debugger *_debugger;
EventsManager *_events;
@@ -173,10 +177,9 @@ public:
ImageEntryList _images;
int _mouseMode;
+ int _playerDataCount;
int _currentManOld;
int _converseMode;
- int _startAboutBox;
- int _startTravelBox;
bool _currentCharFlag;
bool _boxSelect;
int _scale;
@@ -204,6 +207,26 @@ public:
uint32 _newDate;
int _flags[256];
+ // Fields used by MM
+ // TODO: Refactor
+ int _travel[60];
+ int _ask[40];
+ int _startTravelItem;
+ int _startTravelBox;
+ int _startAboutItem;
+ int _startAboutBox;
+ int _boxDataStart;
+ bool _boxDataEnd;
+ int _boxSelectY;
+ int _boxSelectYOld;
+ int _numLines;
+ byte _byte26CB5;
+ int _bcnt;
+ byte *_tempList;
+ int _pictureTaken;
+ //
+
+ bool _vidEnd;
bool _clearSummaryFlag;
bool _cheatFl;
bool _restartFl;
@@ -250,8 +273,6 @@ public:
void copyBF2Vid();
- void doLoadSave();
-
void freeChar();
/**
@@ -289,6 +310,9 @@ public:
* Write out a savegame header
*/
void writeSavegameHeader(Common::OutSaveFile *out, AccessSavegameHeader &header);
+
+ void SPRINTCHR(char c, int fontNum);
+ void PRINTCHR(Common::String msg, int fontNum);
};
} // End of namespace Access
diff --git a/engines/access/amazon/amazon_game.cpp b/engines/access/amazon/amazon_game.cpp
index 4c9df7b8ff..7a55873d97 100644
--- a/engines/access/amazon/amazon_game.cpp
+++ b/engines/access/amazon/amazon_game.cpp
@@ -195,8 +195,8 @@ void AmazonEngine::initVariables() {
_timers.push_back(te);
}
- _player->_playerX = _player->_rawPlayer.x = TRAVEL_POS[_player->_roomNumber][0];
- _player->_playerY = _player->_rawPlayer.y = TRAVEL_POS[_player->_roomNumber][1];
+ _player->_playerX = _player->_rawPlayer.x = _travelPos[_player->_roomNumber][0];
+ _player->_playerY = _player->_rawPlayer.y = _travelPos[_player->_roomNumber][1];
_room->_selectCommand = -1;
_events->setNormalCursor(CURSOR_CROSSHAIRS);
_mouseMode = 0;
@@ -260,13 +260,24 @@ void AmazonEngine::doEstablish(int screenId, int estabIndex) {
_screen->setIconPalette();
_screen->forceFadeIn();
- _fonts._charSet._lo = 1;
- _fonts._charSet._hi = 10;
- _fonts._charFor._lo = 29;
- _fonts._charFor._hi = 32;
+ if (getGameID() == GType_MartianMemorandum) {
+ _fonts._charSet._lo = 1;
+ _fonts._charSet._hi = 10;
+ _fonts._charFor._lo = 0xF7;
+ _fonts._charFor._hi = 0xFF;
+
+ _screen->_maxChars = 50;
+ _screen->_printOrg = _screen->_printStart = Common::Point(24, 18);
+ } else {
+ _fonts._charSet._lo = 1;
+ _fonts._charSet._hi = 10;
+ _fonts._charFor._lo = 29;
+ _fonts._charFor._hi = 32;
+
+ _screen->_maxChars = 37;
+ _screen->_printOrg = _screen->_printStart = Common::Point(48, 35);
+ }
- _screen->_maxChars = 37;
- _screen->_printOrg = _screen->_printStart = Common::Point(48, 35);
loadEstablish(estabIndex);
uint16 msgOffset;
if (!isCD())
diff --git a/engines/access/amazon/amazon_logic.cpp b/engines/access/amazon/amazon_logic.cpp
index 6dffb85e5e..de53da51cd 100644
--- a/engines/access/amazon/amazon_logic.cpp
+++ b/engines/access/amazon/amazon_logic.cpp
@@ -326,16 +326,8 @@ void Opening::doTitle() {
_vm->_buffer2.copyFrom(*_vm->_screen);
_vm->_buffer1.copyFrom(*_vm->_screen);
screen.forceFadeIn();
- _vm->_sound->playSound(1);
- // WORKAROUND: This delay has been added to replace original game delay that
- // came from loading resources, since nowadays it would be too fast to be visible
- // nowadays to be visible.
- _vm->_events->_vbCount = 70;
- while (!_vm->shouldQuit() && _vm->_events->_vbCount > 0)
- _vm->_events->pollEventsAndWait();
- if (_vm->shouldQuit())
- return;
+ _vm->_sound->playSound(1, true);
Resource *spriteData = _vm->_files->loadFile(0, 2);
_vm->_objectsTable[0] = new SpriteResource(_vm, spriteData);
@@ -343,7 +335,6 @@ void Opening::doTitle() {
_vm->_files->_setPaletteFlag = false;
_vm->_files->loadScreen(0, 4);
- _vm->_sound->playSound(1);
_vm->_buffer2.copyFrom(*_vm->_screen);
_vm->_buffer1.copyFrom(*_vm->_screen);
@@ -356,7 +347,6 @@ void Opening::doTitle() {
_vm->_buffer2.plotImage(_vm->_objectsTable[0], id, Common::Point(xp, 71));
_vm->_buffer2.copyTo(_vm->_screen);
- _vm->_sound->playSound(1);
_vm->_events->_vbCount = 70;
while (!_vm->shouldQuit() && _vm->_events->_vbCount > 0 && !_skipStart) {
_vm->_events->pollEventsAndWait();
@@ -368,6 +358,7 @@ void Opening::doTitle() {
return;
_vm->_sound->stopSound();
+ _vm->_sound->checkSoundQueue(); // HACK: Clear sound 1 from the queue
_vm->_sound->playSound(0);
screen.forceFadeOut();
_vm->_events->_vbCount = 100;
@@ -386,7 +377,7 @@ void Opening::doTitle() {
_vm->_buffer1.blitFrom(*_vm->_screen);
screen.forceFadeIn();
_vm->_midi->newMusic(1, 0);
- _vm->_events->_vbCount = 700;
+ _vm->_events->_vbCount = 950;
while (!_vm->shouldQuit() && (_vm->_events->_vbCount > 0) && !_vm->_events->isKeyMousePressed()) {
_vm->_events->pollEventsAndWait();
}
@@ -1605,7 +1596,7 @@ void River::moveCanoe() {
moveCanoe2();
} else {
if (events._leftButton && pt.y >= 140) {
- if (pt.x < RMOUSE[8][0]) {
+ if (pt.x < _vm->_room->_rMouse[8][0]) {
// Disk icon wasn't clicked
_vm->_scripts->printString(BAR_MESSAGE);
} else {
diff --git a/engines/access/amazon/amazon_player.cpp b/engines/access/amazon/amazon_player.cpp
index b1ed501fce..903da6c532 100644
--- a/engines/access/amazon/amazon_player.cpp
+++ b/engines/access/amazon/amazon_player.cpp
@@ -48,7 +48,7 @@ void AmazonPlayer::load() {
_downDelta = -2;
_scrollConst = 2;
- for (int i = 0; i < PLAYER_DATA_COUNT; ++i) {
+ for (int i = 0; i < _vm->_playerDataCount; ++i) {
_walkOffRight[i] = OVEROFFR[i];
_walkOffLeft[i] = OVEROFFL[i];
_walkOffUp[i] = OVEROFFU[i];
@@ -78,6 +78,22 @@ void AmazonPlayer::load() {
_diagDownWalkMin = 0;
_diagDownWalkMax = 5;
_game->_guard->setPosition(Common::Point(56, 190));
+ } else {
+ for (int i = 0; i < _vm->_playerDataCount; ++i) {
+ _walkOffRight[i] = SIDEOFFR[i];
+ _walkOffLeft[i] = SIDEOFFL[i];
+ _walkOffUp[i] = SIDEOFFU[i];
+ _walkOffDown[i] = SIDEOFFD[i];
+
+ _walkOffUR[i].x = DIAGOFFURX[i];
+ _walkOffUR[i].y = DIAGOFFURY[i];
+ _walkOffDR[i].x = DIAGOFFDRX[i];
+ _walkOffDR[i].y = DIAGOFFDRY[i];
+ _walkOffUL[i].x = DIAGOFFULX[i];
+ _walkOffUL[i].y = DIAGOFFULY[i];
+ _walkOffDL[i].x = DIAGOFFDLX[i];
+ _walkOffDL[i].y = DIAGOFFDLY[i];
+ }
}
}
diff --git a/engines/access/amazon/amazon_resources.cpp b/engines/access/amazon/amazon_resources.cpp
index 2010c7d842..430aa64f30 100644
--- a/engines/access/amazon/amazon_resources.cpp
+++ b/engines/access/amazon/amazon_resources.cpp
@@ -72,6 +72,19 @@ const char *const FILENAMES_DEMO[] = {
"CHAPTER.AP", "MUSIC.AP", "SOUND.AP", "INV.AP"
};
+const int SIDEOFFR[] = { 5, 5, 5, 5, 5, 5, 5, 5, 0 };
+const int SIDEOFFL[] = { 5, 5, 5, 5, 5, 5, 5, 5, 0 };
+const int SIDEOFFU[] = { 2, 2, 2, 2, 2, 2, 2, 2, 0 };
+const int SIDEOFFD[] = { 2, 2, 2, 2, 2, 2, 2, 2, 0 };
+const int DIAGOFFURX[] = { 4, 5, 2, 2, 3, 4, 2, 2, 0 };
+const int DIAGOFFURY[] = { 2, 3, 2, 2, 2, 3, 1, 1, 0 };
+const int DIAGOFFDRX[] = { 4, 5, 4, 3, 5, 4, 5, 1, 0 };
+const int DIAGOFFDRY[] = { 3, 2, 1, 2, 2, 1, 2, 1, 0 };
+const int DIAGOFFULX[] = { 4, 5, 4, 3, 3, 2, 2, 2, 0 };
+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,
@@ -313,7 +326,7 @@ const byte *const CURSORS[10] = {
MOUSE0, MOUSE1, MOUSE2, MOUSE3, CURSEYE, CURSHAND, CURSGET, CURSCLIMB, CURSTALK, CURSHELP
};
-const int TRAVEL_POS[][2] = {
+const int _travelPos[][2] = {
{ -1, 0 },
{ 228, 117 },
{ 28, 98 },
@@ -2406,6 +2419,11 @@ const int CAST_END_OBJ1[4][4] = {
{ 3, 103, 1300, 10 }
};
-} // End of namespace Amazon
+const int RMOUSE[10][2] = {
+ { 0, 35 }, { 0, 0 }, { 36, 70 }, { 71, 106 }, { 107, 141 },
+ { 142, 177 }, { 178, 212 }, { 213, 248 }, { 249, 283 }, { 284, 318 }
+};
+
+} // End of namespace Amazon
} // End of namespace Access
diff --git a/engines/access/amazon/amazon_resources.h b/engines/access/amazon/amazon_resources.h
index a952860bc2..10dea02abc 100644
--- a/engines/access/amazon/amazon_resources.h
+++ b/engines/access/amazon/amazon_resources.h
@@ -45,9 +45,22 @@ struct RiverStruct {
extern const char *const FILENAMES[];
extern const char *const FILENAMES_DEMO[];
+extern const int SIDEOFFR[];
+extern const int SIDEOFFL[];
+extern const int SIDEOFFU[];
+extern const int SIDEOFFD[];
+extern const int DIAGOFFURX[];
+extern const int DIAGOFFURY[];
+extern const int DIAGOFFDRX[];
+extern const int DIAGOFFDRY[];
+extern const int DIAGOFFULX[];
+extern const int DIAGOFFULY[];
+extern const int DIAGOFFDLX[];
+extern const int DIAGOFFDLY[];
+
extern const byte *const CURSORS[10];
-extern const int TRAVEL_POS[][2];
+extern const int _travelPos[][2];
extern const int OVEROFFR[];
extern const int OVEROFFL[];
@@ -138,11 +151,11 @@ extern const int HELP1COORDS[2][4];
extern const int RIVER1OBJ[23][4];
extern const int CAST_END_OBJ[26][4];
-
extern const int CAST_END_OBJ1[4][4];
-} // End of namespace Amazon
+extern const int RMOUSE[10][2];
+} // End of namespace Amazon
} // End of namespace Access
#endif /* ACCESS_AMAZON_RESOURCES_H */
diff --git a/engines/access/amazon/amazon_scripts.cpp b/engines/access/amazon/amazon_scripts.cpp
index 92acb3686d..d8f4663401 100644
--- a/engines/access/amazon/amazon_scripts.cpp
+++ b/engines/access/amazon/amazon_scripts.cpp
@@ -33,6 +33,8 @@ namespace Amazon {
AmazonScripts::AmazonScripts(AccessEngine *vm) : Scripts(vm) {
_game = (AmazonEngine *)_vm;
+
+ setOpcodes_v2();
}
void AmazonScripts::cLoop() {
@@ -378,20 +380,20 @@ void AmazonScripts::executeSpecial(int commandIndex, int param1, int param2) {
typedef void(AmazonScripts::*AmazonScriptMethodPtr)();
void AmazonScripts::executeCommand(int commandIndex) {
- static const AmazonScriptMethodPtr COMMAND_LIST[] = {
- &AmazonScripts::cmdHelp, &AmazonScripts::cmdCycleBack,
+ static const AmazonScriptMethodPtr AMAZON_COMMAND_LIST[] = {
+ &AmazonScripts::cmdHelp_v2, &AmazonScripts::cmdCycleBack,
&AmazonScripts::cmdChapter, &AmazonScripts::cmdSetHelp,
&AmazonScripts::cmdCenterPanel, &AmazonScripts::cmdMainPanel,
&AmazonScripts::CMDRETFLASH
};
if (commandIndex >= 73)
- (this->*COMMAND_LIST[commandIndex - 73])();
+ (this->*AMAZON_COMMAND_LIST[commandIndex - 73])();
else
Scripts::executeCommand(commandIndex);
}
-void AmazonScripts::cmdHelp() {
+void AmazonScripts::cmdHelp_v2() {
Common::String helpMessage = readString();
if (_game->_helpLevel == 0) {
diff --git a/engines/access/amazon/amazon_scripts.h b/engines/access/amazon/amazon_scripts.h
index e10eefb4f5..6d992667f5 100644
--- a/engines/access/amazon/amazon_scripts.h
+++ b/engines/access/amazon/amazon_scripts.h
@@ -49,7 +49,7 @@ protected:
void setInactive();
void boatWalls(int param1, int param2);
- void cmdHelp();
+ void cmdHelp_v2();
void cmdCycleBack();
void cmdChapter();
void cmdSetHelp();
diff --git a/engines/access/asurface.cpp b/engines/access/asurface.cpp
index 5f4372d5af..526690807a 100644
--- a/engines/access/asurface.cpp
+++ b/engines/access/asurface.cpp
@@ -54,6 +54,12 @@ SpriteResource::~SpriteResource() {
SpriteFrame::SpriteFrame(AccessEngine *vm, Common::SeekableReadStream *stream, int frameSize) {
int xSize = stream->readUint16LE();
int ySize = stream->readUint16LE();
+
+ if (vm->getGameID() == GType_MartianMemorandum) {
+ int size = stream->readUint16LE();
+ if (size != frameSize)
+ warning("Unexpected file difference: framesize %d - size %d %d - unknown %d", frameSize, xSize, ySize, size);
+ }
create(xSize, ySize);
// Empty surface
@@ -312,6 +318,21 @@ void ASurface::drawRect() {
Graphics::Surface::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 ASurface::drawLine() {
+ Graphics::Surface::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 ASurface::flipHorizontal(ASurface &dest) {
dest.create(this->w, this->h);
for (int y = 0; y < h; ++y) {
diff --git a/engines/access/asurface.h b/engines/access/asurface.h
index 4fb47b9c09..022e2534c1 100644
--- a/engines/access/asurface.h
+++ b/engines/access/asurface.h
@@ -95,6 +95,12 @@ public:
virtual void drawRect();
+ virtual void drawLine(int x1, int y1, int x2, int y2, int col);
+
+ virtual void drawLine();
+
+ virtual void drawBox();
+
virtual void transBlitFrom(ASurface *src, const Common::Point &destPos);
virtual void transBlitFrom(ASurface *src, const Common::Rect &bounds);
diff --git a/engines/access/bubble_box.cpp b/engines/access/bubble_box.cpp
index 28c211991c..df8adc1bc6 100644
--- a/engines/access/bubble_box.cpp
+++ b/engines/access/bubble_box.cpp
@@ -26,13 +26,26 @@
namespace Access {
-BubbleBox::BubbleBox(AccessEngine *vm) : Manager(vm) {
- _startItem = 0;
- _startBox = 0;
- _charCol = _rowOff = 0;
- _type = TYPE_2;
- _bounds = Common::Rect(64, 32, 64 + 130, 32 + 122);
- _bubbleDisplStr = "";
+BubbleBox::BubbleBox(AccessEngine *vm, Access::BoxType type, int x, int y, int w, int h, int val1, int val2, int val3, int val4, Common::String title) : Manager(vm) {
+ _type = type;
+ _bounds = Common::Rect(x, y, x + w, y + h);
+ _bubbleDisplStr = title;
+ _btnId1 = val1;
+ _btnX1 = val2;
+ _btnId2 = val3;
+ _btnX2 = val4;
+ _btnId3 = _btnX3 = 0; // Unused in MM and Amazon?
+ _boxStartX = _boxStartY = 0;
+ _bIconStartX = _bIconStartY = 0;
+ _boxEndX = _boxEndY = 0;
+ _boxPStartX = _boxPStartY = 0;
+ // Unused in AGoE
+ for (int i = 0; i < 60; i++) {
+ _tempList[i] = "";
+ _tempListIdx[i] = 0;
+ }
+ _btnUpPos = Common::Rect(0, 0, 0, 0);
+ _btnDownPos = Common::Rect(0, 0, 0, 0);
}
void BubbleBox::load(Common::SeekableReadStream *stream) {
@@ -61,7 +74,7 @@ void BubbleBox::clearBubbles() {
}
void BubbleBox::placeBubble(const Common::String &msg) {
- _vm->_screen->_maxChars = 27;
+ _vm->_screen->_maxChars = (_vm->getGameID() == GType_MartianMemorandum) ? 30 : 27;
placeBubble1(msg);
}
@@ -69,8 +82,8 @@ void BubbleBox::placeBubble1(const Common::String &msg) {
_bubbles.clear();
_vm->_fonts._charSet._lo = 1;
_vm->_fonts._charSet._hi = 8;
- _vm->_fonts._charFor._lo = 29;
- _vm->_fonts._charFor._hi = 32;
+ _vm->_fonts._charFor._lo = (_vm->getGameID() == GType_MartianMemorandum) ? 247 : 29;
+ _vm->_fonts._charFor._hi = (_vm->getGameID() == GType_MartianMemorandum) ? 255 : 32;
calcBubble(msg);
@@ -86,7 +99,7 @@ void BubbleBox::calcBubble(const Common::String &msg) {
Common::Point printStart = _vm->_screen->_printStart;
// Figure out maximum width allowed
- if (_type == TYPE_4) {
+ if (_type == kBoxTypeFileDialog) {
_vm->_fonts._printMaxX = 110;
} else {
_vm->_fonts._printMaxX = _vm->_fonts._font2.stringWidth(_bubbleDisplStr);
@@ -108,7 +121,7 @@ void BubbleBox::calcBubble(const Common::String &msg) {
_vm->_screen->_printOrg.x = _vm->_screen->_printStart.x;
} while (!lastLine);
- if (_type == TYPE_4)
+ if (_type == kBoxTypeFileDialog)
++_vm->_screen->_printOrg.y += 6;
// Determine the width for the area
@@ -119,12 +132,12 @@ void BubbleBox::calcBubble(const Common::String &msg) {
// Determine the height for area
int y = _vm->_screen->_printOrg.y + 6;
- if (_type == TYPE_4)
+ if (_type == kBoxTypeFileDialog)
y += 6;
int height = y - bounds.top;
bounds.setHeight(height);
- height -= (_type == TYPE_4) ? 30 : 24;
+ height -= (_type == kBoxTypeFileDialog) ? 30 : 24;
if (height >= 0)
bounds.setHeight(bounds.height() + 13 - (height % 13));
@@ -137,6 +150,35 @@ void BubbleBox::calcBubble(const Common::String &msg) {
}
void BubbleBox::printBubble(const Common::String &msg) {
+ if (_vm->getGameID() == GType_MartianMemorandum)
+ printBubble_v1(msg);
+ else
+ printBubble_v2(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;
+ int width = 0;
+ bool lastLine;
+ do {
+ // Get next line
+ Font &font2 = _vm->_fonts._font2;
+ lastLine = font2.getLine(s, _vm->_screen->_maxChars * 6, line, width);
+ // Draw the text
+ printString(line);
+
+ // Move print position
+ _vm->_screen->_printOrg.y += 6;
+ _vm->_screen->_printOrg.x = _vm->_screen->_printStart.x;
+ } while (!lastLine);
+
+}
+
+void BubbleBox::printBubble_v2(const Common::String &msg) {
drawBubble(_bubbles.size() - 1);
// Loop through drawing the lines
@@ -156,7 +198,7 @@ void BubbleBox::printBubble(const Common::String &msg) {
font2._fontColors[3] = 29;
int xp = _vm->_screen->_printOrg.x;
- if (_type == TYPE_4)
+ if (_type == kBoxTypeFileDialog)
xp = (_bounds.width() - width) / 2 + _bounds.left - 4;
// Draw the text
@@ -170,7 +212,11 @@ void BubbleBox::printBubble(const Common::String &msg) {
void BubbleBox::drawBubble(int index) {
_bounds = _bubbles[index];
- doBox(0, 0);
+ if (_vm->getGameID() == GType_MartianMemorandum) {
+ int btnSelected = 0;
+ doBox_v1(0, 0, btnSelected);
+ } else
+ doBox(0, 0);
}
void BubbleBox::doBox(int item, int box) {
@@ -194,7 +240,7 @@ void BubbleBox::doBox(int item, int box) {
fonts._charSet._lo = 1;
fonts._charSet._hi = 0;
- if (_type == TYPE_4) {
+ if (_type == kBoxTypeFileDialog) {
fonts._charFor._lo = 0xFF;
error("TODO: filename listing");
return;
@@ -212,7 +258,7 @@ void BubbleBox::doBox(int item, int box) {
_vm->_screen->_orgY2 = _bounds.bottom;
_vm->_screen->_lColor = 1;
- int h = _bounds.height() - (_type == TYPE_4 ? 30 : 24);
+ int h = _bounds.height() - (_type == kBoxTypeFileDialog ? 30 : 24);
int ySize = (h < 0) ? 0 : (h + 12) / 13;
int w = _bounds.width() - 24;
int xSize = (w < 0) ? 0 : (w + 19) / 20;
@@ -229,21 +275,21 @@ void BubbleBox::doBox(int item, int box) {
screen.plotImage(icons, 21, Common::Point(xp, screen._orgY1));
// Draw images to form the bottom border
- yp = screen._orgY2 - (_type == TYPE_4 ? 18 : 12);
- screen.plotImage(icons, (_type == TYPE_4) ? 72 : 22,
+ yp = screen._orgY2 - (_type == kBoxTypeFileDialog ? 18 : 12);
+ screen.plotImage(icons, (_type == kBoxTypeFileDialog) ? 72 : 22,
Common::Point(screen._orgX1, yp));
xp = screen._orgX1 + 12;
- yp += (_type == TYPE_4) ? 4 : 8;
+ yp += (_type == kBoxTypeFileDialog) ? 4 : 8;
for (int x = 0; x < xSize; ++x, xp += 20) {
- screen.plotImage(icons, (_type == TYPE_4 ? 62 : 34) + x,
+ screen.plotImage(icons, (_type == kBoxTypeFileDialog ? 62 : 34) + x,
Common::Point(xp, yp));
}
- yp = screen._orgY2 - (_type == TYPE_4 ? 18 : 12);
- screen.plotImage(icons, (_type == TYPE_4) ? 73 : 23, Common::Point(xp, yp));
+ yp = screen._orgY2 - (_type == kBoxTypeFileDialog ? 18 : 12);
+ screen.plotImage(icons, (_type == kBoxTypeFileDialog) ? 73 : 23, Common::Point(xp, yp));
- if (_type == TYPE_4) {
+ if (_type == kBoxTypeFileDialog) {
// Further stuff for filename dialog
error("TODO: Box type 4");
}
@@ -278,4 +324,440 @@ void BubbleBox::doBox(int item, int box) {
delete icons;
}
+void BubbleBox::setCursorPos(int posX, int posY) {
+ _vm->_screen->_printStart = _vm->_screen->_printOrg = Common::Point((posX << 3) + _rowOff, posY << 3);
+ warning("Missing call to setCursorPos");
+}
+
+void BubbleBox::printString(Common::String msg) {
+ warning("TODO: Proper implementation of printString");
+ _vm->_fonts._font1.drawString(_vm->_screen, msg, _vm->_screen->_printOrg);
+}
+
+void BubbleBox::displayBoxData() {
+ _vm->_boxDataEnd = false;
+ _rowOff = 2;
+ _vm->_fonts._charFor._lo = 0xF7;
+ _vm->_fonts._charFor._hi = 0xFF;
+
+ if (_tempList[0].size() == 0)
+ return;
+
+ int idx = 0;
+ if ((_type == TYPE_1) || (_type == TYPE_3)) {
+ _vm->_bcnt = 0;
+
+ if (_tempList[idx].size() == 0) {
+ _vm->_boxDataEnd = true;
+ return;
+ }
+
+ _vm->_events->hideCursor();
+
+ _vm->_screen->_orgX1 = _boxStartX;
+ _vm->_screen->_orgX2 = _boxEndX;
+ _vm->_screen->_orgY1 = _boxStartY;
+ _vm->_screen->_orgY2 = _boxEndY;
+ _vm->_screen->_lColor = 0xFA;
+ _vm->_screen->drawRect();
+ _vm->_events->showCursor();
+ }
+
+ _vm->_events->hideCursor();
+ int oldPStartY = _boxPStartY;
+ ++_boxPStartY;
+
+ idx += _vm->_boxDataStart;
+
+ while (true) {
+ setCursorPos(_boxPStartX, _boxPStartY);
+ printString(_tempList[idx]);
+
+ ++idx;
+ ++_boxPStartY;
+ ++_vm->_bcnt;
+ if (_tempList[idx].size() == 0) {
+ _boxPStartY = oldPStartY;
+ _vm->_events->showCursor();
+ _vm->_boxDataEnd = true;
+ return;
+ }
+
+ if (_vm->_bcnt == _vm->_numLines) {
+ _boxPStartY = oldPStartY;
+ _vm->_events->showCursor();
+ return;
+ }
+ }
+}
+
+void BubbleBox::drawSelectBox() {
+ if (_tempList[0].size() == 0)
+ return;
+
+ if (((_type != TYPE_1) && (_type != TYPE_3)) || !_vm->_bcnt)
+ return;
+
+ if (_vm->_boxSelectYOld != -1) {
+ _vm->_events->hideCursor();
+ _vm->_screen->_lColor = 0xFA;
+
+ int val = _vm->_boxSelectYOld + _boxPStartY + 1;
+ _vm->_screen->_orgY1 = (val << 3) + 2;
+ _vm->_screen->_orgY2 = _vm->_screen->_orgY1 + 7;
+ _vm->_screen->_orgX1 = _boxStartX;
+ _vm->_screen->_orgX2 = _boxEndX;
+ _vm->_screen->drawBox();
+ _vm->_events->showCursor();
+ }
+
+ _vm->_events->hideCursor();
+ _vm->_boxSelectYOld = _vm->_boxSelectY;
+ int val = _boxPStartY + _vm->_boxSelectY + 1;
+ _vm->_screen->_orgY1 = (val << 3) + 2;
+ _vm->_screen->_orgY2 = _vm->_screen->_orgY1 + 7;
+ _vm->_screen->_orgX1 = _boxStartX;
+ _vm->_screen->_orgX2 = _boxEndX;
+ _vm->_screen->_lColor = 0xFE;
+ _vm->_screen->drawBox();
+ _vm->_events->showCursor();
+
+ if (_type == TYPE_3)
+ warning("TODO: List filenames");
+}
+
+int BubbleBox::doBox_v1(int item, int box, int &btnSelected) {
+ static const int ICONW[] = { 0, 11, 28, 19, 19, 15 };
+
+ FontManager &fonts = _vm->_fonts;
+ int retval_ = -1;
+
+ _startItem = item;
+ _startBox = box;
+
+ // Save state information
+ _vm->_screen->saveScreen();
+ _vm->_screen->setDisplayScan();
+
+ fonts._charFor._hi = 0xff;
+ fonts._charSet._lo = 1;
+ fonts._charSet._hi = 0;
+
+ _vm->_destIn = _vm->_screen; // TODO: Redundant
+
+ if (_type != TYPE_2) {
+ Common::Rect r = _bounds;
+ r.left -= 2;
+ _vm->_screen->saveBlock(r);
+ }
+
+ // Set the up boundaries and color to use for the box background
+ _vm->_screen->_orgX1 = _bounds.left - 2;
+ _vm->_screen->_orgY1 = _bounds.top;
+ _vm->_screen->_orgX2 = _bounds.right - 2;
+ _vm->_screen->_orgY2 = _bounds.bottom;
+ _vm->_screen->_lColor = 0xFB;
+
+ // Draw a background for the entire area
+ _vm->_screen->drawRect();
+
+ // Draw the inner box;
+ ++_vm->_screen->_orgX1;
+ ++_vm->_screen->_orgY1;
+ --_vm->_screen->_orgX2;
+ --_vm->_screen->_orgY2;
+ _vm->_screen->_lColor = 0xF9;
+
+ // Draw the inner border
+ _vm->_screen->drawBox();
+
+ // Get icons data
+ Resource *iconData = _vm->_files->loadFile("ICONS.LZ");
+ SpriteResource *icons = new SpriteResource(_vm, iconData);
+ delete iconData;
+
+ // Draw upper border
+ _vm->_bcnt = (_vm->_screen->_orgX2 - _vm->_screen->_orgX1) >> 4;
+ int oldX = _vm->_screen->_orgX1;
+ for ( ;_vm->_bcnt > 0; --_vm->_bcnt) {
+ _vm->_screen->plotImage(icons, 16, Common::Point(_vm->_screen->_orgX1, _vm->_screen->_orgY1));
+ _vm->_screen->_orgX1 += 16;
+ }
+
+ _vm->_screen->_orgX1 = oldX;
+ int oldY = _vm->_screen->_orgY2;
+ _vm->_screen->_orgY2 = _vm->_screen->_orgY1 + 8;
+ _vm->_screen->_lColor = 0xF9;
+
+ _boxStartY = _vm->_screen->_orgY2 + 1;
+ _vm->_screen->_orgY2 = oldY;
+
+ int tmpX = 0;
+ int tmpY = 0;
+ if (_type != TYPE_2) {
+ oldY = _vm->_screen->_orgY1;
+ --_vm->_screen->_orgY2;
+ _vm->_screen->_orgY1 = _vm->_screen->_orgY2 - 8;
+ if (_type == TYPE_3)
+ _vm->_screen->_orgY1 -= 8;
+ _vm->_screen->drawRect();
+ tmpX = _bIconStartX = _vm->_screen->_orgX1;
+
+ _boxStartX = tmpX + 1;
+ tmpY = _boxEndY = _vm->_screen->_orgY1;
+
+ if (_type == TYPE_3)
+ _bIconStartY = tmpY + 9;
+ else
+ _bIconStartY = tmpY + 1;
+
+ if (_type == TYPE_3) {
+ _fileStart = Common::Point((tmpX + 2) >> 3, (tmpY + 2) >> 3);
+ int rowOff = tmpY - (_fileStart.y << 3) + 1;
+ if (rowOff == 8) {
+ rowOff = 0;
+ ++_fileStart.y;
+ }
+ _fileOff.y = _rowOff = rowOff;
+ setCursorPos(_fileStart.x, _fileStart.y);
+ _vm->_fonts._charFor._lo = 0xF7;
+ _vm->_fonts._charFor._hi = 0;
+ printString("FILE: ");
+ _vm->_fonts._charFor._hi = 0xFF;
+ }
+ _vm->_screen->_orgY1 = oldY;
+ }
+
+ if ((_type != TYPE_0) && (_type != TYPE_2)) {
+ _vm->_screen->_orgY1 += 8;
+ if (_type == TYPE_3)
+ _vm->_screen->_orgY2 -= 8;
+
+ _vm->_screen->_orgY2 -= 8;
+ _btnUpPos.right = _btnDownPos.right = _vm->_screen->_orgX2;
+ _btnUpPos.left = _btnDownPos.left = _vm->_screen->_orgX1 = _vm->_screen->_orgX2 - 8;
+ _boxEndX = _vm->_screen->_orgX1 - 1;
+ _vm->_screen->drawBox();
+
+ _vm->_screen->_orgY1 += 6;
+ _vm->_screen->_orgY2 -= 6;
+ _vm->_screen->drawBox();
+
+ _btnUpPos.bottom = _vm->_screen->_orgY1 + 1;
+ _btnUpPos.top = _btnUpPos.bottom - 5;
+ _btnDownPos.top = _vm->_screen->_orgY2 + 1;
+ _btnDownPos.bottom = _btnDownPos.top + 6;
+
+ _vm->_screen->_orgX1 += 4;
+ _vm->_screen->_orgX2 = _vm->_screen->_orgX1;
+ _vm->_screen->_orgY1 -= 4;
+ _vm->_screen->_orgY2 += 2;
+ _vm->_screen->drawLine();
+
+ ++_vm->_screen->_orgY1;
+ --_vm->_screen->_orgX1;
+ ++_vm->_screen->_orgX2;
+ _vm->_screen->drawLine();
+
+ ++_vm->_screen->_orgY1;
+ --_vm->_screen->_orgX1;
+ ++_vm->_screen->_orgX2;
+ _vm->_screen->drawLine();
+
+ _vm->_screen->_orgY1 = _vm->_screen->_orgY2;
+ _vm->_screen->drawLine();
+
+ ++_vm->_screen->_orgX1;
+ --_vm->_screen->_orgX2;
+ ++_vm->_screen->_orgY1;
+ _vm->_screen->drawLine();
+
+ ++_vm->_screen->_orgX1;
+ --_vm->_screen->_orgX2;
+ ++_vm->_screen->_orgY1;
+ _vm->_screen->drawLine();
+ }
+
+ int len = _bubbleDisplStr.size();
+ int newX = _bounds.top >> 3;
+ newX = (len - newX) / 2;
+
+ _boxPStartX = _bounds.left >> 3;
+ newX += _boxPStartX;
+
+ int newY = _bounds.top >> 3;
+ int bp = _bounds.top - (newY << 3) + 1;
+ if (bp == 8) {
+ ++newY;
+ bp = 0;
+ }
+
+ _rowOff = bp;
+ retval_ = _boxPStartY = newY;
+
+ setCursorPos(newX, newY);
+
+ _vm->_fonts._charFor._lo = 0xFF;
+ _vm->_fonts._font1.drawString(_vm->_screen, _bubbleDisplStr, _vm->_screen->_printOrg);
+
+ if (_type == TYPE_2) {
+ _vm->_events->showCursor();
+ warning("TODO: pop values");
+ _vm->_screen->restoreScreen();
+ return retval_;
+ }
+
+ _vm->_destIn = _vm->_screen;
+
+ // Draw buttons
+ int ICON1T = 0;
+ int ICON1X = 0;
+ int ICON1Y = 0;
+ int ICON2T = 0;
+ int ICON2X = 0;
+ int ICON3T = 0;
+ int ICON3X = 0;
+ if (_btnId1) {
+ ICON1T = _btnId1;
+ ICON1X = _bIconStartX + _btnX1;
+ ICON1Y = _bIconStartY;
+ _vm->_screen->plotImage(icons, ICON1T + 10, Common::Point(ICON1X, ICON1Y));
+
+ if (_btnId2) {
+ ICON2T = _btnId2;
+ ICON2X = _bIconStartX + _btnX2;
+ _vm->_screen->plotImage(icons, ICON2T + 10, Common::Point(ICON2X, _bIconStartY));
+
+ if (_btnId3) {
+ ICON3T = _btnId3;
+ ICON3X = _bIconStartX + _btnX3;
+ _vm->_screen->plotImage(icons, ICON3T + 10, Common::Point(ICON3X, _bIconStartY));
+ }
+ }
+ }
+
+ _vm->_screen->restoreScreen();
+ _vm->_boxDataStart = _startItem;
+ _vm->_boxSelectYOld = -1;
+ _vm->_boxSelectY = _startBox;
+
+ _vm->_numLines = (_bounds.bottom >> 3) - 2;
+ if (_type == TYPE_3)
+ --_vm->_numLines;
+
+ _vm->_events->showCursor();
+ displayBoxData();
+ drawSelectBox();
+
+ while (!_vm->shouldQuit()) {
+ _vm->_events->pollEvents();
+ if (!_vm->_events->_leftButton)
+ continue;
+
+ if (((_type == TYPE_1) || (_type != TYPE_3)) && (_vm->_timers[2]._flag == 0)) {
+ ++_vm->_timers[2]._flag;
+ if (_btnUpPos.contains(_vm->_events->_mousePos)) {
+ if (_vm->_bcnt) {
+ if (_vm->_boxSelectY != 0) {
+ --_vm->_boxSelectY;
+ drawSelectBox();
+ } else if (_vm->_boxDataStart != 0) {
+ --_vm->_boxDataStart;
+ displayBoxData();
+ drawSelectBox();
+ }
+ }
+ continue;
+ } else if (_btnDownPos.contains(_vm->_events->_mousePos)) {
+ if (_vm->_bcnt) {
+ if (_vm->_bcnt == _vm->_numLines) {
+ if (_vm->_bcnt != _vm->_boxSelectY + 1) {
+ ++_vm->_boxSelectY;
+ drawSelectBox();
+ } else if (!_vm->_boxDataEnd) {
+ ++_vm->_boxDataStart;
+ displayBoxData();
+ drawSelectBox();
+ }
+ } else if (_vm->_bcnt != _vm->_boxSelectY + 1) {
+ ++_vm->_boxSelectY;
+ drawSelectBox();
+ }
+ }
+ continue;
+ }
+ }
+
+ if ((_vm->_events->_mousePos.x >= _boxStartX) && (_vm->_events->_mousePos.x <= _boxEndX)
+ && (_vm->_events->_mousePos.y >= _boxStartY) && (_vm->_events->_mousePos.y <= _boxEndY)) {
+ int val = (_vm->_events->_mousePos.x >> 3) - _boxPStartY;
+ if (val > _vm->_bcnt)
+ continue;
+ --val;
+ if (_type == TYPE_3)
+ _vm->_boxSelect = val;
+ else {
+ btnSelected = 1;
+ if (_vm->_boxSelectY == val)
+ break;
+ _vm->_boxSelectY = val;
+ _vm->_events->debounceLeft();
+ drawSelectBox();
+ continue;
+ }
+ }
+
+ if ((_vm->_events->_mousePos.y >= ICON1Y) && (_vm->_events->_mousePos.y <= ICON1Y + 8)
+ && (_vm->_events->_mousePos.x >= ICON1X)) {
+ btnSelected = 1;
+ if (_vm->_events->_mousePos.x < ICON1X + ICONW[ICON1T])
+ break;
+
+ if ((_vm->_events->_mousePos.x >= ICON2X) && (_vm->_events->_mousePos.x < ICON2X + ICONW[ICON2T])) {
+ btnSelected = 2;
+ break;
+ }
+
+ if ((_vm->_events->_mousePos.x >= ICON3X) && (_vm->_events->_mousePos.x < ICON3X + ICONW[ICON3T])) {
+ btnSelected = 3;
+ break;
+ }
+
+ if (_type != TYPE_3)
+ continue;
+
+ if ((_vm->_events->_mousePos.x < tmpX) || (_vm->_events->_mousePos.x > tmpX + 144))
+ continue;
+
+ if ((_vm->_events->_mousePos.y < tmpY) || (_vm->_events->_mousePos.y > tmpY + 8))
+ continue;
+
+ warning("TODO: sub175B5 - List of files");
+ }
+ }
+
+ _vm->_events->hideCursor();
+ _vm->_screen->restoreBlock();
+ _vm->_events->showCursor();
+ _vm->_events->debounceLeft();
+ if (_vm->_bcnt == 0)
+ retval_ = -1;
+ else
+ retval_ = _vm->_boxDataStart + _vm->_boxSelectY;
+ return retval_;
+}
+
+void BubbleBox::getList(const char *const data[], int *flags) {
+ int srcIdx = 0;
+ int destIdx = 0;
+ while (data[srcIdx]) {
+ if (flags[srcIdx]) {
+ _tempList[destIdx] = Common::String(data[srcIdx]);
+ _tempListIdx[destIdx] = srcIdx;
+ ++destIdx;
+ }
+ srcIdx++;
+ }
+ _tempList[destIdx] = "";
+}
} // End of namespace Access
diff --git a/engines/access/bubble_box.h b/engines/access/bubble_box.h
index 0b3f139520..9a45721108 100644
--- a/engines/access/bubble_box.h
+++ b/engines/access/bubble_box.h
@@ -36,23 +36,46 @@ namespace Access {
class AccessEngine;
-enum BoxType { TYPE_2 = 2, TYPE_4 = 4 };
+enum BoxType { TYPE_0 = 0, TYPE_1 = 1, TYPE_2 = 2, TYPE_3 = 3, kBoxTypeFileDialog = 4 };
class BubbleBox : public Manager {
private:
int _startItem, _startBox;
int _charCol, _rowOff;
Common::Point _fileStart;
+ Common::Point _fileOff;
+ int _boxStartX, _boxStartY;
+ int _boxEndX, _boxEndY;
+ int _bIconStartX, _bIconStartY;
+ int _boxPStartX, _boxPStartY;
+
+ void displayBoxData();
+ void drawSelectBox();
+ /**
+ * Prints a text bubble and it's contents
+ */
+ void printBubble_v1(const Common::String &msg);
+ void printBubble_v2(const Common::String &msg);
+
public:
BoxType _type;
Common::Rect _bounds;
Common::StringArray _nameIndex;
Common::String _bubbleTitle;
Common::String _bubbleDisplStr;
-
+ Common::String _tempList[60];
+ int _tempListIdx[60];
+ int _btnId1;
+ int _btnX1;
+ int _btnId2;
+ int _btnX2;
+ int _btnId3;
+ int _btnX3;
+ Common::Rect _btnUpPos;
+ Common::Rect _btnDownPos;
Common::Array<Common::Rect> _bubbles;
public:
- BubbleBox(AccessEngine *vm);
+ BubbleBox(AccessEngine *vm, Access::BoxType type, int x, int y, int w, int h, int val1, int val2, int val3, int val4, Common::String title);
void load(Common::SeekableReadStream *stream);
@@ -78,6 +101,11 @@ public:
void drawBubble(int index);
void doBox(int item, int box);
+
+ int doBox_v1(int item, int box, int &btnSelected);
+ void getList(const char *const data[], int *flags);
+ void setCursorPos(int posX, int posY);
+ void printString(Common::String msg);
};
} // End of namespace Access
diff --git a/engines/access/char.cpp b/engines/access/char.cpp
index b359bcf13a..aca7262952 100644
--- a/engines/access/char.cpp
+++ b/engines/access/char.cpp
@@ -27,15 +27,25 @@
namespace Access {
-CharEntry::CharEntry(const byte *data) {
+CharEntry::CharEntry(const byte *data, AccessEngine *vm) {
Common::MemoryReadStream s(data, 999);
_charFlag = s.readByte();
- _estabIndex = s.readSint16LE();
- _screenFile.load(s);
+ if (vm->getGameID() == GType_MartianMemorandum) {
+ _screenFile.load(s);
+ _estabIndex = s.readSint16LE();
+ } else {
+ _estabIndex = s.readSint16LE();
+ _screenFile.load(s);
+ }
+
_paletteFile.load(s);
_startColor = s.readUint16LE();
- _numColors = s.readUint16LE();
+ if (vm->getGameID() == GType_MartianMemorandum) {
+ int lastColor = s.readUint16LE();
+ _numColors = lastColor - _startColor;
+ } else
+ _numColors = s.readUint16LE();
// Load cells
for (byte cell = s.readByte(); cell != 0xff; cell = s.readByte()) {
@@ -73,12 +83,18 @@ CharManager::CharManager(AccessEngine *vm) : Manager(vm) {
// Setup character list
if (_vm->isDemo()) {
for (int i = 0; i < 27; ++i)
- _charTable.push_back(CharEntry(Amazon::CHARTBL_DEMO[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]));
+ _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");
}
@@ -152,8 +168,14 @@ void CharManager::charMenu() {
screen.saveScreen();
screen.setDisplayScan();
- screen.plotImage(spr, 17, Common::Point(0, 176));
- screen.plotImage(spr, 18, Common::Point(155, 176));
+ if (_vm->getGameID() == GType_MartianMemorandum) {
+ screen.plotImage(spr, 17, Common::Point(0, 184));
+ screen.plotImage(spr, 18, Common::Point(193, 184));
+ } else if (_vm->getGameID() == GType_Amazon) {
+ screen.plotImage(spr, 17, Common::Point(0, 176));
+ screen.plotImage(spr, 18, Common::Point(155, 176));
+ } else
+ error("Game not supported");
screen.restoreScreen();
delete spr;
diff --git a/engines/access/char.h b/engines/access/char.h
index 6fb4934978..f2828e9779 100644
--- a/engines/access/char.h
+++ b/engines/access/char.h
@@ -41,7 +41,7 @@ public:
FileIdent _scriptFile;
Common::Array<ExtraCell> _extraCells;
public:
- CharEntry(const byte *data);
+ CharEntry(const byte *data, AccessEngine *vm);
CharEntry();
};
diff --git a/engines/access/decompress.cpp b/engines/access/decompress.cpp
index c5656afa51..3de376c193 100644
--- a/engines/access/decompress.cpp
+++ b/engines/access/decompress.cpp
@@ -46,7 +46,7 @@ void LzwDecompressor::decompress(byte *source, byte *dest) {
maxCodeValue = 512;
copyLength = 0;
- _bitPos = 0;
+ _sourceBitsLeft = 8;
while (1) {
@@ -97,17 +97,39 @@ uint16 LzwDecompressor::getCode() {
const byte bitMasks[9] = {
0x00, 0x01, 0x03, 0x07, 0x0F, 0x1F, 0x3F, 0x7F, 0x0FF
};
- uint16 bits, loCode, hiCode;
- loCode = (READ_LE_UINT16(_source) >> _bitPos) & 0xFF;
- _source++;
- bits = _codeLength - 8;
- hiCode = (READ_LE_UINT16(_source) >> _bitPos) & bitMasks[bits];
- _bitPos += bits;
- if (_bitPos > 8) {
- _source++;
- _bitPos -= 8;
+
+ byte resultBitsLeft = _codeLength;
+ byte resultBitsPos = 0;
+ uint16 result = 0;
+ byte currentByte = *_source;
+ byte currentBits = 0;
+
+ // Get bits of current byte
+ while (resultBitsLeft) {
+ if (resultBitsLeft < _sourceBitsLeft) {
+ // we need less than we have left
+ currentBits = (currentByte >> (8 - _sourceBitsLeft)) & bitMasks[resultBitsLeft];
+ result |= (currentBits << resultBitsPos);
+ _sourceBitsLeft -= resultBitsLeft;
+ resultBitsLeft = 0;
+
+ } else {
+ // we need as much as we have left or more
+ resultBitsLeft -= _sourceBitsLeft;
+ currentBits = currentByte >> (8 - _sourceBitsLeft);
+ result |= (currentBits << resultBitsPos);
+ resultBitsPos += _sourceBitsLeft;
+
+ // Go to next byte
+ _source++;
+
+ _sourceBitsLeft = 8;
+ if (resultBitsLeft) {
+ currentByte = *_source;
+ }
+ }
}
- return (hiCode << 8) | loCode;
+ return result;
}
uint32 decompressDBE(byte *source, byte **dest) {
diff --git a/engines/access/decompress.h b/engines/access/decompress.h
index eea450086b..bea9a1d3f8 100644
--- a/engines/access/decompress.h
+++ b/engines/access/decompress.h
@@ -32,7 +32,8 @@ public:
void decompress(byte *source, byte *dest);
private:
byte *_source;
- byte _codeLength, _bitPos;
+ byte _sourceBitsLeft;
+ byte _codeLength;
uint16 getCode();
};
diff --git a/engines/access/detection_tables.h b/engines/access/detection_tables.h
index 88a64470c5..124f5fcf0d 100644
--- a/engines/access/detection_tables.h
+++ b/engines/access/detection_tables.h
@@ -75,7 +75,22 @@ static const AccessGameDescription gameDescriptions[] = {
{
"martian",
nullptr,
- AD_ENTRY1s("r00.ap", "af98db5ee7f9ef86c6b1f43187a3691b", 31),
+ AD_ENTRY1s("r01.ap", "c081daca9b0cfd710157cf946e343df6", 39352),
+ Common::EN_ANY,
+ Common::kPlatformDOS,
+ ADGF_NO_FLAGS,
+ GUIO1(GUIO_NONE)
+ },
+ GType_MartianMemorandum,
+ 0
+ },
+
+ {
+ // Martian Memorandum
+ {
+ "martian",
+ "Demo",
+ AD_ENTRY1s("r01.rm", "c2facf9c43047211289044ee39a2322a", 2313),
Common::EN_ANY,
Common::kPlatformDOS,
ADGF_NO_FLAGS,
diff --git a/engines/access/inventory.cpp b/engines/access/inventory.cpp
index df499ba705..3823b17283 100644
--- a/engines/access/inventory.cpp
+++ b/engines/access/inventory.cpp
@@ -31,10 +31,17 @@ namespace Access {
void InventoryEntry::load(const Common::String &name, const int *data) {
_value = ITEM_NOT_FOUND;
_name = name;
- _otherItem1 = *data++;
- _newItem1 = *data++;
- _otherItem2 = *data++;
- _newItem2 = *data;
+ if (data) {
+ _otherItem1 = *data++;
+ _newItem1 = *data++;
+ _otherItem2 = *data++;
+ _newItem2 = *data;
+ } else {
+ _otherItem1 = -1;
+ _newItem1 = -1;
+ _otherItem2 = -1;
+ _newItem2 = -1;
+ }
}
int InventoryEntry::checkItem(int itemId) {
@@ -67,20 +74,20 @@ InventoryManager::InventoryManager(AccessEngine *vm) : Manager(vm) {
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 = &Martian::COMBO_TABLE[0][0];
- _inv.resize(54);
+ combineP = nullptr;
+ _inv.resize(55);
+ for (uint i = 0; i < _inv.size(); ++i)
+ _inv[i].load(names[i], nullptr);
break;
default:
error("Unknown game");
}
- for (uint i = 0; i < _inv.size(); ++i, combineP += 4) {
- _inv[i].load(names[i], combineP);
- }
-
for (uint i = 0; i < 26; ++i) {
const int *r = INVCOORDS[i];
_invCoords.push_back(Common::Rect(r[0], r[2], r[1], r[3]));
@@ -209,6 +216,31 @@ int InventoryManager::newDisplayInv() {
return result;
}
+int InventoryManager::displayInv() {
+ int *inv = (int *) malloc (Martian::INVENTORY_SIZE * sizeof(int));
+
+ for (int i = 0; i < Martian::INVENTORY_SIZE; i++)
+ inv[i] = _inv[i]._value;
+ _vm->_events->forceSetCursor(CURSOR_CROSSHAIRS);
+ _vm->_invBox->getList(Martian::INVENTORY_NAMES, inv);
+
+ int btnSelected = 0;
+ int boxX = _vm->_invBox->doBox_v1(_startInvItem, _startInvBox, btnSelected);
+ _startInvItem = _vm->_boxDataStart;
+ _startInvBox = _vm->_boxSelectY;
+
+ if (boxX == -1)
+ btnSelected = 2;
+
+ if (btnSelected != 2)
+ _vm->_useItem = _vm->_invBox->_tempListIdx[boxX];
+ else
+ _vm->_useItem = -1;
+
+ free(inv);
+ return 0;
+}
+
void InventoryManager::savedFields() {
Screen &screen = *_vm->_screen;
Room &room = *_vm->_room;
diff --git a/engines/access/inventory.h b/engines/access/inventory.h
index 6a9390eda9..1d88bf4555 100644
--- a/engines/access/inventory.h
+++ b/engines/access/inventory.h
@@ -128,6 +128,7 @@ public:
void refreshInventory();
int newDisplayInv();
+ int displayInv();
/**
* Synchronize savegame data
diff --git a/engines/access/martian/martian_game.cpp b/engines/access/martian/martian_game.cpp
index 4e4a5135a6..3fdba8d260 100644
--- a/engines/access/martian/martian_game.cpp
+++ b/engines/access/martian/martian_game.cpp
@@ -35,108 +35,256 @@ MartianEngine::MartianEngine(OSystem *syst, const AccessGameDescription *gameDes
}
MartianEngine::~MartianEngine() {
+ _introObjects = _spec7Objects = nullptr;
}
-void MartianEngine::playGame() {
- // Do introduction
- doIntroduction();
- if (shouldQuit())
- return;
+void MartianEngine::initObjects() {
+ _room = new MartianRoom(this);
+ _scripts = new MartianScripts(this);
+}
- // Setup the game
- setupGame();
+void MartianEngine::configSelect() {
+ // No implementation required in MM
+}
- _screen->clearScreen();
- _screen->setPanel(0);
- _screen->forceFadeOut();
+void MartianEngine::initVariables() {
+ warning("TODO: initVariables");
+
+ // Set player room and position
+ _player->_roomNumber = 7;
+
+ _inventory->_startInvItem = 0;
+ _inventory->_startInvBox = 0;
+ Common::fill(&_objectsTable[0], &_objectsTable[100], (SpriteResource *)nullptr);
+ _player->_playerOff = false;
+
+ // Setup timers
+ const int TIMER_DEFAULTS[] = { 4, 10, 8, 1, 1, 1, 1, 2 };
+ for (int i = 0; i < 32; ++i) {
+ TimerEntry te;
+ te._initTm = te._timer = (i < 8) ? TIMER_DEFAULTS[i] : 1;
+ te._flag = 1;
+
+ _timers.push_back(te);
+ }
+
+ _player->_playerX = _player->_rawPlayer.x = _travelPos[_player->_roomNumber][0];
+ _player->_playerY = _player->_rawPlayer.y = _travelPos[_player->_roomNumber][1];
+ _room->_selectCommand = -1;
+ _events->setNormalCursor(CURSOR_CROSSHAIRS);
+ _mouseMode = 0;
+ _numAnimTimers = 0;
+
+ for (int i = 0; i < 60; i++)
+ _travel[i] = 0;
+ _travel[7] = 1;
+
+ for (int i = 0; i < 40; i++)
+ _ask[i] = 0;
+ _ask[33] = 1;
+}
+
+void MartianEngine::setNoteParams() {
+ _events->hideCursor();
+
+ _screen->_orgX1 = 58;
+ _screen->_orgY1 = 124;
+ _screen->_orgX2 = 297;
+ _screen->_orgY2 = 199;
+ _screen->_lColor = 51;
+ _screen->drawRect();
_events->showCursor();
+}
- // Setup and execute the room
- _room = new MartianRoom(this);
- _scripts = new MartianScripts(this);
- _room->doRoom();
+void MartianEngine::displayNote(const Common::String &msg) {
+ _fonts._charSet._lo = 1;
+ _fonts._charSet._hi = 8;
+ _fonts._charFor._lo = 0;
+ _fonts._charFor._hi = 255;
+
+ _screen->_maxChars = 40;
+ _screen->_printOrg = _screen->_printStart = Common::Point(59, 124);
+
+ setNoteParams();
+
+ Common::String lines = msg;
+ Common::String line;
+ int width = 0;
+ bool lastLine = false;
+ do {
+ lastLine = _fonts._font1.getLine(lines, _screen->_maxChars * 6, line, width);
+ _bubbleBox->printString(line);
+ _screen->_printOrg = Common::Point(_screen->_printStart.x, _screen->_printOrg.y + 6);
+
+ if (_screen->_printOrg.y == 196) {
+ _events->waitKeyMouse();
+ setNoteParams();
+ _screen->_printOrg = _screen->_printStart;
+ }
+ } while (!lastLine);
+ _events->waitKeyMouse();
}
-void MartianEngine::doIntroduction() {
- _screen->setInitialPalettte();
- _events->setCursor(CURSOR_ARROW);
+void MartianEngine::doSpecial5(int param1) {
+ warning("TODO: Push midi song");
+ _midi->stopSong();
+ _midi->_byte1F781 = false;
+ _midi->loadMusic(47, 4);
+ _midi->midiPlay();
+ _screen->setDisplayScan();
+ _events->clearEvents();
+ _screen->forceFadeOut();
+ _events->hideCursor();
+ _files->loadScreen("DATA.SC");
_events->showCursor();
- _screen->setPanel(0);
+ _screen->setIconPalette();
+ _screen->forceFadeIn();
+
+ Resource *cellsRes = _files->loadFile("CELLS00.LZ");
+ _objectsTable[0] = new SpriteResource(this, cellsRes);
+ delete cellsRes;
+
+ _timers[20]._timer = _timers[20]._initTm = 30;
+ Resource *notesRes = _files->loadFile("NOTES.DAT");
+ notesRes->_stream->skip(param1 * 2);
+ int pos = notesRes->_stream->readUint16LE();
+ notesRes->_stream->seek(pos);
+ Common::String msg = "";
+ byte c;
+ while ((c = (char)notesRes->_stream->readByte()) != '\0')
+ msg += c;
+
+ displayNote(msg);
+
+ _midi->stopSong();
+ _midi->freeMusic();
+
+ warning("TODO: Pop Midi");
+ // _midi->_byte1F781 = true;
+}
+
+void MartianEngine::playGame() {
+ // Initialize Martian Memorandum game-specific objects
+ initObjects();
- // TODO: Worry about implementing full intro sequence later
- return;
+ // Setup the game
+ setupGame();
+ configSelect();
- doTitle();
- if (shouldQuit())
- return;
+ if (_loadSaveSlot == -1) {
+ // Do introduction
+ doCredits();
+ if (shouldQuit())
+ return;
- if (!_skipStart) {
- _screen->setPanel(3);
- doOpening();
+ // Display Notes screen
+ doSpecial5(4);
if (shouldQuit())
return;
+ _screen->forceFadeOut();
+ }
- if (!_skipStart) {
- //doTent();
- if (shouldQuit())
- return;
+ do {
+ _restartFl = false;
+ _screen->clearScreen();
+ _screen->setPanel(0);
+ _screen->forceFadeOut();
+ _events->showCursor();
+
+ initVariables();
+
+ // If there's a pending savegame to load, load it
+ if (_loadSaveSlot != -1) {
+ loadGameState(_loadSaveSlot);
+ _loadSaveSlot = -1;
}
- }
- doTitle();
+ // Execute the room
+ _room->doRoom();
+ } while (_restartFl);
}
-void MartianEngine::doTitle() {
- /*
- _screen->setDisplayScan();
- _destIn = &_buffer2;
-
- _screen->forceFadeOut();
+bool MartianEngine::showCredits() {
_events->hideCursor();
+ _screen->clearScreen();
+ _destIn = _screen;
- _sound->queueSound(0, 98, 30);
-
- _files->_setPaletteFlag = false;
- _files->loadScreen(0, 3);
-
- _buffer2.blitFrom(*_screen);
- _buffer1.blitFrom(*_screen);
- _screen->forceFadeIn();
- _sound->playSound(1);
+ int posX = _creditsStream->readSint16LE();
+ int posY = 0;
- Resource *spriteData = _files->loadFile(0, 2);
- _objectsTable[0] = new SpriteResource(this, spriteData);
- delete spriteData;
+ while(posX != -1) {
+ posY = _creditsStream->readSint16LE();
+ int frameNum = _creditsStream->readSint16LE();
+ _screen->plotImage(_introObjects, frameNum, Common::Point(posX, posY));
- _sound->playSound(1);
+ posX = _creditsStream->readSint16LE();
+ }
- _files->_setPaletteFlag = false;
- _files->loadScreen(0, 4);
- _sound->playSound(1);
+ posY = _creditsStream->readSint16LE();
+ if (posY == -1) {
+ _events->showCursor();
+ _screen->forceFadeOut();
+ return true;
+ }
- _buffer2.blitFrom(*_screen);
- _buffer1.blitFrom(*_screen);
- _sound->playSound(1);
+ _screen->forceFadeIn();
+ _timers[3]._timer = _timers[3]._initTm = posY;
- const int COUNTDOWN[6] = { 2, 0x80, 1, 0x7d, 0, 0x87 };
- for (_pCount = 0; _pCount < 3; ++_pCount) {
- _buffer2.blitFrom(_buffer1);
- int id = READ_LE_UINT16(COUNTDOWN + _pCount * 4);
- int xp = READ_LE_UINT16(COUNTDOWN + _pCount * 4 + 2);
- _screen->plotImage(_objectsTable[0], id, Common::Point(xp, 71));
+ while (!shouldQuit() && !_events->isKeyMousePressed() && _timers[3]._timer) {
+ _events->pollEventsAndWait();
}
- // TODO: More to do
- delete _objectsTable[0];
- */
+ _events->showCursor();
+ _screen->forceFadeOut();
+
+ if (_events->_rightButton)
+ return true;
+ else
+ return false;
}
-void MartianEngine::doOpening() {
- warning("TODO doOpening");
+void MartianEngine::doCredits() {
+ _midi->_byte1F781 = false;
+ _midi->loadMusic(47, 3);
+ _midi->midiPlay();
+ _screen->setDisplayScan();
+ _events->hideCursor();
+ _screen->forceFadeOut();
+ Resource *data = _files->loadFile(41, 1);
+ _introObjects = new SpriteResource(this, data);
+ delete data;
+
+ _files->loadScreen(41, 0);
+ _buffer2.copyFrom(*_screen);
+ _buffer1.copyFrom(*_screen);
+ _events->showCursor();
+ _creditsStream = new Common::MemoryReadStream(CREDIT_DATA, 180);
+
+ if (!showCredits()) {
+ _screen->copyFrom(_buffer2);
+ _screen->forceFadeIn();
+
+ _events->_vbCount = 550;
+ while (!shouldQuit() && !_events->isKeyMousePressed() && _events->_vbCount > 0)
+ _events->pollEventsAndWait();
+
+ _screen->forceFadeOut();
+ while (!shouldQuit() && !_events->isKeyMousePressed()&& !showCredits())
+ _events->pollEventsAndWait();
+
+ warning("TODO: Free word_21E2B");
+ _midi->freeMusic();
+ }
}
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];
+ }
// Setup timers
const int TIMER_DEFAULTS[] = { 4, 10, 8, 1, 1, 1, 1, 2 };
@@ -155,12 +303,60 @@ void MartianEngine::setupGame() {
// Set player room and position
_player->_roomNumber = 7;
- _player->_playerX = _player->_rawPlayer.x = TRAVEL_POS[_player->_roomNumber][0];
- _player->_playerY = _player->_rawPlayer.y = TRAVEL_POS[_player->_roomNumber][1];
+ _player->_playerX = _player->_rawPlayer.x = _travelPos[_player->_roomNumber][0];
+ _player->_playerY = _player->_rawPlayer.y = _travelPos[_player->_roomNumber][1];
+}
+
+void MartianEngine::showDeathText(Common::String msg) {
+ Common::String line = "";
+ int width = 0;
+ bool lastLine;
+ do {
+ lastLine = _fonts._font2.getLine(msg, _screen->_maxChars * 6, line, width);
+ // Draw the text
+ _bubbleBox->printString(line);
+
+ _screen->_printOrg.y += 6;
+ _screen->_printOrg.x = _screen->_printStart.x;
+
+ if (_screen->_printOrg.y == 180) {
+ _events->waitKeyMouse();
+ _screen->copyBuffer(&_buffer2);
+ _screen->_printOrg.y = _screen->_printStart.y;
+ }
+ } while (!lastLine);
+ _events->waitKeyMouse();
}
-void MartianEngine::drawHelp() {
- error("TODO: drawHelp");
+void MartianEngine::dead(int deathId) {
+ // Load and display death screen
+ _events->hideCursor();
+ _screen->forceFadeOut();
+ _files->loadScreen(48, _deaths[deathId]._screenId);
+ _screen->setIconPalette();
+ _buffer2.copyBuffer(_screen);
+ _screen->forceFadeIn();
+ _events->showCursor();
+
+ // Setup fonts
+ _fonts._charSet._hi = 10;
+ _fonts._charSet._lo = 1;
+ _fonts._charFor._lo = 247;
+ _fonts._charFor._hi = 255;
+ _screen->_maxChars = 50;
+ _screen->_printOrg = Common::Point(24, 18);
+ _screen->_printStart = Common::Point(24, 18);
+
+ // Display death message
+ showDeathText(_deaths[deathId]._msg);
+
+ _screen->forceFadeOut();
+ _room->clearRoom();
+ freeChar();
+
+ // The original was jumping to the restart label in main
+ _restartFl = true;
+ _events->pollEvents();
}
} // End of namespace Martian
diff --git a/engines/access/martian/martian_game.h b/engines/access/martian/martian_game.h
index a83b67a288..9ef6c05c29 100644
--- a/engines/access/martian/martian_game.h
+++ b/engines/access/martian/martian_game.h
@@ -32,40 +32,41 @@ namespace Martian {
class MartianEngine : public AccessEngine {
private:
bool _skipStart;
-
+ SpriteResource *_introObjects;
+ Common::MemoryReadStream *_creditsStream;
/**
* Do the game introduction
*/
- void doIntroduction();
+ void doCredits();
- /**
- * Do title sequence
- */
- void doTitle();
-
- /**
- * Do opening sequence
- */
- void doOpening();
+ bool showCredits();
/**
* Setup variables for the game
*/
void setupGame();
+ void initObjects();
+ void configSelect();
+ void initVariables();
protected:
/**
* Play the game
*/
virtual void playGame();
- virtual void dead(int deathId) {}
+ virtual void dead(int deathId);
+
+ void setNoteParams();
+ void displayNote(const Common::String &msg);
public:
- MartianEngine(OSystem *syst, const AccessGameDescription *gameDesc);
+ SpriteResource *_spec7Objects;
+ MartianEngine(OSystem *syst, const AccessGameDescription *gameDesc);
virtual ~MartianEngine();
- void drawHelp();
+ void doSpecial5(int param1);
+ void showDeathText(Common::String msg);
virtual void establish(int esatabIndex, int sub) {};
};
diff --git a/engines/access/martian/martian_player.cpp b/engines/access/martian/martian_player.cpp
new file mode 100644
index 0000000000..598664a600
--- /dev/null
+++ b/engines/access/martian/martian_player.cpp
@@ -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.
+ *
+ */
+
+#include "common/scummsys.h"
+#include "access/access.h"
+#include "access/room.h"
+#include "access/martian/martian_game.h"
+#include "access/martian/martian_player.h"
+#include "access/martian/martian_resources.h"
+
+namespace Access {
+
+namespace Martian {
+
+MartianPlayer::MartianPlayer(AccessEngine *vm) : Player(vm) {
+ _game = (MartianEngine *)vm;
+}
+
+void MartianPlayer::load() {
+ Player::load();
+
+ // Overwrite game-specific values
+ _playerOffset.x = _vm->_screen->_scaleTable1[20];
+ _playerOffset.y = _vm->_screen->_scaleTable1[52];
+ _leftDelta = -9;
+ _rightDelta = 33;
+ _upDelta = 5;
+ _downDelta = -5;
+ _scrollConst = 5;
+
+ for (int i = 0; i < _vm->_playerDataCount; ++i) {
+ _walkOffRight[i] = SIDEOFFR[i];
+ _walkOffLeft[i] = SIDEOFFL[i];
+ _walkOffUp[i] = SIDEOFFU[i];
+ _walkOffDown[i] = SIDEOFFD[i];
+ }
+
+ _sideWalkMin = 0;
+ _sideWalkMax = 7;
+ _upWalkMin = 8;
+ _upWalkMax = 14;
+ _downWalkMin = 15;
+ _downWalkMax = 23;
+}
+
+} // End of namespace Martian
+
+} // End of namespace Access
diff --git a/engines/access/martian/martian_player.h b/engines/access/martian/martian_player.h
new file mode 100644
index 0000000000..007a32e9b2
--- /dev/null
+++ b/engines/access/martian/martian_player.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 ACCESS_MARTIAN_PLAYER_H
+#define ACCESS_MARTIAN_PLAYER_H
+
+#include "common/scummsys.h"
+#include "access/player.h"
+
+namespace Access {
+
+namespace Martian {
+
+class MartianEngine;
+
+class MartianPlayer : public Player {
+private:
+ MartianEngine *_game;
+public:
+ MartianPlayer(AccessEngine *vm);
+ virtual void load();
+};
+
+} // End of namespace Martian
+
+} // End of namespace Access
+
+#endif /* ACCESS_MARTIAN_PLAYER_H */
diff --git a/engines/access/martian/martian_resources.cpp b/engines/access/martian/martian_resources.cpp
index d2b5dfd5d0..474ec2f71c 100644
--- a/engines/access/martian/martian_resources.cpp
+++ b/engines/access/martian/martian_resources.cpp
@@ -41,51 +41,100 @@ const char *const FILENAMES[] = {
};
const byte MOUSE0[] = {
- 0, 0, 0, 0, 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
+ // 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[] = {
- 7, 0, 7, 0, 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
+ // 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[] = {
- 8, 0, 8, 0, 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
+ // 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[] = {
- 0, 0, 0, 0, 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
+ // 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 TRAVEL_POS[][2] = {
+const int _travelPos[][2] = {
{ -1, 0 },
{ 228, 117 },
{ 28, 98 },
@@ -139,17 +188,19 @@ const int TRAVEL_POS[][2] = {
{ -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",
+ "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"
+ "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[] = {
@@ -436,12 +487,12 @@ const char *const ROOM_DESCR[] = {
const int ROOM_NUMB = 48;
-const byte CHAR_TABLE0[] = {
+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 CHAR_TABLE2[] = {
+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,
@@ -454,13 +505,13 @@ const byte CHAR_TABLE2[] = {
0x00, 0x12, 0x00, 0x33, 0x00, 0x0a, 0x00, 0x33, 0x00, 0x13,
0x00, 0xff, 0xff,
};
-const byte CHAR_TABLE3[] = {
+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 CHAR_TABLE4[] = {
+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,
@@ -473,7 +524,7 @@ const byte CHAR_TABLE4[] = {
0x00, 0x13, 0x00, 0x35, 0x00, 0x0b, 0x00, 0x35, 0x00, 0x14,
0x00, 0xff, 0xff,
};
-const byte CHAR_TABLE5[] = {
+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,
@@ -490,31 +541,31 @@ const byte CHAR_TABLE5[] = {
0x00, 0x0f, 0x00, 0x43, 0x00, 0x0d, 0x00, 0x34, 0x00, 0x10,
0x00, 0xff, 0xff,
};
-const byte CHAR_TABLE6[] = {
+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 CHAR_TABLE7[] = {
+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 CHAR_TABLE8[] = {
+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 CHAR_TABLE9[] = {
+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 CHAR_TABLE10[] = {
+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,
@@ -532,19 +583,19 @@ const byte CHAR_TABLE10[] = {
0x00, 0x36, 0x00, 0x11, 0x00, 0x36, 0x00, 0x21, 0x00, 0x36,
0x00, 0x12, 0x00, 0x36, 0x00, 0x22, 0x00, 0xff, 0xff,
};
-const byte CHAR_TABLE11[] = {
+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 CHAR_TABLE12[] = {
+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 CHAR_TABLE13[] = {
+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,
@@ -557,7 +608,7 @@ const byte CHAR_TABLE13[] = {
0x00, 0x14, 0x00, 0x46, 0x00, 0x0c, 0x00, 0x46, 0x00, 0x15,
0x00, 0xff, 0xff,
};
-const byte CHAR_TABLE15[] = {
+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,
@@ -565,43 +616,43 @@ const byte CHAR_TABLE15[] = {
0x00, 0x47, 0x00, 0x06, 0x00, 0x47, 0x00, 0x04, 0x00, 0x47,
0x00, 0x07, 0x00, 0xff, 0xff,
};
-const byte CHAR_TABLE16[] = {
+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 CHAR_TABLE18[] = {
+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 CHAR_TABLE19[] = {
+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 CHAR_TABLE20[] = {
+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 CHAR_TABLE21[] = {
+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 CHAR_TABLE23[] = {
+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 CHAR_TABLE24[] = {
+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,
@@ -612,13 +663,13 @@ const byte CHAR_TABLE24[] = {
0x00, 0x08, 0x00, 0x32, 0x00, 0x0f, 0x00, 0x32, 0x00, 0x09,
0x00, 0x32, 0x00, 0x10, 0x00, 0xff, 0xff
};
-const byte CHAR_TABLE25[] = {
+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 CHAR_TABLE26[] = {
+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,
@@ -638,7 +689,7 @@ const byte CHAR_TABLE26[] = {
0x00, 0x3a, 0x00, 0x14, 0x00, 0x42, 0x00, 0x11, 0x00, 0x3a,
0x00, 0x15, 0x00, 0xff, 0xff
};
-const byte CHAR_TABLE27[] = {
+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,
@@ -650,73 +701,144 @@ const byte CHAR_TABLE27[] = {
0x00, 0x49, 0x00, 0x10, 0x00, 0x49, 0x00, 0x09, 0x00, 0x49,
0x00, 0x11, 0x00, 0xff, 0xff,
};
-const byte *const CHAR_TABLE[] = {
- CHAR_TABLE0, nullptr, CHAR_TABLE2, CHAR_TABLE3, CHAR_TABLE4, CHAR_TABLE5,
- CHAR_TABLE6, CHAR_TABLE7, CHAR_TABLE8, CHAR_TABLE9, CHAR_TABLE10,
- CHAR_TABLE11, CHAR_TABLE12, CHAR_TABLE13, nullptr, CHAR_TABLE15,
- CHAR_TABLE16, nullptr, CHAR_TABLE18, CHAR_TABLE19, CHAR_TABLE20,
- CHAR_TABLE21, nullptr, CHAR_TABLE23, CHAR_TABLE24, CHAR_TABLE25,
- CHAR_TABLE26, CHAR_TABLE27
+
+// 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
};
-// TODO: Fix that array
-const int COMBO_TABLE[54][4] = {
- { -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, -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 },
- { -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, -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 },
- { -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 }
+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 };
+const int SIDEOFFD[] = { 2, 0, 1, 1, 0, 1, 1, 1, 2, 0, 0, 0 };
+
+const byte CREDIT_DATA[] = {
+ 0x1F, 0x00, 0x49, 0x00, 0x00, 0x00, 0xB7, 0x00, 0x49, 0x00,
+ 0x01, 0x00, 0x79, 0x00, 0x6F, 0x00, 0x02, 0x00, 0xFF, 0xFF,
+ 0xEA, 0x01, 0x75, 0x00, 0x46, 0x00, 0x03, 0x00, 0x46, 0x00,
+ 0x5E, 0x00, 0x04, 0x00, 0xFF, 0xFF, 0xEA, 0x01, 0x72, 0x00,
+ 0x3E, 0x00, 0x05, 0x00, 0x46, 0x00, 0x57, 0x00, 0x04, 0x00,
+ 0x5C, 0x00, 0x6E, 0x00, 0x06, 0x00, 0xFF, 0xFF, 0xEA, 0x01,
+ 0x63, 0x00, 0x48, 0x00, 0x07, 0x00, 0x2A, 0x00, 0x65, 0x00,
+ 0x08, 0x00, 0xFF, 0xFF, 0xEA, 0x01, 0x7E, 0x00, 0x39, 0x00,
+ 0x09, 0x00, 0x5C, 0x00, 0x57, 0x00, 0x06, 0x00, 0x45, 0x00,
+ 0x6B, 0x00, 0x04, 0x00, 0xFF, 0xFF, 0xEA, 0x01, 0x5F, 0x00,
+ 0x46, 0x00, 0x0A, 0x00, 0x67, 0x00, 0x62, 0x00, 0x0B, 0x00,
+ 0x47, 0x00, 0x76, 0x00, 0x0C, 0x00, 0xFF, 0xFF, 0xEA, 0x01,
+ 0x62, 0x00, 0x38, 0x00, 0x0D, 0x00, 0x47, 0x00, 0x55, 0x00,
+ 0x0E, 0x00, 0x49, 0x00, 0x6A, 0x00, 0x0F, 0x00, 0xFF, 0xFF,
+ 0xEA, 0x01, 0x18, 0x00, 0x22, 0x00, 0x10, 0x00, 0x17, 0x00,
+ 0x3E, 0x00, 0x11, 0x00, 0x16, 0x00, 0x52, 0x00, 0x12, 0x00,
+ 0xEE, 0x00, 0x7B, 0x00, 0x13, 0x00, 0xB5, 0x00, 0x93, 0x00,
+ 0x0B, 0x00, 0xFF, 0xFF, 0xF4, 0x01, 0xFF, 0xFF, 0xFF, 0xFF
};
-} // End of namespace Martian
+const byte ICON_PALETTE[] = {
+ 0x3F, 0x3F, 0x00, 0x00, 0x07, 0x16,
+ 0x00, 0x0A, 0x1A, 0x00, 0x0D, 0x1F,
+ 0x00, 0x11, 0x28, 0x00, 0x15, 0x30,
+ 0x00, 0x19, 0x39, 0x00, 0x1B, 0x3F,
+ 0x00, 0x2D, 0x3A
+};
+
+const int RMOUSE[10][2] = {
+ { 7, 36 }, { 38, 68 }, { 70, 99 }, { 102, 125 }, { 128, 152 },
+ { 155, 185 }, { 188, 216 }, { 219, 260 }, { 263, 293 }, { 295, 314 }
+};
+
+const char *const TRAVDATA[] = {
+ "GALACTIC PICTURES", "TERRAFORM", "WASHROOM", "MR. BIG", "ALEXIS' HOME",
+ "JOHNNY FEDORA", "JUNKYARD IN", "TEX'S OFFICE", "MURDER SCENE", "PLAZA HOTEL",
+ "RESTAURANT", "GIFT SHOP", "LOVE SCENE", "RICK LOGAN", "HUT",
+ "SMUGGLERS BASE", "PYRAMID", "CASINO", "CAS LOBBY", "BAR",
+ "DUCTWORK", "RESTROOM", "OFFICE", "SAFE", "ALLEY",
+ "POWER PLANT", "PLANT OFFICE", "PLANT ROOM", "TEMPLE", "IN TEMPLE",
+ "JANE MANSFIELD'S HOME", "AEROBICS ACADEMY", "DR. LAWRENCE BARKLEY", "COLONISTS CAMP", "IN SLUM",
+ "REMOTE OUTPOST", "WALK", "CAVE", "PRISON", "ORACLE",
+ "JOCQUES SPARROW", "MAC MALDEN", "CHANTAL VARGAS", "GUY CALLABERO", "ROCKWELL BACHE",
+ "FERRIS COLLETTE", "NORA DESMOND ALEXANDER", "LOWELL PERCIVAL", "MICHELE BLOODWORTH", "BRADLEY ERICSON",
+ "COOPER BRADBURY", nullptr
+};
+
+const char *const _askTBL[] = {
+ "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",
+ "ALEXIS ALEXANDER", "FERRIS COLLETT", "GUY CALLABERO", "ORACLE STONE", "THOMAS DANGERFIELD",
+ "JANE MANSFIELD", "STACY CRAWFORD", "DICK CASTRO", "ROCKY BULLWINKEL", "DEACON HAWKE",
+ "NATHAN BLOODWORTH", "MICHELLE BLOODWORTH", "BRADLEY ERICSON", "COOPER BRADBURY", "MARTIAN MEMORANDUM",
+ "JOHNNY FEDORA", "RHONDA FOXWORTH", "ANGELO ANDRETTI", "TEX MURPHY", "ROBERT BLOODWORTH",
+ "LARRRY HAMMOND", nullptr
+};
+
+byte HELP[] = {
+ 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
+};
+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 " \
+ "LOGICAL CHOICE FOR THE STONE. WE ARRIVE AT THE TEMPLE WHERE SHE IS WAITING FOR US. SHE TURNS AND WHISPERS; 'YOU HAVE RETURNED " \
+ "THE STONE TO THE MISTRESS OF THE LIGHT. YOU HAVE SURELY SAVED THE WORLD FROM ANNIHILATION BUT YOU MUST CONTINUE TO BE DILIGENT. " \
+ "MANKIND MAY YET PROVE TO BE THE AUTHOR OF HIS OWN DEMISE. REVERENCE LIFE. PROTECT THE LIVING THINGS AND RECYCLE. AND NOW FOR " \
+ "THE SAFETY OF MANKIND, I MUST TAKE THE STONE. PERHAPS SOMEDAY, WHEN THE HUMAN RACE IS READY, IT WILL BE RETURNED. UNTIL THEN "\
+ "FAREWELL...'"
+};
+
+const byte _byte1EEB5[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 0, 0, 0, 0, 0, 1, 0, 1, 1, 1,
+ 1
+};
+
+const int PICTURERANGE[][2] = {
+// { min X, max X}, {min Y, max Y}
+ { 20, 30 }, { 82, 87 },
+ { 20, 30 }, { 105, 110 },
+ { 0, 8 }, { 92, 100 },
+ { 42, 46 }, { 92, 100 },
+ { 9, 41 }, { 88, 104 },
+ { 9, 41 }, { 117, 133 },
+ { -1, -1 }
+};
+
+} // End of namespace Martian
} // End of namespace Access
diff --git a/engines/access/martian/martian_resources.h b/engines/access/martian/martian_resources.h
index a52967d42a..2eb810ac80 100644
--- a/engines/access/martian/martian_resources.h
+++ b/engines/access/martian/martian_resources.h
@@ -31,22 +31,46 @@ 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 TRAVEL_POS[][2];
+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 CHAR_TABLE[];
+extern const byte *const CHARTBL_MM[];
-extern const int COMBO_TABLE[54][4];
+extern const int SIDEOFFR[];
+extern const int SIDEOFFL[];
+extern const int SIDEOFFU[];
+extern const int SIDEOFFD[];
-} // End of namespace Martian
+extern const byte CREDIT_DATA[];
+extern const byte ICON_PALETTE[];
+
+extern const int RMOUSE[10][2];
+
+extern byte HELP[];
+extern const char *const _askTBL[];
+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];
+
+} // End of namespace Martian
} // End of namespace Access
#endif /* ACCESS_MARTIAN_RESOURCES_H */
diff --git a/engines/access/martian/martian_room.cpp b/engines/access/martian/martian_room.cpp
index e9d1b9d8cf..d5b03db246 100644
--- a/engines/access/martian/martian_room.cpp
+++ b/engines/access/martian/martian_room.cpp
@@ -43,72 +43,47 @@ void MartianRoom::loadRoom(int roomNumber) {
}
void MartianRoom::reloadRoom() {
- loadRoom(_vm->_player->_roomNumber);
-
- if (_roomFlag != 1) {
- _vm->_currentMan = _roomFlag;
- _vm->_currentManOld = _roomFlag;
- _vm->_manScaleOff = 0;
-
- switch (_vm->_currentMan) {
- case 0:
- _vm->_player->loadSprites("MAN.LZ");
- break;
-
- case 2:
- _vm->_player->loadSprites("JMAN.LZ");
- break;
+// _vm->_currentMan = _roomFlag;
+// _vm->_currentManOld = _roomFlag;
+// _vm->_manScaleOff = 0;
- case 3:
- _vm->_player->loadSprites("OVERHEAD.LZ");
- _vm->_manScaleOff = 1;
- break;
+ _vm->_player->loadTexPalette();
+ _vm->_player->loadSprites("TEX.LZ");
- default:
- break;
- }
- }
+ loadRoom(_vm->_player->_roomNumber);
reloadRoom1();
}
void MartianRoom::reloadRoom1() {
- if (_vm->_player->_roomNumber == 29 || _vm->_player->_roomNumber == 31
- || _vm->_player->_roomNumber == 42 || _vm->_player->_roomNumber == 44) {
- //Resource *spriteData = _vm->_files->loadFile("MAYA.LZ");
- //_vm->_inactive._spritesPtr = new SpriteResource(_vm, spriteData);
- //delete spriteData;
- _vm->_currentCharFlag = false;
- }
-
_selectCommand = -1;
- _vm->_events->setNormalCursor(CURSOR_CROSSHAIRS);
- _vm->_mouseMode = 0;
- _vm->_boxSelect = true;
+ _vm->_boxSelect = false; //-1
_vm->_player->_playerOff = false;
- _vm->_screen->fadeOut();
+ _vm->_screen->forceFadeOut();
+ _vm->_events->hideCursor();
_vm->_screen->clearScreen();
+ _vm->_events->showCursor();
roomSet();
+ _vm->_player->load();
- // TODO: Refactor
+ if (_vm->_player->_roomNumber != 47)
+ _vm->_player->calcManScale();
+ _vm->_events->hideCursor();
+ roomMenu();
_vm->_screen->setBufferScan();
setupRoom();
setWallCodes();
buildScreen();
+ _vm->copyBF2Vid();
- if (!_vm->_screen->_vesaMode) {
- _vm->copyBF2Vid();
- } else if (_vm->_player->_roomNumber != 20 && _vm->_player->_roomNumber != 24
- && _vm->_player->_roomNumber != 33) {
- _vm->_screen->setPalette();
- _vm->copyBF2Vid();
- }
-
+ _vm->_screen->setManPalette();
+ _vm->_events->showCursor();
_vm->_player->_frame = 0;
_vm->_oldRects.clear();
_vm->_newRects.clear();
+ _vm->_events->clearEvents();
}
void MartianRoom::roomSet() {
@@ -116,6 +91,12 @@ void MartianRoom::roomSet() {
_vm->_scripts->_sequence = 1000;
_vm->_scripts->searchForSequence();
_vm->_scripts->executeScript();
+
+ for (int i = 0; i < 30; i++)
+ _byte26CD2[i] = 0;
+
+ for (int i = 0; i < 10; i++)
+ _byte26CBC[i] = 0;
}
void MartianRoom::roomMenu() {
@@ -126,16 +107,31 @@ void MartianRoom::roomMenu() {
_vm->_screen->saveScreen();
_vm->_screen->setDisplayScan();
_vm->_destIn = _vm->_screen; // TODO: Redundant
- _vm->_screen->plotImage(spr, 0, Common::Point(0, 177));
- _vm->_screen->plotImage(spr, 1, Common::Point(143, 177));
+ _vm->_screen->plotImage(spr, 0, Common::Point(5, 184));
+ _vm->_screen->plotImage(spr, 1, Common::Point(155, 184));
_vm->_screen->restoreScreen();
delete spr;
}
void MartianRoom::mainAreaClick() {
+ Common::Point &mousePos = _vm->_events->_mousePos;
+ Common::Point pt = _vm->_events->calcRawMouse();
+ Screen &screen = *_vm->_screen;
+ Player &player = *_vm->_player;
+
+ if (_selectCommand == -1) {
+ player._moveTo = pt;
+ player._playerMove = true;
+ } else if (mousePos.x >= screen._windowXAdd &&
+ mousePos.x <= (screen._windowXAdd + screen._vWindowBytesWide) &&
+ mousePos.y >= screen._windowYAdd &&
+ mousePos.y <= (screen._windowYAdd + screen._vWindowLinesTall)) {
+ if (checkBoxes1(pt) >= 0) {
+ checkBoxes3();
+ }
+ }
}
} // End of namespace Martian
-
} // End of namespace Access
diff --git a/engines/access/martian/martian_room.h b/engines/access/martian/martian_room.h
index 85529ce8f0..11501b6e57 100644
--- a/engines/access/martian/martian_room.h
+++ b/engines/access/martian/martian_room.h
@@ -39,6 +39,9 @@ private:
MartianEngine *_game;
void roomSet();
+
+ int _byte26CD2[30];
+ int _byte26CBC[10];
protected:
virtual void loadRoom(int roomNumber);
@@ -52,8 +55,6 @@ public:
virtual ~MartianRoom();
- virtual void loadRoomData(const byte *roomData) { warning("TODO - loadRoomData"); }
-
virtual void init4Quads() { }
virtual void roomMenu();
diff --git a/engines/access/martian/martian_scripts.cpp b/engines/access/martian/martian_scripts.cpp
index 0578872092..a9b5de5597 100644
--- a/engines/access/martian/martian_scripts.cpp
+++ b/engines/access/martian/martian_scripts.cpp
@@ -34,7 +34,300 @@ MartianScripts::MartianScripts(AccessEngine *vm) : Scripts(vm) {
_game = (MartianEngine *)_vm;
}
+void MartianScripts::cmdSpecial0() {
+ _vm->_sound->stopSound();
+ _vm->_midi->stopSong();
+
+ _vm->_midi->loadMusic(47, 1);
+ _vm->_midi->midiPlay();
+ _vm->_midi->setLoop(true);
+
+ _vm->_events->_vbCount = 300;
+ while (!_vm->shouldQuit() && _vm->_events->_vbCount > 0)
+ _vm->_events->pollEventsAndWait();
+
+ _vm->_screen->forceFadeOut();
+ _vm->_files->loadScreen("HOUSE.SC");
+
+ _vm->_video->setVideo(_vm->_screen, Common::Point(46, 30), "HVID.VID", 20);
+
+ do {
+ _vm->_video->playVideo();
+ if (_vm->_video->_videoFrame == 4) {
+ _vm->_screen->flashPalette(16);
+ _vm->_sound->playSound(4);
+ do {
+ _vm->_events->pollEvents();
+ } while (!_vm->shouldQuit() && _vm->_sound->_playingSound);
+ _vm->_timers[31]._timer = _vm->_timers[31]._initTm = 40;
+ }
+ } while (!_vm->_video->_videoEnd && !_vm->shouldQuit());
+
+ if (_vm->_video->_videoEnd) {
+ _vm->_screen->flashPalette(12);
+ _vm->_sound->playSound(4);
+ do {
+ _vm->_events->pollEvents();
+ } while (!_vm->shouldQuit() && _vm->_sound->_playingSound);
+ _vm->_midi->stopSong();
+ _vm->_midi->freeMusic();
+ warning("TODO: Pop Midi");
+ }
+}
+
+void MartianScripts::cmdSpecial1(int param1) {
+ _vm->_events->hideCursor();
+
+ if (param1 != -1) {
+ _vm->_files->loadScreen(49, param1);
+ _vm->_buffer2.copyBuffer(_vm->_screen);
+ }
+
+ _vm->_screen->setIconPalette();
+ _vm->_screen->forceFadeIn();
+ _vm->_events->showCursor();
+}
+
+void MartianScripts::cmdSpecial3() {
+ _vm->_screen->forceFadeOut();
+ _vm->_events->hideCursor();
+ _vm->_files->loadScreen(57, 3);
+ _vm->_buffer2.copyFrom(*_vm->_screen);
+
+ _vm->_screen->setIconPalette();
+ _vm->_events->showCursor();
+ _vm->_screen->forceFadeIn();
+}
+
+void MartianScripts::doIntro(int param1) {
+ _game->doSpecial5(param1);
+}
+
+void MartianScripts::cmdSpecial6() {
+ _vm->_midi->stopSong();
+ _vm->_screen->setDisplayScan();
+ _vm->_events->clearEvents();
+ _vm->_screen->forceFadeOut();
+ _vm->_events->hideCursor();
+ _vm->_files->loadScreen(49, 9);
+ _vm->_events->showCursor();
+ _vm->_screen->setIconPalette();
+ _vm->_screen->forceFadeIn();
+
+ Resource *cellsRes = _vm->_files->loadFile("CELLS00.LZ");
+ _vm->_objectsTable[0] = new SpriteResource(_vm, cellsRes);
+ delete cellsRes;
+
+ _vm->_timers[20]._timer = _vm->_timers[20]._initTm = 30;
+ _vm->_fonts._charSet._lo = 1;
+ _vm->_fonts._charSet._hi = 10;
+ _vm->_fonts._charFor._lo = 1;
+ _vm->_fonts._charFor._hi = 255;
+
+ _vm->_screen->_maxChars = 50;
+ _vm->_screen->_printOrg = _vm->_screen->_printStart = Common::Point(24, 18);
+
+ Resource *notesRes = _vm->_files->loadFile("ETEXT.DAT");
+ notesRes->_stream->seek(72);
+
+ // Read the message
+ Common::String msg = "";
+ byte c;
+ while ((c = (char)notesRes->_stream->readByte()) != '\0')
+ msg += c;
+
+ //display the message
+ _game->showDeathText(msg);
+
+ delete notesRes;
+ delete _vm->_objectsTable[0];
+ _vm->_objectsTable[0] = nullptr;
+ _vm->_midi->stopSong();
+}
+
+void MartianScripts::cmdSpecial7() {
+ _vm->_room->clearRoom();
+ _vm->_midi->loadMusic(47, 8);
+
+ _vm->_sound->freeSounds();
+ Resource *sound = _vm->_sound->loadSound(46, 14);
+ _vm->_sound->_soundTable.push_back(SoundEntry(sound, 1));
+
+ _vm->_screen->setDisplayScan();
+ _vm->_screen->forceFadeOut();
+ _vm->_events->hideCursor();
+
+ _vm->_files->loadScreen(40, 3);
+ _vm->_buffer1.copyBuffer(_vm->_screen);
+ _vm->_buffer2.copyBuffer(_vm->_screen);
+
+ _vm->_events->showCursor();
+ _vm->_screen->setIconPalette();
+ _vm->_screen->forceFadeIn();
+
+ // Load objects specific to this special scene
+ Resource *data = _vm->_files->loadFile(40, 2);
+ _game->_spec7Objects = new SpriteResource(_vm, data);
+ delete data;
+
+ // Load animation data
+ _vm->_animation->freeAnimationData();
+ Resource *animResource = _vm->_files->loadFile(40, 1);
+ _vm->_animation->loadAnimations(animResource);
+ delete animResource;
+
+ // Load script
+ Resource *newScript = _vm->_files->loadFile(40, 0);
+ _vm->_scripts->setScript(newScript);
+
+ _vm->_images.clear();
+ _vm->_oldRects.clear();
+ _vm->_scripts->_sequence = 0;
+
+ _vm->_sound->playSound(0);
+
+ do {
+ charLoop();
+ } while (_vm->_flags[134] != 1);
+
+ do {
+ _vm->_events->pollEvents();
+ } while (!_vm->shouldQuit() && _vm->_sound->_playingSound);
+
+ _game->_numAnimTimers = 0;
+ _vm->_animation->freeAnimationData();
+ _vm->_scripts->freeScriptData();
+ _vm->_sound->freeSounds();
+
+ _vm->_screen->forceFadeOut();
+ _vm->_midi->midiPlay();
+ _vm->_midi->setLoop(true);
+ _vm->_events->hideCursor();
+
+ _vm->_files->loadScreen(40, 4);
+ _vm->_buffer1.copyBuffer(_vm->_screen);
+ _vm->_buffer2.copyBuffer(_vm->_screen);
+
+ _vm->_events->showCursor();
+ _vm->_screen->setIconPalette();
+ _vm->_screen->forceFadeIn();
+
+ // Setup fonts
+ _vm->_fonts._charSet._hi = 10;
+ _vm->_fonts._charSet._lo = 1;
+ _vm->_fonts._charFor._lo = 247;
+ _vm->_fonts._charFor._hi = 255;
+ _vm->_screen->_maxChars = 50;
+ _vm->_screen->_printOrg = Common::Point(24, 18);
+ _vm->_screen->_printStart = Common::Point(24, 18);
+
+ // Display death message
+ _game->showDeathText(Common::String(SPEC7MESSAGE));
+
+ _vm->_events->showCursor();
+ _vm->_screen->copyBuffer(&_vm->_buffer1);
+ _vm->_events->hideCursor();
+
+ _vm->_video->setVideo(_vm->_screen, Common::Point(120, 16), FileIdent(40, 5), 10);
+
+ while (!_vm->shouldQuit() && !_vm->_video->_videoEnd) {
+ _vm->_video->playVideo();
+ _vm->_events->pollEventsAndWait();
+ }
+
+ _vm->_sound->freeSounds();
+ sound = _vm->_sound->loadSound(40, 8);
+ _vm->_sound->_soundTable.push_back(SoundEntry(sound, 1));
+ sound = _vm->_sound->loadSound(40, 9);
+ _vm->_sound->_soundTable.push_back(SoundEntry(sound, 1));
+ sound = _vm->_sound->loadSound(40, 10);
+ _vm->_sound->_soundTable.push_back(SoundEntry(sound, 1));
+
+ _vm->_screen->forceFadeOut();
+ _vm->_files->loadScreen(40, 7);
+ _vm->_destIn = _vm->_screen;
+
+ _vm->_screen->plotImage(_game->_spec7Objects, 8, Common::Point(104, 176));
+ _vm->_screen->plotImage(_game->_spec7Objects, 7, Common::Point(102, 160));
+ _vm->_events->showCursor();
+ _vm->_screen->forceFadeIn();
+
+ _vm->_events->_vbCount = 100;
+ while (!_vm->shouldQuit() && _vm->_events->_vbCount > 0)
+ _vm->_events->pollEventsAndWait();
+
+ _vm->_sound->playSound(0);
+ do {
+ _vm->_events->pollEvents();
+ } while (!_vm->shouldQuit() && _vm->_sound->_playingSound);
+
+ _vm->_events->_vbCount = 80;
+ while (!_vm->shouldQuit() && _vm->_events->_vbCount > 0)
+ _vm->_events->pollEventsAndWait();
+
+ _vm->_sound->playSound(1);
+ do {
+ _vm->_events->pollEvents();
+ } while (!_vm->shouldQuit() && _vm->_sound->_playingSound);
+
+ _vm->_events->_vbCount = 80;
+ while (!_vm->shouldQuit() && _vm->_events->_vbCount > 0)
+ _vm->_events->pollEventsAndWait();
+
+ _vm->_sound->playSound(2);
+ do {
+ _vm->_events->pollEvents();
+ } while (!_vm->shouldQuit() && _vm->_sound->_playingSound);
+
+ _vm->_sound->freeSounds();
+
+ delete _game->_spec7Objects;
+ _game->_spec7Objects = nullptr;
+
+ _vm->_events->hideCursor();
+ _vm->_screen->forceFadeOut();
+ _vm->_files->loadScreen(40, 6);
+ _vm->_events->showCursor();
+ _vm->_screen->forceFadeIn();
+
+ _vm->_events->waitKeyMouse();
+ _vm->_midi->stopSong();
+ _vm->_midi->freeMusic();
+
+ // The original was jumping to the restart label in main
+ _vm->_restartFl = true;
+ _vm->_events->pollEvents();
+}
+
void MartianScripts::executeSpecial(int commandIndex, int param1, int param2) {
+ switch (commandIndex) {
+ case 0:
+ cmdSpecial0();
+ break;
+ case 1:
+ cmdSpecial1(param1);
+ break;
+ case 2:
+ warning("TODO: cmdSpecial2");
+ break;
+ case 3:
+ cmdSpecial3();
+ break;
+ case 4:
+ warning("TODO: cmdSpecial4");
+ break;
+ case 5:
+ doIntro(param1);
+ break;
+ case 6:
+ cmdSpecial6();
+ break;
+ case 7:
+ cmdSpecial7();
+ break;
+ default:
+ warning("Unexpected Special code %d - Skipped", commandIndex);
+ }
}
typedef void(MartianScripts::*MartianScriptMethodPtr)();
diff --git a/engines/access/martian/martian_scripts.h b/engines/access/martian/martian_scripts.h
index fc7495fc47..9c2141276e 100644
--- a/engines/access/martian/martian_scripts.h
+++ b/engines/access/martian/martian_scripts.h
@@ -35,9 +35,18 @@ class MartianEngine;
class MartianScripts : public Scripts {
private:
MartianEngine *_game;
+
+ void cmdSpecial0();
+ void cmdSpecial1(int param1);
+ void cmdSpecial3();
+ void doIntro(int param1);
+ void cmdSpecial6();
+ void cmdSpecial7();
+
protected:
virtual void executeSpecial(int commandIndex, int param1, int param2);
virtual void executeCommand(int commandIndex);
+
public:
MartianScripts(AccessEngine *vm);
};
diff --git a/engines/access/module.mk b/engines/access/module.mk
index b6961aeca9..f7cf7f2261 100644
--- a/engines/access/module.mk
+++ b/engines/access/module.mk
@@ -28,6 +28,7 @@ MODULE_OBJS := \
amazon/amazon_room.o \
amazon/amazon_scripts.o \
martian/martian_game.o \
+ martian/martian_player.o \
martian/martian_resources.o \
martian/martian_room.o \
martian/martian_scripts.o
diff --git a/engines/access/player.cpp b/engines/access/player.cpp
index 5a2b98293f..0162491aee 100644
--- a/engines/access/player.cpp
+++ b/engines/access/player.cpp
@@ -26,24 +26,25 @@
#include "access/access.h"
#include "access/resources.h"
#include "access/amazon/amazon_player.h"
+#include "access/martian/martian_player.h"
namespace Access {
Player *Player::init(AccessEngine *vm) {
switch (vm->getGameID()) {
case GType_Amazon:
+ vm->_playerDataCount = 8;
return new Amazon::AmazonPlayer(vm);
+ case GType_MartianMemorandum:
+ vm->_playerDataCount = 10;
+ return new Martian::MartianPlayer(vm);
default:
+ vm->_playerDataCount = 8;
return new Player(vm);
}
}
Player::Player(AccessEngine *vm) : Manager(vm), ImageEntry() {
- Common::fill(&_walkOffRight[0], &_walkOffRight[PLAYER_DATA_COUNT], 0);
- Common::fill(&_walkOffLeft[0], &_walkOffLeft[PLAYER_DATA_COUNT], 0);
- Common::fill(&_walkOffUp[0], &_walkOffUp[PLAYER_DATA_COUNT], 0);
- Common::fill(&_walkOffDown[0], &_walkOffDown[PLAYER_DATA_COUNT], 0);
-
_playerSprites = nullptr;
_playerSprites1 = nullptr;
_manPal1 = nullptr;
@@ -78,14 +79,36 @@ Player::Player(AccessEngine *vm) : Manager(vm), ImageEntry() {
_downWalkMin = _downWalkMax = 0;
_diagUpWalkMin = _diagUpWalkMax = 0;
_diagDownWalkMin = _diagDownWalkMax = 0;
+ _walkOffRight = _walkOffLeft = nullptr;
+ _walkOffUp = _walkOffDown = nullptr;
+ _walkOffUR = _walkOffDR = nullptr;
+ _walkOffUL = _walkOffDL = nullptr;
}
Player::~Player() {
delete _playerSprites;
delete[] _manPal1;
+ delete[] _walkOffRight;
+ delete[] _walkOffLeft;
+ delete[] _walkOffUp;
+ delete[] _walkOffDown;
+ delete[] _walkOffUR;
+ delete[] _walkOffDR;
+ delete[] _walkOffUL;
+ delete[] _walkOffDL;
}
void Player::load() {
+ int dataCount = _vm->_playerDataCount;
+ _walkOffRight = new int[dataCount];
+ _walkOffLeft = new int[dataCount];
+ _walkOffUp = new int[dataCount];
+ _walkOffDown = new int[dataCount];
+ _walkOffUR = new Common::Point[dataCount];
+ _walkOffDR = new Common::Point[dataCount];
+ _walkOffUL = new Common::Point[dataCount];
+ _walkOffDL = new Common::Point[dataCount];
+
_playerOffset.x = _vm->_screen->_scaleTable1[25];
_playerOffset.y = _vm->_screen->_scaleTable1[67];
_leftDelta = -3;
@@ -94,21 +117,6 @@ void Player::load() {
_downDelta = -10;
_scrollConst = 5;
- for (int i = 0; i < PLAYER_DATA_COUNT; ++i) {
- _walkOffRight[i] = SIDEOFFR[i];
- _walkOffLeft[i] = SIDEOFFL[i];
- _walkOffUp[i] = SIDEOFFU[i];
- _walkOffDown[i] = SIDEOFFD[i];
- _walkOffUR[i].x = DIAGOFFURX[i];
- _walkOffUR[i].y = DIAGOFFURY[i];
- _walkOffDR[i].x = DIAGOFFDRX[i];
- _walkOffDR[i].y = DIAGOFFDRY[i];
- _walkOffUL[i].x = DIAGOFFULX[i];
- _walkOffUL[i].y = DIAGOFFULY[i];
- _walkOffDL[i].x = DIAGOFFDLX[i];
- _walkOffDL[i].y = DIAGOFFDLY[i];
- }
-
_sideWalkMin = 0;
_sideWalkMax = 7;
_upWalkMin = 16;
@@ -122,16 +130,35 @@ void Player::load() {
_playerSprites = _playerSprites1;
if (_manPal1) {
- Common::copy(_manPal1 + 0x270, _manPal1 + 0x270 + 0x60, _vm->_screen->_manPal);
+ // Those values are from MM as Amazon doesn't use it
+ Common::copy(_manPal1 + 0x2A0, _manPal1 + 0x2A0 + 0x42, _vm->_screen->_manPal);
} else {
Common::fill(_vm->_screen->_manPal, _vm->_screen->_manPal + 0x60, 0);
}
}
+void Player::loadTexPalette() {
+ Resource *texPal = _vm->_files->loadFile("TEXPAL.COL");
+ int size = texPal->_size;
+ assert(size == 768);
+ _manPal1 = new byte[size];
+ memcpy(_manPal1, texPal->data(), size);
+}
+
void Player::loadSprites(const Common::String &name) {
freeSprites();
Resource *data = _vm->_files->loadFile(name);
+
+#if 0
+ Common::DumpFile *outFile = new Common::DumpFile();
+ Common::String outName = name + ".dump";
+ outFile->open(outName);
+ outFile->write(data->data(), data->_size);
+ outFile->finalize();
+ outFile->close();
+#endif
+
_playerSprites1 = new SpriteResource(_vm, data);
delete data;
}
@@ -357,7 +384,7 @@ void Player::walkRight() {
if (_frame > _sideWalkMax)
_frame = _sideWalkMin;
- plotCom(0);
+ plotCom0();
}
}
@@ -634,15 +661,19 @@ void Player::checkMove() {
}
void Player::plotCom(int flags) {
- _flags &= ~2;
- _flags &= ~8;
+ _flags &= ~IMGFLAG_BACKWARDS;
+ _flags &= ~IMGFLAG_UNSCALED;
_flags |= flags;
plotCom3();
}
+void Player::plotCom0() {
+ plotCom(_vm->getGameID() == GType_Amazon ? 0 : IMGFLAG_BACKWARDS);
+}
+
void Player::plotCom1() {
- plotCom(2);
+ plotCom(_vm->getGameID() == GType_Amazon ? IMGFLAG_BACKWARDS : 0);
}
void Player::plotCom2() {
@@ -709,8 +740,12 @@ void Player::checkScroll() {
}
}
-bool Player::scrollUp() {
- _scrollAmount = -(_vm->_screen->_clipHeight - _playerY - _scrollThreshold);
+bool Player::scrollUp(int forcedAmount) {
+ if (forcedAmount == -1)
+ _scrollAmount = -(_vm->_screen->_clipHeight - _playerY - _scrollThreshold);
+ else
+ _scrollAmount = forcedAmount;
+
if ((_vm->_scrollRow + _vm->_screen->_vWindowHeight) >=
_vm->_room->_playFieldHeight)
return true;
@@ -737,8 +772,12 @@ bool Player::scrollUp() {
return false;
}
-bool Player::scrollDown() {
- _scrollAmount = -(_playerY - _scrollThreshold);
+bool Player::scrollDown(int forcedAmount) {
+ if (forcedAmount == -1)
+ _scrollAmount = -(_playerY - _scrollThreshold);
+ else
+ _scrollAmount = forcedAmount;
+
_scrollFlag = true;
_vm->_scrollY -= _scrollAmount;
if (_vm->_scrollY >= 0)
@@ -762,9 +801,13 @@ bool Player::scrollDown() {
return true;
}
-bool Player::scrollLeft() {
+bool Player::scrollLeft(int forcedAmount) {
Screen &screen = *_vm->_screen;
- _scrollAmount = -(_vm->_screen->_clipWidth - _playerX - _scrollThreshold);
+ if (forcedAmount == -1)
+ _scrollAmount = -(_vm->_screen->_clipWidth - _playerX - _scrollThreshold);
+ else
+ _scrollAmount = forcedAmount;
+
if ((_vm->_scrollCol + screen._vWindowWidth) == _vm->_room->_playFieldWidth) {
_scrollEnd = 2;
_vm->_scrollX = 0;
@@ -789,8 +832,12 @@ bool Player::scrollLeft() {
}
}
-bool Player::scrollRight() {
- _scrollAmount = -(_playerX - _scrollThreshold);
+bool Player::scrollRight(int forcedAmount) {
+ if (forcedAmount == -1)
+ _scrollAmount = -(_playerX - _scrollThreshold);
+ else
+ _scrollAmount = forcedAmount;
+
_scrollFlag = true;
_vm->_scrollX -= _scrollAmount;
diff --git a/engines/access/player.h b/engines/access/player.h
index 329cc15ed2..3c554556dd 100644
--- a/engines/access/player.h
+++ b/engines/access/player.h
@@ -31,8 +31,6 @@
namespace Access {
-#define PLAYER_DATA_COUNT 8
-
enum Direction {
NONE = 0,
UP = 1,
@@ -58,11 +56,11 @@ protected:
int _diagUpWalkMin, _diagUpWalkMax;
int _diagDownWalkMin, _diagDownWalkMax;
SpriteResource *_playerSprites1;
- byte *_manPal1;
int _scrollEnd;
int _inactiveYOff;
void plotCom(int v1);
+ void plotCom0();
void plotCom1();
void plotCom2();
void plotCom3();
@@ -76,22 +74,19 @@ protected:
void walkUpRight();
void walkDownRight();
void checkScrollUp();
- bool scrollUp();
- bool scrollDown();
- bool scrollLeft();
- bool scrollRight();
public:
Direction _playerDirection;
SpriteResource *_playerSprites;
// Fields in original Player structure
- int _walkOffRight[PLAYER_DATA_COUNT];
- int _walkOffLeft[PLAYER_DATA_COUNT];
- int _walkOffUp[PLAYER_DATA_COUNT];
- int _walkOffDown[PLAYER_DATA_COUNT];
- Common::Point _walkOffUR[PLAYER_DATA_COUNT];
- Common::Point _walkOffDR[PLAYER_DATA_COUNT];
- Common::Point _walkOffUL[PLAYER_DATA_COUNT];
- Common::Point _walkOffDL[PLAYER_DATA_COUNT];
+ byte *_manPal1;
+ int *_walkOffRight;
+ int *_walkOffLeft;
+ int *_walkOffUp;
+ int *_walkOffDown;
+ Common::Point *_walkOffUR;
+ Common::Point *_walkOffDR;
+ Common::Point *_walkOffUL;
+ Common::Point *_walkOffDL;
byte _rawTempL;
int _rawXTemp;
byte _rawYTempL;
@@ -125,6 +120,8 @@ public:
virtual void load();
+ void loadTexPalette();
+
void loadSprites(const Common::String &name);
void freeSprites();
@@ -137,6 +134,10 @@ public:
void calcPlayer();
+ bool scrollUp(int forcedAmount = -1);
+ bool scrollDown(int forcedAmount = -1);
+ bool scrollLeft(int forcedAmount = -1);
+ bool scrollRight(int forcedAmount = -1);
void checkScroll();
void checkMove();
diff --git a/engines/access/resources.cpp b/engines/access/resources.cpp
index 4157cdfc0d..8699a4a82f 100644
--- a/engines/access/resources.cpp
+++ b/engines/access/resources.cpp
@@ -46,35 +46,17 @@ const byte INITIAL_PALETTE[18 * 3] = {
0x00, 0x00, 0x00
};
-const int SIDEOFFR[] = { 5, 5, 5, 5, 5, 5, 5, 5, 0 };
-const int SIDEOFFL[] = { 5, 5, 5, 5, 5, 5, 5, 5, 0 };
-const int SIDEOFFU[] = { 2, 2, 2, 2, 2, 2, 2, 2, 0 };
-const int SIDEOFFD[] = { 2, 2, 2, 2, 2, 2, 2, 2, 0 };
-const int DIAGOFFURX[] = { 4, 5, 2, 2, 3, 4, 2, 2, 0 };
-const int DIAGOFFURY[] = { 2, 3, 2, 2, 2, 3, 1, 1, 0 };
-const int DIAGOFFDRX[] = { 4, 5, 4, 3, 5, 4, 5, 1, 0 };
-const int DIAGOFFDRY[] = { 3, 2, 1, 2, 2, 1, 2, 1, 0 };
-const int DIAGOFFULX[] = { 4, 5, 4, 3, 3, 2, 2, 2, 0 };
-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 int RMOUSE[10][2] = {
- { 0, 35 }, { 0, 0 }, { 36, 70 }, { 71, 106 }, { 107, 141 },
- { 142, 177 }, { 178, 212 }, { 213, 248 }, { 249, 283 }, { 284, 318 }
-};
-
-const char *const LOOK_MESSAGE = "LOOKING THERE REVEALS NOTHING OF INTEREST.";
-const char *const GET_MESSAGE = "YOU CAN'T TAKE THAT.";
-const char *const OPEN_MESSAGE = "THAT DOESN'T OPEN.";
-const char *const MOVE_MESSAGE = "THAT WON'T MOVE.";
-const char *const USE_MESSAGE = "THAT DOESN'T SEEM TO WORK.";
-const char *const GO_MESSAGE = "YOU CAN'T CLIMB THAT.";
-const char *const HELP_MESSAGE = "THIS OBJECT REQUIRES NO HINTS";
-const char *const TALK_MESSAGE = "THERE SEEMS TO BE NO RESPONSE.";
const char *const GENERAL_MESSAGES[] = {
- LOOK_MESSAGE, OPEN_MESSAGE, MOVE_MESSAGE, GET_MESSAGE, USE_MESSAGE,
- GO_MESSAGE, TALK_MESSAGE, HELP_MESSAGE, HELP_MESSAGE, USE_MESSAGE
+ "LOOKING THERE REVEALS NOTHING OF INTEREST.", // LOOK_MESSAGE
+ "THAT DOESN'T OPEN.", // OPEN_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
};
const int INVCOORDS[][4] = {
diff --git a/engines/access/resources.h b/engines/access/resources.h
index 8d59b1b1f1..07b8e5ada9 100644
--- a/engines/access/resources.h
+++ b/engines/access/resources.h
@@ -29,21 +29,6 @@ namespace Access {
extern const byte INITIAL_PALETTE[18 * 3];
-extern const int SIDEOFFR[];
-extern const int SIDEOFFL[];
-extern const int SIDEOFFU[];
-extern const int SIDEOFFD[];
-extern const int DIAGOFFURX[];
-extern const int DIAGOFFURY[];
-extern const int DIAGOFFDRX[];
-extern const int DIAGOFFDRY[];
-extern const int DIAGOFFULX[];
-extern const int DIAGOFFULY[];
-extern const int DIAGOFFDLX[];
-extern const int DIAGOFFDLY[];
-
-extern const int RMOUSE[10][2];
-
extern const char *const GENERAL_MESSAGES[];
extern const int INVCOORDS[][4];
diff --git a/engines/access/room.cpp b/engines/access/room.cpp
index 607259ec6f..c91b37c65d 100644
--- a/engines/access/room.cpp
+++ b/engines/access/room.cpp
@@ -38,6 +38,23 @@ Room::Room(AccessEngine *vm) : Manager(vm) {
_selectCommand = 0;
_conFlag = false;
_selectCommand = -1;
+
+ switch (vm->getGameID()) {
+ case GType_Amazon:
+ for (int i = 0; i < 10; i++) {
+ _rMouse[i][0] = Amazon::RMOUSE[i][0];
+ _rMouse[i][1] = Amazon::RMOUSE[i][1];
+ }
+ break;
+ case GType_MartianMemorandum:
+ for (int i = 0; i < 10; i++) {
+ _rMouse[i][0] = Martian::RMOUSE[i][0];
+ _rMouse[i][1] = Martian::RMOUSE[i][1];
+ }
+ break;
+ default:
+ error("Game not supported");
+ }
}
Room::~Room() {
@@ -55,6 +72,91 @@ void Room::freeTileData() {
_tile = nullptr;
}
+void Room::clearCamera() {
+ _vm->_player->_scrollFlag = true;
+ _vm->_events->hideCursor();
+
+ _vm->_screen->_orgX1 = 48;
+ _vm->_screen->_orgY1 = 24;
+ _vm->_screen->_orgX2 = 274;
+ _vm->_screen->_orgY2 = 152;
+ _vm->_screen->_lColor = 0;
+ _vm->_screen->drawRect();
+
+ _vm->_events->showCursor();
+
+ _vm->_events->_vbCount = 4;
+ while (!_vm->shouldQuit() && _vm->_events->_vbCount > 0)
+ _vm->_events->pollEventsAndWait();
+}
+
+void Room::takePicture() {
+ _vm->_events->pollEvents();
+ if (!_vm->_events->_leftButton)
+ return;
+
+ Common::Array<Common::Rect> pictureCoords;
+ for (int i = 0; Martian::PICTURERANGE[i][0] != -1; i += 2) {
+ pictureCoords.push_back(Common::Rect(Martian::PICTURERANGE[i][0], Martian::PICTURERANGE[i + 1][0],
+ Martian::PICTURERANGE[i][1], Martian::PICTURERANGE[i + 1][1]));
+ }
+
+ int result = _vm->_events->checkMouseBox1(pictureCoords);
+
+ if (result == 4) {
+ _vm->_events->debounceLeft();
+ if (_vm->_inventory->_inv[44]._value != ITEM_IN_INVENTORY) {
+ Common::String msg = "YOU HAVE NO MORE FILM.";
+ _vm->_scripts->doCmdPrint_v1(msg);
+ return;
+ }
+
+ // TODO: simplify the second part of the test when tested
+ if ((_vm->_scrollCol < 35) || ((_vm->_scrollRow >= 10) && (_vm->_scrollRow >= 20))){
+ Common::String msg = "THAT ISN'T INTERESTING ENOUGH TO WASTE FILM ON.";
+ _vm->_scripts->doCmdPrint_v1(msg);
+ return;
+ }
+
+ if (_vm->_inventory->_inv[26]._value != ITEM_USED) {
+ Common::String msg = "ALTHOUGH IT WOULD MAKE A NICE PICTURE, YOU MAY FIND SOMETHING MORE INTERESTING TO USE YOUR FILM ON.";
+ _vm->_scripts->doCmdPrint_v1(msg);
+ return;
+ }
+
+ Common::String msg = "THAT PHOTO MAY COME IN HANDY SOME DAY.";
+ _vm->_scripts->doCmdPrint_v1(msg);
+ _vm->_inventory->_inv[8]._value = ITEM_IN_INVENTORY;
+ _vm->_pictureTaken++;
+ if (_vm->_pictureTaken == 16)
+ _vm->_inventory->_inv[44]._value = ITEM_USED;
+
+ _vm->_events->debounceLeft();
+ _vm->_sound->playSound(0);
+ clearCamera();
+ return;
+ } else if (result == 5) {
+ if (_vm->_flags[26] != 2) {
+ _vm->_video->closeVideo();
+ _vm->_video->_videoEnd = true;
+ }
+ _vm->_player->_roomNumber = 7;
+ _vm->_room->_function = FN_CLEAR1;
+ return;
+ } else if (result >= 0)
+ _vm->_player->_move = (Direction)(result + 1);
+
+ _vm->_player->_scrollFlag = false;
+ if (_vm->_player->_move == UP)
+ _vm->_player->scrollDown(2);
+ else if (_vm->_player->_move == DOWN)
+ _vm->_player->scrollUp(2);
+ else if (_vm->_player->_move == LEFT)
+ _vm->_player->scrollRight(2);
+ else if (_vm->_player->_move == RIGHT)
+ _vm->_player->scrollLeft(2);
+}
+
void Room::doRoom() {
bool reloadFlag = false;
@@ -84,9 +186,13 @@ void Room::doRoom() {
_vm->_events->pollEventsAndWait();
_vm->_canSaveLoad = false;
- _vm->_player->walk();
- _vm->_midi->midiRepeat();
- _vm->_player->checkScroll();
+ if ((_vm->getGameID() == GType_MartianMemorandum) && (_vm->_player->_roomNumber == 47)) {
+ takePicture();
+ } else {
+ _vm->_player->walk();
+ _vm->_midi->midiRepeat();
+ _vm->_player->checkScroll();
+ }
doCommands();
if (_vm->shouldQuitOrRestart())
@@ -136,7 +242,8 @@ void Room::doRoom() {
} else {
_vm->plotList();
- if (_vm->_events->_mousePos.y < 177)
+ if (((_vm->getGameID() == GType_MartianMemorandum) && (_vm->_events->_mousePos.y < 184)) ||
+ ((_vm->getGameID() == GType_Amazon) && (_vm->_events->_mousePos.y < 177)))
_vm->_events->setCursor(_vm->_events->_normalMouse);
else
_vm->_events->setCursor(CURSOR_ARROW);
@@ -173,8 +280,8 @@ void Room::loadRoomData(const byte *roomData) {
_vm->_establishFlag = false;
if (roomInfo._estIndex != -1) {
_vm->_establishFlag = true;
- if (_vm->_establishTable[roomInfo._estIndex] != 1) {
- _vm->_establishTable[roomInfo._estIndex] = 1;
+ if (!_vm->_establishTable[roomInfo._estIndex]) {
+ _vm->_establishTable[roomInfo._estIndex] = true;
_vm->establish(0, roomInfo._estIndex);
}
}
@@ -455,8 +562,8 @@ void Room::doCommands() {
if (_vm->_events->_mouseRow >= 22) {
// Mouse in user interface area
for (commandId = 0; commandId < 10; ++commandId) {
- if (_vm->_events->_mousePos.x >= RMOUSE[commandId][0] &&
- _vm->_events->_mousePos.x < RMOUSE[commandId][1])
+ if (_vm->_events->_mousePos.x >= _rMouse[commandId][0] &&
+ _vm->_events->_mousePos.x < _rMouse[commandId][1])
break;
}
if (commandId < 10)
@@ -489,9 +596,6 @@ void Room::cycleCommand(int incr) {
}
void Room::handleCommand(int commandId) {
- if (commandId == 1)
- --commandId;
-
if (commandId == 9) {
_vm->_events->debounceLeft();
_vm->_canSaveLoad = true;
@@ -510,41 +614,90 @@ void Room::executeCommand(int commandId) {
EventsManager &events = *_vm->_events;
_selectCommand = commandId;
- switch (commandId) {
- case 0:
- events.forceSetCursor(CURSOR_LOOK);
- break;
- case 2:
- events.forceSetCursor(CURSOR_USE);
- break;
- case 3:
- events.forceSetCursor(CURSOR_TAKE);
- break;
- case 4:
- events.setCursor(CURSOR_ARROW);
- if (_vm->_inventory->newDisplayInv() == 2) {
- commandOff();
+ if (_vm->getGameID() == GType_MartianMemorandum) {
+ switch (commandId) {
+ case 4:
+ events.setCursor(CURSOR_ARROW);
+ if (_vm->_inventory->displayInv() == 2) {
+ commandOff();
+ return;
+ }
+ if (_vm->_useItem == 39) {
+ if (_vm->_player->_roomNumber == 23)
+ _vm->_currentMan = 1;
+ commandOff();
+ return;
+ } else if (_vm->_useItem == 6) {
+ _vm->_flags[3] = 2;
+ _vm->_scripts->converse1(24);
+
+ _conFlag = true;
+ while (_conFlag && !_vm->shouldQuitOrRestart()) {
+ _conFlag = false;
+ _vm->_scripts->executeScript();
+ }
+
+ _vm->_boxSelect = true;
+ return;
+ }
+ break;
+ case 7:
+ walkCursor();
return;
+ case 8: {
+ events.forceSetCursor(CURSOR_CROSSHAIRS);
+ _vm->_scripts->_sequence = 10000;
+ _vm->_scripts->searchForSequence();
+
+ _conFlag = true;
+ while (_conFlag && !_vm->shouldQuitOrRestart()) {
+ _conFlag = false;
+ _vm->_scripts->executeScript();
+ }
+
+ _vm->_boxSelect = true;
+ return;
+ }
+ default:
+ // No set cursor in MM. Forcing to CROSSHAIRS
+ events.setCursor(CURSOR_CROSSHAIRS);
+ break;
+ }
+ } else {
+ switch (commandId) {
+ case 0:
+ case 1:
+ events.forceSetCursor(CURSOR_LOOK);
+ break;
+ case 2:
+ events.forceSetCursor(CURSOR_USE);
+ break;
+ case 3:
+ events.forceSetCursor(CURSOR_TAKE);
+ break;
+ case 4:
+ events.setCursor(CURSOR_ARROW);
+ if (_vm->_inventory->newDisplayInv() == 2) {
+ commandOff();
+ return;
+ }
+ break;
+ case 5:
+ events.forceSetCursor(CURSOR_CLIMB);
+ break;
+ case 6:
+ events.forceSetCursor(CURSOR_TALK);
+ break;
+ case 7:
+ walkCursor();
+ return;
+ case 8:
+ events.forceSetCursor(CURSOR_HELP);
+ break;
+ default:
+ break;
}
- break;
- case 5:
- events.forceSetCursor(CURSOR_CLIMB);
- break;
- case 6:
- events.forceSetCursor(CURSOR_TALK);
- break;
- case 7:
- walkCursor();
- return;
- case 8:
- events.forceSetCursor(CURSOR_HELP);
- break;
- default:
- break;
}
-
- // Draw the default toolbar menu at the bottom of the screen
- roomMenu();
_vm->_screen->saveScreen();
_vm->_screen->setDisplayScan();
@@ -555,7 +708,7 @@ void Room::executeCommand(int commandId) {
// Draw the button as selected
_vm->_screen->plotImage(spr, _selectCommand + 2,
- Common::Point(RMOUSE[_selectCommand][0], 176));
+ Common::Point(_rMouse[_selectCommand][0], (_vm->getGameID() == GType_MartianMemorandum) ? 184 : 176));
_vm->_screen->restoreScreen();
_vm->_boxSelect = true;
diff --git a/engines/access/room.h b/engines/access/room.h
index eec273e3f4..12e7375428 100644
--- a/engines/access/room.h
+++ b/engines/access/room.h
@@ -72,6 +72,8 @@ private:
int calcLR(int yp);
int calcUD(int xp);
+ void takePicture();
+
/**
* Cycles forwards or backwards through the list of commands
*/
@@ -103,6 +105,8 @@ protected:
*/
void executeCommand(int commandId);
+ void clearCamera();
+
virtual void reloadRoom() = 0;
virtual void reloadRoom1() = 0;
@@ -126,6 +130,7 @@ public:
byte *_tile;
int _selectCommand;
bool _conFlag;
+ int _rMouse[10][2];
public:
Room(AccessEngine *vm);
diff --git a/engines/access/screen.cpp b/engines/access/screen.cpp
index 970a8f3079..41f6194238 100644
--- a/engines/access/screen.cpp
+++ b/engines/access/screen.cpp
@@ -113,6 +113,20 @@ void Screen::setInitialPalettte() {
g_system->getPaletteManager()->setPalette(INITIAL_PALETTE, 0, 18);
}
+void Screen::setManPalette() {
+ for (int i = 0; i < 0x42; i++) {
+ _rawPalette[672 + i] = VGA_COLOR_TRANS(_manPal[i]);
+ }
+}
+
+void Screen::setIconPalette() {
+ if (_vm->getGameID() == GType_MartianMemorandum) {
+ for (int i = 0; i < 0x1B; i++) {
+ _rawPalette[741 + i] = VGA_COLOR_TRANS(Martian::ICON_PALETTE[i]);
+ }
+ }
+}
+
void Screen::loadPalette(int fileNum, int subfile) {
Resource *res = _vm->_files->loadFile(fileNum, subfile);
byte *palette = res->data();
@@ -189,7 +203,7 @@ void Screen::forceFadeIn() {
for (int idx = 0; idx < PALETTE_SIZE; ++idx, ++srcP, ++destP) {
if (*destP != *srcP) {
repeatFlag = true;
- *destP = MAX((int)*destP + FADE_AMOUNT, (int)*srcP);
+ *destP = MIN((int)*destP + FADE_AMOUNT, (int)*srcP);
}
}
@@ -267,6 +281,11 @@ void Screen::drawRect() {
ASurface::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);
@@ -322,6 +341,10 @@ 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);
diff --git a/engines/access/screen.h b/engines/access/screen.h
index d45a533f9a..52485e5c7c 100644
--- a/engines/access/screen.h
+++ b/engines/access/screen.h
@@ -92,6 +92,8 @@ public:
virtual void drawRect();
+ virtual void drawBox();
+
virtual void transBlitFrom(ASurface *src, const Common::Point &destPos);
virtual void transBlitFrom(ASurface *src, const Common::Rect &bounds);
@@ -137,7 +139,12 @@ public:
/**
* Set icon palette
*/
- void setIconPalette() {}
+ void setIconPalette();
+
+ /**
+ * Set Tex palette (Martian Memorandum)
+ */
+ void setManPalette();
void loadPalette(int fileNum, int subfile);
@@ -151,6 +158,8 @@ public:
void getPalette(byte *pal);
+ void flashPalette(int count);
+
/**
* Copy a buffer to the screen
*/
diff --git a/engines/access/scripts.cpp b/engines/access/scripts.cpp
index 1bd24894d7..41dd5cc0d0 100644
--- a/engines/access/scripts.cpp
+++ b/engines/access/scripts.cpp
@@ -39,12 +39,101 @@ Scripts::Scripts(AccessEngine *vm) : Manager(vm) {
_choiceStart = 0;
_charsOrg = Common::Point(0, 0);
_texsOrg = Common::Point(0, 0);
+ setOpcodes();
}
Scripts::~Scripts() {
freeScriptData();
}
+void Scripts::setOpcodes() {
+ COMMAND_LIST[0] = &Scripts::cmdObject;
+ COMMAND_LIST[1] = &Scripts::cmdEndObject;
+ COMMAND_LIST[2] = &Scripts::cmdJumpLook;
+ COMMAND_LIST[3] = &Scripts::cmdJumpHelp;
+ COMMAND_LIST[4] = &Scripts::cmdJumpGet;
+ COMMAND_LIST[5] = &Scripts::cmdJumpMove;
+ COMMAND_LIST[6] = &Scripts::cmdJumpUse;
+ COMMAND_LIST[7] = &Scripts::cmdJumpTalk;
+ COMMAND_LIST[8] = &Scripts::cmdNull;
+ COMMAND_LIST[9] = &Scripts::cmdPrint_v1;
+ COMMAND_LIST[10] = &Scripts::cmdRetPos;
+ COMMAND_LIST[11] = &Scripts::cmdAnim;
+ COMMAND_LIST[12] = &Scripts::cmdSetFlag;
+ COMMAND_LIST[13] = &Scripts::cmdCheckFlag;
+ COMMAND_LIST[14] = &Scripts::cmdGoto;
+ COMMAND_LIST[15] = &Scripts::cmdAddScore;
+ COMMAND_LIST[16] = &Scripts::cmdSetInventory;
+ COMMAND_LIST[17] = &Scripts::cmdCheckInventory;
+ COMMAND_LIST[18] = &Scripts::cmdSetTex;
+ COMMAND_LIST[19] = &Scripts::cmdNewRoom;
+ COMMAND_LIST[20] = &Scripts::cmdConverse;
+ COMMAND_LIST[21] = &Scripts::cmdCheckFrame;
+ COMMAND_LIST[22] = &Scripts::cmdCheckAnim;
+ COMMAND_LIST[23] = &Scripts::cmdSnd;
+ COMMAND_LIST[24] = &Scripts::cmdRetNeg;
+ COMMAND_LIST[25] = &Scripts::cmdRetPos;
+ COMMAND_LIST[26] = &Scripts::cmdCheckLoc;
+ COMMAND_LIST[27] = &Scripts::cmdSetAnim;
+ COMMAND_LIST[28] = &Scripts::cmdDispInv_v1;
+ COMMAND_LIST[29] = &Scripts::cmdSetAbout;
+ COMMAND_LIST[30] = &Scripts::cmdSetTimer;
+ COMMAND_LIST[31] = &Scripts::cmdCheckTimer;
+ COMMAND_LIST[32] = &Scripts::cmdSetTravel;
+ COMMAND_LIST[33] = &Scripts::cmdJumpGoto;
+ COMMAND_LIST[34] = &Scripts::cmdSetVideo;
+ COMMAND_LIST[35] = &Scripts::cmdPlayVideo;
+ COMMAND_LIST[36] = &Scripts::cmdPlotImage;
+ COMMAND_LIST[37] = &Scripts::cmdSetDisplay;
+ COMMAND_LIST[38] = &Scripts::cmdSetBuffer;
+ COMMAND_LIST[39] = &Scripts::cmdSetScroll;
+ COMMAND_LIST[40] = &Scripts::cmdSaveRect;
+ COMMAND_LIST[41] = &Scripts::cmdVideoEnded;
+ COMMAND_LIST[42] = &Scripts::cmdSetBufVid;
+ COMMAND_LIST[43] = &Scripts::cmdPlayBufVid;
+ COMMAND_LIST[44] = &Scripts::cmdRemoveLast;
+ COMMAND_LIST[45] = &Scripts::cmdDoTravel;
+ COMMAND_LIST[46] = &Scripts::cmdCheckAbout;
+ COMMAND_LIST[47] = &Scripts::cmdSpecial;
+ COMMAND_LIST[48] = &Scripts::cmdSetCycle;
+ COMMAND_LIST[49] = &Scripts::cmdCycle;
+ COMMAND_LIST[50] = &Scripts::cmdCharSpeak;
+ COMMAND_LIST[51] = &Scripts::cmdTexSpeak;
+ COMMAND_LIST[52] = &Scripts::cmdTexChoice;
+ COMMAND_LIST[53] = &Scripts::cmdWait;
+ COMMAND_LIST[54] = &Scripts::cmdSetConPos;
+ COMMAND_LIST[55] = &Scripts::cmdCheckVFrame;
+ COMMAND_LIST[56] = &Scripts::cmdJumpChoice;
+ COMMAND_LIST[57] = &Scripts::cmdReturnChoice;
+ COMMAND_LIST[58] = &Scripts::cmdClearBlock;
+ COMMAND_LIST[59] = &Scripts::cmdLoadSound;
+ COMMAND_LIST[60] = &Scripts::cmdFreeSound;
+ COMMAND_LIST[61] = &Scripts::cmdSetVideoSound;
+ COMMAND_LIST[62] = &Scripts::cmdPlayVideoSound;
+ COMMAND_LIST[63] = &Scripts::cmdPrintWatch;
+ COMMAND_LIST[64] = &Scripts::cmdDispAbout;
+ COMMAND_LIST[65] = &Scripts::cmdPushLocation;
+ COMMAND_LIST[66] = &Scripts::cmdCheckTravel;
+ COMMAND_LIST[67] = &Scripts::cmdBlock;
+ COMMAND_LIST[68] = &Scripts::cmdPlayerOff;
+ COMMAND_LIST[69] = &Scripts::cmdPlayerOn;
+ COMMAND_LIST[70] = &Scripts::cmdDead;
+ COMMAND_LIST[71] = &Scripts::cmdFadeOut;
+ COMMAND_LIST[72] = &Scripts::cmdEndVideo;
+ COMMAND_LIST[73] = &Scripts::cmdHelp_v1;
+}
+
+void Scripts::setOpcodes_v2() {
+ COMMAND_LIST[9] = &Scripts::cmdPrint_v2;
+ COMMAND_LIST[15] = &Scripts::cmdSetInventory;
+ COMMAND_LIST[28] = &Scripts::cmdDispInv_v2;
+ COMMAND_LIST[29] = &Scripts::cmdSetTimer;
+ COMMAND_LIST[32] = &Scripts::cmdJumpGoto;
+ COMMAND_LIST[40] = &Scripts::cmdVideoEnded;
+ COMMAND_LIST[45] = COMMAND_LIST[46] = &Scripts::cmdSpecial;
+ COMMAND_LIST[63] = COMMAND_LIST[64] = COMMAND_LIST[66] = COMMAND_LIST[67] = &Scripts::cmdPushLocation;
+}
+
void Scripts::setScript(Resource *res, bool restartFlag) {
_resource = res;
_data = res->_stream;
@@ -86,6 +175,50 @@ void Scripts::charLoop() {
_endFlag = endFlag;
}
+void Scripts::clearWatch() {
+ _vm->_events->hideCursor();
+ _vm->_screen->_orgX1 = 128;
+ _vm->_screen->_orgY1 = 57;
+ _vm->_screen->_orgX2 = 228;
+ _vm->_screen->_orgY2 = 106;
+ _vm->_screen->_lColor = 0;
+ _vm->_screen->drawRect();
+
+ _vm->_events->showCursor();
+}
+
+void Scripts::printWatch() {
+ _vm->_fonts._charSet._lo = 8;
+ _vm->_fonts._charSet._hi = 2;
+ _vm->_fonts._charFor._lo = 2;
+ _vm->_fonts._charFor._hi = 255;
+
+ _vm->_screen->_maxChars = 19;
+ _vm->_screen->_printOrg = Common::Point(128, 58);
+ _vm->_screen->_printStart = Common::Point(128, 58);
+ clearWatch();
+
+ Common::String msg = readString();
+ Common::String line = "";
+ int width = 0;
+ bool lastLine;
+ do {
+ lastLine = _vm->_fonts._font2.getLine(msg, _vm->_screen->_maxChars * 6, line, width);
+ // Draw the text
+ _vm->_bubbleBox->printString(line);
+
+ _vm->_screen->_printOrg.y += 6;
+ _vm->_screen->_printOrg.x = _vm->_screen->_printStart.x;
+
+ if (_vm->_screen->_printOrg.y == 106) {
+ _vm->_events->waitKeyMouse();
+ clearWatch();
+ _vm->_screen->_printOrg.y = _vm->_screen->_printStart.y;
+ }
+ } while (!lastLine);
+ _vm->_events->waitKeyMouse();
+}
+
void Scripts::findNull() {
// No implementation required in ScummVM, the strings in the script files are already skipped by the use of readByte()
}
@@ -109,37 +242,7 @@ int Scripts::executeScript() {
return _returnCode;
}
-typedef void(Scripts::*ScriptMethodPtr)();
-
void Scripts::executeCommand(int commandIndex) {
- static const ScriptMethodPtr COMMAND_LIST[] = {
- &Scripts::cmdObject, &Scripts::cmdEndObject, &Scripts::cmdJumpLook,
- &Scripts::cmdJumpHelp, &Scripts::cmdJumpGet, &Scripts::cmdJumpMove,
- &Scripts::cmdJumpUse, &Scripts::cmdJumpTalk, &Scripts::cmdNull,
- &Scripts::cmdPrint, &Scripts::cmdRetPos, &Scripts::cmdAnim,
- &Scripts::cmdSetFlag, &Scripts::cmdCheckFlag, &Scripts::cmdGoto,
- &Scripts::cmdAddScore, &Scripts::cmdSetInventory, &Scripts::cmdCheckInventory,
- &Scripts::cmdSetTex, &Scripts::cmdNewRoom, &Scripts::cmdConverse,
- &Scripts::cmdCheckFrame, &Scripts::cmdCheckAnim, &Scripts::cmdSnd,
- &Scripts::cmdRetNeg, &Scripts::cmdRetPos, &Scripts::cmdCheckLoc,
- &Scripts::cmdSetAnim, &Scripts::cmdDispInv, &Scripts::cmdSetAbout,
- &Scripts::cmdSetTimer, &Scripts::cmdCheckTimer, &Scripts::cmdSetTravel,
- &Scripts::cmdJumpGoto, &Scripts::cmdSetVideo, &Scripts::cmdPlayVideo,
- &Scripts::cmdPlotImage, &Scripts::cmdSetDisplay, &Scripts::cmdSetBuffer,
- &Scripts::cmdSetScroll, &Scripts::cmdSaveRect, &Scripts::cmdVideoEnded,
- &Scripts::cmdSetBufVid, &Scripts::cmdPlayBufVid, &Scripts::cmdRemoveLast,
- &Scripts::cmdDoTravel, &Scripts::cmdCheckAbout, &Scripts::cmdSpecial,
- &Scripts::cmdSetCycle, &Scripts::cmdCycle, &Scripts::cmdCharSpeak,
- &Scripts::cmdTexSpeak, &Scripts::cmdTexChoice, &Scripts::cmdWait,
- &Scripts::cmdSetConPos, &Scripts::cmdCheckVFrame, &Scripts::cmdJumpChoice,
- &Scripts::cmdReturnChoice, &Scripts::cmdClearBlock, &Scripts::cmdLoadSound,
- &Scripts::cmdFreeSound, &Scripts::cmdSetVideoSound, &Scripts::cmdPlayVideoSound,
- &Scripts::cmdPrintWatch, &Scripts::cmdDispAbout, &Scripts::cmdPushLocation,
- &Scripts::cmdCheckTravel, &Scripts::cmdBlock, &Scripts::cmdPlayerOff,
- &Scripts::cmdPlayerOn, &Scripts::cmdDead, &Scripts::cmdFadeOut,
- &Scripts::cmdEndVideo
- };
-
(this->*COMMAND_LIST[commandIndex])();
}
@@ -198,18 +301,36 @@ void Scripts::cmdNull() {
#define PRINT_TIMER 25
-void Scripts::cmdPrint() {
+void Scripts::cmdPrint_v2() {
// Get a text line for display
Common::String msg = readString();
printString(msg);
}
-void Scripts::printString(const Common::String &msg) {
+void Scripts::doCmdPrint_v1(Common::String msg) {
_vm->_screen->_printOrg = Common::Point(20, 42);
- _vm->_screen->_printStart = Common::Point(20, 42);
- _vm->_timers[PRINT_TIMER]._timer = 50;
- _vm->_timers[PRINT_TIMER]._initTm = 50;
- ++_vm->_timers[PRINT_TIMER]._flag;
+ _vm->_screen->_printStart = Common::Point(20, 32);
+ _vm->_bubbleBox->placeBubble(msg);
+ _vm->_events->waitKeyMouse();
+ _vm->_events->hideCursor();
+ _vm->_screen->restoreBlock();
+ _vm->_events->showCursor();
+ findNull();
+}
+
+void Scripts::cmdPrint_v1() {
+ Common::String msg = readString();
+ doCmdPrint_v1(msg);
+}
+
+void Scripts::printString(const Common::String &msg) {
+ if (_vm->getGameID() != GType_MartianMemorandum) {
+ _vm->_screen->_printOrg = Common::Point(20, 42);
+ _vm->_screen->_printStart = Common::Point(20, 42);
+ _vm->_timers[PRINT_TIMER]._timer = 50;
+ _vm->_timers[PRINT_TIMER]._initTm = 50;
+ ++_vm->_timers[PRINT_TIMER]._flag;
+ }
// Display the text in a bubble, and wait for a keypress or mouse click
_vm->_bubbleBox->placeBubble(msg);
@@ -268,11 +389,6 @@ void Scripts::cmdGoto() {
}
void Scripts::cmdAddScore() {
- if (!_vm->isDemo()) {
- cmdSetInventory();
- return;
- }
-
_data->skip(1);
}
@@ -338,8 +454,8 @@ void Scripts::cmdNewRoom() {
cmdRetPos();
}
-void Scripts::cmdConverse() {
- _vm->_conversation = _data->readUint16LE();
+void Scripts::converse1(int val) {
+ _vm->_conversation = val;
_vm->_room->clearRoom();
_vm->freeChar();
_vm->_char->loadChar(_vm->_conversation);
@@ -355,6 +471,11 @@ void Scripts::cmdConverse() {
}
}
+void Scripts::cmdConverse() {
+ int val = _data->readUint16LE();
+ converse1(val);
+}
+
void Scripts::cmdCheckFrame() {
int id = _data->readUint16LE();
Animation *anim = _vm->_animation->findAnimation(id);
@@ -409,17 +530,19 @@ void Scripts::cmdSetAnim() {
_vm->_animation->setAnimTimer(anim);
}
-void Scripts::cmdDispInv() {
+void Scripts::cmdDispInv_v1() {
+ _vm->_inventory->displayInv();
+}
+
+void Scripts::cmdDispInv_v2() {
_vm->_inventory->newDisplayInv();
}
void Scripts::cmdSetAbout() {
- if (!_vm->isDemo()) {
- cmdSetTimer();
- return;
- }
-
- error("TODO: DEMO - cmdSetAbout");
+ int idx = _data->readByte();
+ int val = _data->readByte();
+ _vm->_ask[idx] = val;
+ _vm->_startAboutBox = _vm->_startAboutItem = 0;
}
void Scripts::cmdSetTimer() {
@@ -461,11 +584,10 @@ void Scripts::cmdCheckTimer() {
}
void Scripts::cmdSetTravel() {
- if (!_vm->isDemo()) {
- cmdJumpGoto();
- return;
- }
- error("TODO: DEMO - cmdSetTravel");
+ int idx = _data->readByte();
+ int dest = _data->readByte();
+ _vm->_travel[idx] = dest;
+ _vm->_startTravelItem = _vm->_startTravelBox = 0;
}
void Scripts::cmdJumpGoto() {
@@ -517,11 +639,11 @@ void Scripts::cmdSetScroll() {
}
void Scripts::cmdSaveRect() {
- if (!_vm->isDemo()) {
- cmdVideoEnded();
- return;
- }
- error("TODO: DEMO - cmdSaveRect");
+ int x = _vm->_screen->_lastBoundsX;
+ int y = _vm->_screen->_lastBoundsY;
+ int w = _vm->_screen->_lastBoundsW;
+ int h = _vm->_screen->_lastBoundsH;
+ _vm->_newRects.push_back(Common::Rect(x, y, x + w, x + h));
}
void Scripts::cmdVideoEnded() {
@@ -553,19 +675,81 @@ void Scripts::cmdRemoveLast() {
}
void Scripts::cmdDoTravel() {
- if (!_vm->isDemo()) {
- cmdSpecial();
+ while (true) {
+ _vm->_travelBox->getList(Martian::TRAVDATA, _vm->_travel);
+ int btnSelected = 0;
+ int boxX = _vm->_travelBox->doBox_v1(_vm->_startTravelItem, _vm->_startTravelBox, btnSelected);
+ _vm->_startTravelItem = _vm->_boxDataStart;
+ _vm->_startTravelBox = _vm->_boxSelectY;
+
+ if (boxX == -1)
+ btnSelected = 2;
+
+ if (btnSelected != 2) {
+ 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.");
+ continue;
+ }
+ if (_vm->_player->_roomNumber != idx) {
+ _vm->_player->_roomNumber = idx;
+ _vm->_room->_function = FN_CLEAR1;
+ if (Martian::_travelPos[idx][0] == -1) {
+ _vm->_player->_roomNumber = idx;
+ _vm->_room->_conFlag = true;
+ _vm->_scripts->converse1(Martian::_travelPos[idx][1]);
+ return;
+ }
+ _vm->_player->_rawPlayer = Common::Point(Martian::_travelPos[idx][0], Martian::_travelPos[idx][1]);
+ cmdRetPos();
+ return;
+ }
+ }
+
+ if (_vm->_player->_roomNumber == -1)
+ continue;
+
return;
}
- error("TODO: DEMO - cmdDoTravel");
}
-void Scripts::cmdCheckAbout() {
- if (!_vm->isDemo()) {
- cmdSpecial();
- return;
+void Scripts::cmdHelp_v1() {
+ int idx = 0;
+ for (int i = 0; i < 40; i++) {
+ byte c = _data->readByte();
+ if (c != 0xFF) {
+ Common::String tmpStr = c + readString();
+ if (Martian::HELP[i]) {
+ _vm->_helpBox->_tempList[idx] = tmpStr;
+ _vm->_helpBox->_tempListIdx[idx] = i;
+ ++idx;
+ }
+ } else
+ break;
}
- error("TODO: DEMO - cmdCheckAbout");
+ _vm->_helpBox->_tempList[idx] = "";
+
+ int btnSelected = 0;
+ int boxX = _vm->_helpBox->doBox_v1(0, 0, btnSelected);
+
+ if (boxX == -1)
+ btnSelected = 2;
+
+ if (btnSelected != 2)
+ _vm->_useItem = _vm->_helpBox->_tempListIdx[boxX];
+ else
+ _vm->_useItem = -1;
+}
+
+void Scripts::cmdCheckAbout() {
+ int idx = _data->readSint16LE();
+ int val = _data->readSint16LE();
+
+ if (_vm->_ask[idx] == val)
+ cmdGoto();
+ else
+ _data->skip(2);
}
void Scripts::cmdSpecial() {
@@ -574,7 +758,7 @@ void Scripts::cmdSpecial() {
int p2 = _data->readUint16LE();
if (_specialFunction == 1) {
- if (_vm->_establishTable[p2] == 1)
+ if (_vm->_establishTable[p2])
return;
_vm->_screen->savePalette();
@@ -616,33 +800,48 @@ void Scripts::cmdCharSpeak() {
void Scripts::cmdTexSpeak() {
_vm->_screen->_printOrg = _texsOrg;
_vm->_screen->_printStart = _texsOrg;
- _vm->_screen->_maxChars = 20;
+ _vm->_screen->_maxChars = (_vm->getGameID() == GType_MartianMemorandum) ? 23 : 20;
byte v;
Common::String tmpStr = "";
while ((v = _data->readByte()) != 0)
tmpStr += (char)v;
- _vm->_bubbleBox->_bubbleDisplStr = Common::String("JASON");
+ if (_vm->getGameID() == GType_MartianMemorandum)
+ _vm->_bubbleBox->_bubbleDisplStr = Common::String("TEX");
+ else
+ _vm->_bubbleBox->_bubbleDisplStr = Common::String("JASON");
+
_vm->_bubbleBox->placeBubble1(tmpStr);
findNull();
}
#define BTN_COUNT 6
void Scripts::cmdTexChoice() {
- static const int BTN_RANGES[BTN_COUNT][2] = {
- { 0, 76 }, { 77, 154 }, { 155, 232 }, { 233, 276 }, { 0, 0 },
- { 277, 319 }
+ // MM is defining 2 times the last range in the original.
+ static const int BTN_RANGES_v1[BTN_COUNT][2] = {
+ { 0, 60 }, { 64, 124 }, { 129, 192 }, { 194, 227 }, { 233, 292 }, { 297, 319 }
+ };
+
+ static const int BTN_RANGES_v2[BTN_COUNT][2] = {
+ { 0, 76 }, { 77, 154 }, { 155, 232 }, { 233, 276 }, { 0, 0 }, { 277, 319 }
};
+
_vm->_oldRects.clear();
_choiceStart = _data->pos() - 1;
_vm->_fonts._charSet._lo = 1;
_vm->_fonts._charSet._hi = 8;
- _vm->_fonts._charFor._lo = 55;
_vm->_fonts._charFor._hi = 255;
+
+ if (_vm->getGameID() == GType_MartianMemorandum) {
+ _vm->_fonts._charFor._lo = 247;
+ _vm->_screen->_maxChars = 23;
+ } else {
+ _vm->_fonts._charFor._lo = 55;
+ _vm->_screen->_maxChars = 20;
+ }
- _vm->_screen->_maxChars = 20;
_vm->_screen->_printOrg = _texsOrg;
_vm->_screen->_printStart = _texsOrg;
@@ -659,7 +858,7 @@ void Scripts::cmdTexChoice() {
Common::Array<Common::Rect> responseCoords;
responseCoords.push_back(_vm->_bubbleBox->_bounds);
- _vm->_screen->_printOrg.y = _vm->_bubbleBox->_bounds.bottom + 11;
+ _vm->_screen->_printOrg.y = _vm->_bubbleBox->_bounds.bottom + ((_vm->getGameID() == GType_MartianMemorandum) ? 20 : 11);
findNull();
@@ -672,7 +871,7 @@ void Scripts::cmdTexChoice() {
_vm->_bubbleBox->calcBubble(tmpStr);
_vm->_bubbleBox->printBubble(tmpStr);
responseCoords.push_back(_vm->_bubbleBox->_bounds);
- _vm->_screen->_printOrg.y = _vm->_bubbleBox->_bounds.bottom + 11;
+ _vm->_screen->_printOrg.y = _vm->_bubbleBox->_bounds.bottom + ((_vm->getGameID() == GType_MartianMemorandum) ? 20 : 11);
}
findNull();
@@ -687,7 +886,7 @@ void Scripts::cmdTexChoice() {
_vm->_bubbleBox->calcBubble(tmpStr);
_vm->_bubbleBox->printBubble(tmpStr);
responseCoords.push_back(_vm->_bubbleBox->_bounds);
- _vm->_screen->_printOrg.y = _vm->_bubbleBox->_bounds.bottom + 11;
+ _vm->_screen->_printOrg.y = _vm->_bubbleBox->_bounds.bottom + ((_vm->getGameID() == GType_MartianMemorandum) ? 20 : 11);
}
findNull();
@@ -702,11 +901,13 @@ void Scripts::cmdTexChoice() {
_vm->_bubbleBox->_bubbleDisplStr = _vm->_bubbleBox->_bubbleTitle;
if (_vm->_events->_leftButton) {
- if (_vm->_events->_mouseRow >= 22) {
+ if (_vm->_events->_mouseRow >= ((_vm->getGameID() == GType_MartianMemorandum) ? 23 : 22)) {
_vm->_events->debounceLeft();
int x = _vm->_events->_mousePos.x;
for (int i = 0; i < BTN_COUNT; i++) {
- if ((x >= BTN_RANGES[i][0]) && (x < BTN_RANGES[i][1])) {
+ if (((_vm->getGameID() == GType_MartianMemorandum) && (x >= BTN_RANGES_v1[i][0]) && (x < BTN_RANGES_v1[i][1]))
+ || ((_vm->getGameID() == GType_Amazon) && (x >= BTN_RANGES_v2[i][0]) && (x < BTN_RANGES_v2[i][1]))) {
+
choice = i;
break;
}
@@ -827,39 +1028,46 @@ void Scripts::cmdPlayVideoSound() {
}
void Scripts::cmdPrintWatch() {
- if (!_vm->isDemo()) {
- cmdPushLocation();
- return;
- }
- error("TODO: DEMO - cmdPrintWatch");
+ printWatch();
+ findNull();
}
void Scripts::cmdDispAbout() {
- if (!_vm->isDemo()) {
- cmdPushLocation();
- return;
- }
- error("TODO: DEMO - cmdDispAbout");
+ _vm->_travelBox->getList(Martian::_askTBL, _vm->_ask);
+ int btnSelected = 0;
+ int boxX = _vm->_aboutBox->doBox_v1(_vm->_startAboutItem, _vm->_startAboutBox, btnSelected);
+ _vm->_startAboutItem = _vm->_boxDataStart;
+ _vm->_startAboutBox = _vm->_boxSelectY;
+
+ if (boxX == -1)
+ btnSelected = 2;
+
+ if (btnSelected == 2)
+ _vm->_useItem = -1;
+ else
+ _vm->_useItem = _vm->_travelBox->_tempListIdx[boxX];
}
void Scripts::cmdPushLocation() {
- error("TODO cmdPushLocation");
+ _choiceStart = _data->pos() - 1;
}
void Scripts::cmdCheckTravel() {
- if (!_vm->isDemo()) {
- cmdPushLocation();
- return;
- }
- error("TODO: DEMO - cmdCheckTravel");
+ int idx = _data->readSint16LE();
+ int val = _data->readUint16LE();
+
+ if (_vm->_travel[idx] == val)
+ cmdGoto();
+ else
+ _data->skip(2);
}
void Scripts::cmdBlock() {
- if (!_vm->isDemo()) {
- cmdPushLocation();
- return;
- }
- error("TODO: DEMO - cmdBlock");
+ error("TODO: cmdBlock");
+ /*int val1 = */_data->readSint16LE();
+ /*int val2 = */_data->readUint16LE();
+ /*int val3 = */_data->readSint16LE();
+ /*int val4 = */_data->readUint16LE();
}
void Scripts::cmdPlayerOff() {
diff --git a/engines/access/scripts.h b/engines/access/scripts.h
index cfadf6d901..07fd6acfb1 100644
--- a/engines/access/scripts.h
+++ b/engines/access/scripts.h
@@ -35,18 +35,25 @@ class Scripts;
#define SCRIPT_START_BYTE 0xE0
#define ROOM_SCRIPT 2000
+typedef void(Scripts::*ScriptMethodPtr)();
+
class Scripts : public Manager {
private:
Resource *_resource;
int _specialFunction;
- void charLoop();
+ void clearWatch();
+ void printWatch();
+
protected:
Common::SeekableReadStream *_data;
+ ScriptMethodPtr COMMAND_LIST[100];
virtual void executeSpecial(int commandIndex, int param1, int param2) = 0;
virtual void executeCommand(int commandIndex);
+ void charLoop();
+
/**
* Read a null terminated string from the script
*/
@@ -61,7 +68,8 @@ protected:
void cmdJumpUse();
void cmdJumpTalk();
void cmdNull();
- void cmdPrint();
+ void cmdPrint_v1();
+ void cmdPrint_v2();
void cmdAnim();
void cmdSetFlag();
void cmdCheckFlag();
@@ -83,7 +91,8 @@ protected:
void cmdRetNeg();
void cmdCheckLoc();
void cmdSetAnim();
- void cmdDispInv();
+ void cmdDispInv_v1();
+ void cmdDispInv_v2();
void cmdSetAbout();
void cmdSetTimer();
void cmdCheckTimer();
@@ -127,7 +136,8 @@ protected:
void cmdDead();
void cmdFadeOut();
void cmdEndVideo();
- void cmdHelp();
+ void cmdHelp_v1();
+ void cmdHelp_v2();
void cmdCycleBack();
void cmdSetHelp();
public:
@@ -138,11 +148,15 @@ public:
int _choice;
int32 _choiceStart;
Common::Point _charsOrg, _texsOrg;
+
public:
Scripts(AccessEngine *vm);
virtual ~Scripts();
+ void setOpcodes();
+ void setOpcodes_v2();
+
void setScript(Resource *data, bool restartFlag = false);
void freeScriptData();
@@ -152,6 +166,7 @@ public:
int executeScript();
void findNull();
+ void doCmdPrint_v1(Common::String msg);
/**
* Print a given message to the screen in a bubble box
@@ -161,6 +176,7 @@ public:
// Script commands that need to be public
void cmdFreeSound();
void cmdRetPos();
+ void converse1(int val);
};
} // End of namespace Access
diff --git a/engines/access/sound.cpp b/engines/access/sound.cpp
index da267bdc4c..51ffb88f37 100644
--- a/engines/access/sound.cpp
+++ b/engines/access/sound.cpp
@@ -21,9 +21,12 @@
*/
#include "common/algorithm.h"
+#include "common/config-manager.h"
#include "audio/mixer.h"
#include "audio/decoders/raw.h"
#include "audio/decoders/wave.h"
+// Miles Audio
+#include "audio/miles.h"
#include "access/access.h"
#include "access/sound.h"
@@ -47,9 +50,6 @@ void SoundManager::clearSounds() {
if (_mixer->isSoundHandleActive(_effectsHandle))
_mixer->stopHandle(_effectsHandle);
- if (_queue.size())
- _queue.remove_at(0);
-
while (_queue.size()) {
delete _queue[0];
_queue.remove_at(0);
@@ -75,26 +75,26 @@ Resource *SoundManager::loadSound(int fileNum, int subfile) {
return _vm->_files->loadFile(fileNum, subfile);
}
-void SoundManager::playSound(int soundIndex) {
- debugC(1, kDebugSound, "playSound(%d)", soundIndex);
+void SoundManager::playSound(int soundIndex, bool loop) {
+ debugC(1, kDebugSound, "playSound(%d, %d)", soundIndex, loop);
int priority = _soundTable[soundIndex]._priority;
- playSound(_soundTable[soundIndex]._res, priority);
+ playSound(_soundTable[soundIndex]._res, priority, loop);
}
-void SoundManager::playSound(Resource *res, int priority) {
+void SoundManager::playSound(Resource *res, int priority, bool loop) {
debugC(1, kDebugSound, "playSound");
byte *resourceData = res->data();
assert(res->_size >= 32);
+ Audio::RewindableAudioStream *audioStream;
+
if (READ_BE_UINT32(resourceData) == MKTAG('R','I','F','F')) {
// CD version uses WAVE-files
Common::SeekableReadStream *waveStream = new Common::MemoryReadStream(resourceData, res->_size, DisposeAfterUse::NO);
- Audio::RewindableAudioStream *audioStream = Audio::makeWAVStream(waveStream, DisposeAfterUse::YES);
- _queue.push_back(audioStream);
-
+ audioStream = Audio::makeWAVStream(waveStream, DisposeAfterUse::YES);
} else if (READ_BE_UINT32(resourceData) == MKTAG('S', 'T', 'E', 'V')) {
// sound files have a fixed header of 32 bytes in total
// header content:
@@ -134,16 +134,20 @@ void SoundManager::playSound(Resource *res, int priority) {
return;
}
- Audio::RewindableAudioStream *audioStream = Audio::makeRawStream(resourceData + 32, sampleSize, sampleRate, 0, DisposeAfterUse::NO);
- _queue.push_back(audioStream);
-
+ audioStream = Audio::makeRawStream(resourceData + 32, sampleSize, sampleRate, 0, DisposeAfterUse::NO);
} else
error("Unknown format");
+ if (loop) {
+ _queue.push_back(new Audio::LoopingAudioStream(audioStream, 0, DisposeAfterUse::NO));
+ } else {
+ _queue.push_back(audioStream);
+ }
+
if (!_mixer->isSoundHandleActive(_effectsHandle))
_mixer->playStream(Audio::Mixer::kSFXSoundType, &_effectsHandle,
_queue[0], -1, _mixer->kMaxChannelVolume, 0,
- DisposeAfterUse::YES);
+ DisposeAfterUse::NO);
}
void SoundManager::checkSoundQueue() {
@@ -152,12 +156,13 @@ void SoundManager::checkSoundQueue() {
if (_queue.empty() || _mixer->isSoundHandleActive(_effectsHandle))
return;
+ delete _queue[0];
_queue.remove_at(0);
- if (_queue.size())
+ if (_queue.size() && _queue[0])
_mixer->playStream(Audio::Mixer::kSFXSoundType, &_effectsHandle,
_queue[0], -1, _mixer->kMaxChannelVolume, 0,
- DisposeAfterUse::YES);
+ DisposeAfterUse::NO);
}
bool SoundManager::isSFXPlaying() {
@@ -178,7 +183,7 @@ void SoundManager::loadSounds(Common::Array<RoomInfo::SoundIdent> &sounds) {
void SoundManager::stopSound() {
debugC(3, kDebugSound, "stopSound");
- _mixer->stopHandle(Audio::SoundHandle());
+ _mixer->stopHandle(_effectsHandle);
}
void SoundManager::freeSounds() {
@@ -194,18 +199,63 @@ MusicManager::MusicManager(AccessEngine *vm) : _vm(vm) {
_music = nullptr;
_tempMusic = nullptr;
_isLooping = false;
+ _driver = nullptr;
+ _byte1F781 = false;
+
+ MidiDriver::DeviceHandle dev = MidiDriver::detectDevice(MDT_MIDI | MDT_ADLIB | MDT_PREFER_MT32);
+ MusicType musicType = MidiDriver::getMusicType(dev);
+
+ // Amazon Guardians of Eden uses MIDPAK inside MIDIDRV.AP
+ // AdLib patches are inside MIDIDRV.AP too, 2nd resource file
+ //
+ // Amazon Guardians of Eden (demo) seems to use another type of driver, possibly written by Access themselves
+ // Martian Memorandum uses this other type of driver as well, which means it makes sense to reverse engineer it.
+ //
+ switch (musicType) {
+ case MT_ADLIB: {
+ if (_vm->getGameID() == GType_Amazon) {
+ Resource *midiDrvResource = _vm->_files->loadFile(92, 1);
+ Common::MemoryReadStream *adLibInstrumentStream = new Common::MemoryReadStream(midiDrvResource->data(), midiDrvResource->_size);
+
+ _driver = Audio::MidiDriver_Miles_AdLib_create("", "", adLibInstrumentStream);
+
+ delete midiDrvResource;
+ delete adLibInstrumentStream;
+ } else {
+ MidiPlayer::createDriver();
+ }
+ break;
+ }
+ case MT_MT32:
+ _driver = Audio::MidiDriver_Miles_MT32_create("");
+ _nativeMT32 = true;
+ break;
+ case MT_GM:
+ if (ConfMan.getBool("native_mt32")) {
+ _driver = Audio::MidiDriver_Miles_MT32_create("");
+ _nativeMT32 = true;
+ }
+ break;
+
+ default:
+ break;
+ }
+#if 0
MidiPlayer::createDriver();
MidiDriver::detectDevice(MDT_MIDI | MDT_ADLIB | MDT_PREFER_GM);
+#endif
- int retValue = _driver->open();
- if (retValue == 0) {
- if (_nativeMT32)
- _driver->sendMT32Reset();
- else
- _driver->sendGMReset();
+ if (_driver) {
+ int retValue = _driver->open();
+ if (retValue == 0) {
+ if (_nativeMT32)
+ _driver->sendMT32Reset();
+ else
+ _driver->sendGMReset();
- _driver->setTimerCallback(this, &timerCallback);
+ _driver->setTimerCallback(this, &timerCallback);
+ }
}
}
@@ -215,16 +265,23 @@ MusicManager::~MusicManager() {
}
void MusicManager::send(uint32 b) {
+ // Pass data directly to driver
+ _driver->send(b);
+#if 0
if ((b & 0xF0) == 0xC0 && !_nativeMT32) {
b = (b & 0xFFFF00FF) | MidiDriver::_mt32ToGm[(b >> 8) & 0xFF] << 8;
}
Audio::MidiPlayer::send(b);
+#endif
}
void MusicManager::midiPlay() {
debugC(1, kDebugSound, "midiPlay");
+ if (!_driver)
+ return;
+
if (_music->_size < 4) {
error("midiPlay() wrong music resource size");
}
@@ -262,6 +319,8 @@ bool MusicManager::checkMidiDone() {
void MusicManager::midiRepeat() {
debugC(1, kDebugSound, "midiRepeat");
+ if (!_driver)
+ return;
if (!_parser)
return;
@@ -274,6 +333,9 @@ void MusicManager::midiRepeat() {
void MusicManager::stopSong() {
debugC(1, kDebugSound, "stopSong");
+ if (!_driver)
+ return;
+
stop();
}
@@ -292,6 +354,9 @@ void MusicManager::loadMusic(FileIdent file) {
void MusicManager::newMusic(int musicId, int mode) {
debugC(1, kDebugSound, "newMusic(%d, %d)", musicId, mode);
+ if (!_driver)
+ return;
+
if (mode == 1) {
stopSong();
freeMusic();
diff --git a/engines/access/sound.h b/engines/access/sound.h
index 90f6656e26..e11a6b9730 100644
--- a/engines/access/sound.h
+++ b/engines/access/sound.h
@@ -49,20 +49,21 @@ private:
AccessEngine *_vm;
Audio::Mixer *_mixer;
Audio::SoundHandle _effectsHandle;
- Common::Array<Audio::RewindableAudioStream *> _queue;
+ Common::Array<Audio::AudioStream *> _queue;
void clearSounds();
- void playSound(Resource *res, int priority);
+ void playSound(Resource *res, int priority, bool loop);
public:
Common::Array<SoundEntry> _soundTable;
+ bool _playingSound;
public:
SoundManager(AccessEngine *vm, Audio::Mixer *mixer);
~SoundManager();
void loadSoundTable(int idx, int fileNum, int subfile, int priority = 1);
- void playSound(int soundIndex);
+ void playSound(int soundIndex, bool loop = false);
void checkSoundQueue();
bool isSFXPlaying();
@@ -84,6 +85,7 @@ private:
public:
Resource *_music;
+ bool _byte1F781;
public:
MusicManager(AccessEngine *vm);
diff --git a/engines/access/video.cpp b/engines/access/video.cpp
index 63d0aa5c89..5fc5f6762c 100644
--- a/engines/access/video.cpp
+++ b/engines/access/video.cpp
@@ -48,17 +48,13 @@ VideoPlayer::~VideoPlayer() {
closeVideo();
}
-
-void VideoPlayer::setVideo(ASurface *vidSurface, const Common::Point &pt, const FileIdent &videoFile, int rate) {
+void VideoPlayer::setVideo(ASurface *vidSurface, const Common::Point &pt, int rate) {
_vidSurface = vidSurface;
vidSurface->_orgX1 = pt.x;
vidSurface->_orgY1 = pt.y;
_vm->_timers[31]._timer = rate;
_vm->_timers[31]._initTm = rate;
- // Open up video stream
- _videoData = _vm->_files->loadFile(videoFile);
-
// Load in header
_header._frameCount = _videoData->_stream->readUint16LE();
_header._width = _videoData->_stream->readUint16LE();
@@ -91,6 +87,20 @@ void VideoPlayer::setVideo(ASurface *vidSurface, const Common::Point &pt, const
_videoEnd = false;
}
+void VideoPlayer::setVideo(ASurface *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) {
+ // Open up video stream
+ _videoData = _vm->_files->loadFile(videoFile);
+
+ setVideo(vidSurface, pt, rate);
+}
+
void VideoPlayer::closeVideo() {
delete _videoData;
_videoData = nullptr;
diff --git a/engines/access/video.h b/engines/access/video.h
index 17825db367..83c8995d3e 100644
--- a/engines/access/video.h
+++ b/engines/access/video.h
@@ -51,6 +51,7 @@ private:
Common::Rect _videoBounds;
void getFrame();
+ void setVideo(ASurface *vidSurface, const Common::Point &pt, int rate);
public:
int _videoFrame;
bool _soundFlag;
@@ -64,6 +65,7 @@ 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);
/**
* Decodes a frame of the video
diff --git a/engines/agi/detection_tables.h b/engines/agi/detection_tables.h
index 0ae822a538..af3d93288e 100644
--- a/engines/agi/detection_tables.h
+++ b/engines/agi/detection_tables.h
@@ -850,6 +850,7 @@ static const AGIGameDescription gameDescriptions[] = {
FANMADE("Tex McPhilip 3 - A Destiny of Sin (Demo v0.25)", "992d12031a486ad84e592ff5d7c9d782"),
FANMADE("The 13th Disciple (v1.00)", "887719ad59afce9a41ec057dbb73ad73"),
FANMADE("The Adventures of a Crazed Hermit", "6e3086cbb794d3299a9c5a9792295511"),
+ FANMADE("The Gourd of the Beans", "246f4d94946afb547482d44a53616d06"),
FANMADE("The Grateful Dead", "c2146631afacf8cb455ce24f3d2d46e7"),
FANMADE("The Legend of Shay-Larah 1 - The Lost Prince", "04e720c8e30c9cf12db22ea14a24a3dd"),
FANMADE("The Legend of Zelda: The Fungus of Time (Demo v1.00)", "dcaf8166ceb62a3d9b9aea7f3b197c09"),
diff --git a/engines/agi/graphics.cpp b/engines/agi/graphics.cpp
index 32d0fdc06a..c5cede71ef 100644
--- a/engines/agi/graphics.cpp
+++ b/engines/agi/graphics.cpp
@@ -72,6 +72,7 @@ static const uint8 egaPalette[16 * 3] = {
* 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,
@@ -90,6 +91,7 @@ static const uint8 atariStAgiPalette[16 * 3] = {
0x7, 0x7, 0x4,
0x7, 0x7, 0x7
};
+#endif
/**
* Second generation Apple IIGS AGI palette.
@@ -109,6 +111,8 @@ static const uint8 atariStAgiPalette[16 * 3] = {
* 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,
@@ -127,6 +131,7 @@ static const uint8 appleIIgsAgiPaletteV2[16 * 3] = {
0xE, 0xE, 0x0,
0xF, 0xF, 0xF
};
+#endif
/**
* First generation Amiga & Apple IIGS AGI palette.
diff --git a/engines/agi/preagi_mickey.cpp b/engines/agi/preagi_mickey.cpp
index a1572d7f1f..883107a957 100644
--- a/engines/agi/preagi_mickey.cpp
+++ b/engines/agi/preagi_mickey.cpp
@@ -2299,6 +2299,8 @@ void MickeyEngine::init() {
_gameStateMickey.fItemUsed[IDI_MSA_ITEM_LETTER] = true;
#endif
+
+ setflag(fSoundOn, true); // enable sound
}
Common::Error MickeyEngine::go() {
diff --git a/engines/agos/agos.cpp b/engines/agos/agos.cpp
index 6eda2eb9aa..8952e649fd 100644
--- a/engines/agos/agos.cpp
+++ b/engines/agos/agos.cpp
@@ -585,7 +585,9 @@ Common::Error AGOSEngine::init() {
((getFeatures() & GF_TALKIE) && getPlatform() == Common::kPlatformAcorn) ||
(getPlatform() == Common::kPlatformDOS)) {
- int ret = _midi->open(getGameType());
+ bool isDemo = (getFeatures() & GF_DEMO) ? true : false;
+
+ int ret = _midi->open(getGameType(), isDemo);
if (ret)
warning("MIDI Player init failed: \"%s\"", MidiDriver::getErrorName(ret));
diff --git a/engines/agos/detection_tables.h b/engines/agos/detection_tables.h
index 2f4709c49e..793d4081cf 100644
--- a/engines/agos/detection_tables.h
+++ b/engines/agos/detection_tables.h
@@ -1385,7 +1385,7 @@ static const AGOSGameDescription gameDescriptions[] = {
{
{
"simon1",
- "Floppy",
+ "Infocom Floppy",
{
{ "gamepc", GAME_BASEFILE, "9f93d27432ce44a787eef10adb640870", 37070},
@@ -1409,7 +1409,7 @@ static const AGOSGameDescription gameDescriptions[] = {
{
{
"simon1",
- "Floppy",
+ "Infocom Floppy",
{
{ "gamepc", GAME_BASEFILE, "62de24fc579b94fac7d3d23201b65b14", -1},
@@ -1599,11 +1599,11 @@ static const AGOSGameDescription gameDescriptions[] = {
GF_TALKIE
},
- // Simon the Sorcerer 1 - English DOS CD alternate?
+ // Simon the Sorcerer 1 - English DOS CD (Infocom)
{
{
"simon1",
- "CD",
+ "Infocom CD",
{
{ "gamepc", GAME_BASEFILE, "c0b948b6821d2140f8b977144f21027a", -1},
diff --git a/engines/agos/drivers/accolade/adlib.cpp b/engines/agos/drivers/accolade/adlib.cpp
new file mode 100644
index 0000000000..294be2b8a7
--- /dev/null
+++ b/engines/agos/drivers/accolade/adlib.cpp
@@ -0,0 +1,883 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public 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 "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"
+
+namespace AGOS {
+
+#define AGOS_ADLIB_VOICES_COUNT 11
+#define AGOS_ADLIB_VOICES_MELODIC_COUNT 6
+#define AGOS_ADLIB_VOICES_PERCUSSION_START 6
+#define AGOS_ADLIB_VOICES_PERCUSSION_COUNT 5
+#define AGOS_ADLIB_VOICES_PERCUSSION_CYMBAL 9
+
+// 5 instruments on top of the regular MIDI ones
+// used by the MUSIC.DRV variant for percussion instruments
+#define AGOS_ADLIB_EXTRA_INSTRUMENT_COUNT 5
+
+const byte operator1Register[AGOS_ADLIB_VOICES_COUNT] = {
+ 0x00, 0x01, 0x02, 0x08, 0x09, 0x0A, 0x10, 0x14, 0x12, 0x15, 0x11
+};
+
+const byte operator2Register[AGOS_ADLIB_VOICES_COUNT] = {
+ 0x03, 0x04, 0x05, 0x0B, 0x0C, 0x0D, 0x13, 0xFF, 0xFF, 0xFF, 0xFF
+};
+
+// percussion:
+// voice 6 - base drum - also uses operator 13h
+// voice 7 - snare drum
+// voice 8 - tom tom
+// voice 9 - cymbal
+// voice 10 - hi hat
+const byte percussionBits[AGOS_ADLIB_VOICES_PERCUSSION_COUNT] = {
+ 0x10, 0x08, 0x04, 0x02, 0x01
+};
+
+// hardcoded, dumped from Accolade music system
+// same for INSTR.DAT + MUSIC.DRV, except that MUSIC.DRV does the lookup differently
+const byte percussionKeyNoteChannelTable[] = {
+ 0x06, 0x07, 0x07, 0x07, 0x07, 0x08, 0x0A, 0x08, 0x0A, 0x08,
+ 0x0A, 0x08, 0x08, 0x09, 0x08, 0x09, 0x0F, 0x0F, 0x0A, 0x0F,
+ 0x0A, 0x0F, 0x0F, 0x0F, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
+ 0x08, 0x08, 0x08, 0x08, 0x0A, 0x0F, 0x0F, 0x08, 0x0F, 0x08
+};
+
+struct InstrumentEntry {
+ byte reg20op1; // Amplitude Modulation / Vibrato / Envelope Generator Type / Keyboard Scaling Rate / Modulator Frequency Multiple
+ byte reg40op1; // Level Key Scaling / Total Level
+ byte reg60op1; // Attack Rate / Decay Rate
+ byte reg80op1; // Sustain Level / Release Rate
+ byte reg20op2; // Amplitude Modulation / Vibrato / Envelope Generator Type / Keyboard Scaling Rate / Modulator Frequency Multiple
+ byte reg40op2; // Level Key Scaling / Total Level
+ byte reg60op2; // Attack Rate / Decay Rate
+ byte reg80op2; // Sustain Level / Release Rate
+ byte regC0; // Feedback / Algorithm, bit 0 - set -> both operators in use
+};
+
+// hardcoded, dumped from Accolade music system (INSTR.DAT variant)
+const uint16 frequencyLookUpTable[12] = {
+ 0x02B2, 0x02DB, 0x0306, 0x0334, 0x0365, 0x0399, 0x03CF,
+ 0xFE05, 0xFE23, 0xFE44, 0xFE67, 0xFE8B
+};
+
+// hardcoded, dumped from Accolade music system (MUSIC.DRV variant)
+const uint16 frequencyLookUpTableMusicDrv[12] = {
+ 0x0205, 0x0223, 0x0244, 0x0267, 0x028B, 0x02B2, 0x02DB,
+ 0x0306, 0x0334, 0x0365, 0x0399, 0x03CF
+};
+
+//
+// Accolade adlib music driver
+//
+// Remarks:
+//
+// There are at least 2 variants of this sound system.
+// One for the games Elvira 1 + Elvira 2
+// It seems it was also used for the game "Altered Destiny"
+// Another one for the games Waxworks + Simon, the Sorcerer 1 Demo
+//
+// First one uses the file INSTR.DAT for instrument data, channel mapping etc.
+// Second one uses the file MUSIC.DRV, which actually contains driver code + instrument data + channel mapping, etc.
+//
+// The second variant supported dynamic channel allocation for the FM voice channels, but this
+// feature was at least definitely disabled for Simon, the Sorcerer 1 demo and for the Waxworks demo too.
+//
+// I have currently not implemented dynamic channel allocation.
+
+class MidiDriver_Accolade_AdLib : public MidiDriver {
+public:
+ MidiDriver_Accolade_AdLib();
+ virtual ~MidiDriver_Accolade_AdLib();
+
+ // MidiDriver
+ int open();
+ void close();
+ void send(uint32 b);
+ MidiChannel *allocateChannel() { return NULL; }
+ MidiChannel *getPercussionChannel() { return NULL; }
+
+ bool isOpen() const { return _isOpen; }
+ uint32 getBaseTempo() { return 1000000 / OPL::OPL::kDefaultCallbackFrequency; }
+
+ void setVolume(byte volume);
+ virtual uint32 property(int prop, uint32 param);
+
+ bool setupInstruments(byte *instrumentData, uint16 instrumentDataSize, bool useMusicDrvFile);
+
+ void setTimerCallback(void *timerParam, Common::TimerManager::TimerProc timerProc);
+
+private:
+ bool _musicDrvMode;
+
+ // from INSTR.DAT/MUSIC.DRV - simple mapping between MIDI channel and MT32 channel
+ byte _channelMapping[AGOS_MIDI_CHANNEL_COUNT];
+ // from INSTR.DAT/MUSIC.DRV - simple mapping between MIDI instruments and MT32 instruments
+ byte _instrumentMapping[AGOS_MIDI_INSTRUMENT_COUNT];
+ // from INSTR.DAT/MUSIC.DRV - volume adjustment per instrument
+ signed char _instrumentVolumeAdjust[AGOS_MIDI_INSTRUMENT_COUNT];
+ // simple mapping between MIDI key notes and MT32 key notes
+ byte _percussionKeyNoteMapping[AGOS_MIDI_KEYNOTE_COUNT];
+
+ // from INSTR.DAT/MUSIC.DRV - adlib instrument data
+ InstrumentEntry *_instrumentTable;
+ byte _instrumentCount;
+
+ struct ChannelEntry {
+ const InstrumentEntry *currentInstrumentPtr;
+ byte currentNote;
+ byte currentA0hReg;
+ byte currentB0hReg;
+ int16 volumeAdjust;
+
+ ChannelEntry() : currentInstrumentPtr(NULL), currentNote(0),
+ currentA0hReg(0), currentB0hReg(0), volumeAdjust(0) { }
+ };
+
+ byte _percussionReg;
+
+ OPL::OPL *_opl;
+ int _masterVolume;
+
+ Common::TimerManager::TimerProc _adlibTimerProc;
+ void *_adlibTimerParam;
+
+ bool _isOpen;
+
+ // stores information about all FM voice channels
+ ChannelEntry _channels[AGOS_ADLIB_VOICES_COUNT];
+
+ void onTimer();
+
+ void resetAdLib();
+ void resetAdLibOperatorRegisters(byte baseRegister, byte value);
+ void resetAdLibFMVoiceChannelRegisters(byte baseRegister, byte value);
+
+ void programChange(byte FMvoiceChannel, byte mappedInstrumentNr, byte MIDIinstrumentNr);
+ void programChangeSetInstrument(byte FMvoiceChannel, byte mappedInstrumentNr, byte MIDIinstrumentNr);
+ void setRegister(int reg, int value);
+ void noteOn(byte FMvoiceChannel, byte note, byte velocity);
+ void noteOnSetVolume(byte FMvoiceChannel, byte operatorReg, byte adjustedVelocity);
+ void noteOff(byte FMvoiceChannel, byte note, bool dontCheckNote);
+};
+
+MidiDriver_Accolade_AdLib::MidiDriver_Accolade_AdLib()
+ : _masterVolume(15), _opl(0),
+ _adlibTimerProc(0), _adlibTimerParam(0), _isOpen(false) {
+ memset(_channelMapping, 0, sizeof(_channelMapping));
+ memset(_instrumentMapping, 0, sizeof(_instrumentMapping));
+ memset(_instrumentVolumeAdjust, 0, sizeof(_instrumentVolumeAdjust));
+ memset(_percussionKeyNoteMapping, 0, sizeof(_percussionKeyNoteMapping));
+
+ _instrumentTable = NULL;
+ _instrumentCount = 0;
+ _musicDrvMode = false;
+ _percussionReg = 0x20;
+}
+
+MidiDriver_Accolade_AdLib::~MidiDriver_Accolade_AdLib() {
+ if (_instrumentTable) {
+ delete[] _instrumentTable;
+ _instrumentCount = 0;
+ }
+}
+
+int MidiDriver_Accolade_AdLib::open() {
+// debugC(kDebugLevelAdLibDriver, "AdLib: starting driver");
+
+ _opl = OPL::Config::create(OPL::Config::kOpl2);
+
+ if (!_opl)
+ return -1;
+
+ _opl->init();
+
+ _isOpen = true;
+
+ _opl->start(new Common::Functor0Mem<void, MidiDriver_Accolade_AdLib>(this, &MidiDriver_Accolade_AdLib::onTimer));
+
+ resetAdLib();
+
+ // Finally set up default instruments
+ for (byte FMvoiceNr = 0; FMvoiceNr < AGOS_ADLIB_VOICES_COUNT; FMvoiceNr++) {
+ if (FMvoiceNr < AGOS_ADLIB_VOICES_PERCUSSION_START) {
+ // Regular FM voices with instrument 0
+ programChangeSetInstrument(FMvoiceNr, 0, 0);
+ } else {
+ byte percussionInstrument;
+ if (!_musicDrvMode) {
+ // INSTR.DAT: percussion voices with instrument 1, 2, 3, 4 and 5
+ percussionInstrument = FMvoiceNr - AGOS_ADLIB_VOICES_PERCUSSION_START + 1;
+ } else {
+ // MUSIC.DRV: percussion voices with instrument 0x80, 0x81, 0x82, 0x83 and 0x84
+ percussionInstrument = FMvoiceNr - AGOS_ADLIB_VOICES_PERCUSSION_START + 0x80;
+ }
+ programChangeSetInstrument(FMvoiceNr, percussionInstrument, percussionInstrument);
+ }
+ }
+
+ // driver initialization does this here:
+ // INSTR.DAT
+ // noteOn(9, 0x29, 0);
+ // noteOff(9, 0x26, false);
+ // MUSIC.DRV
+ // noteOn(9, 0x26, 0);
+ // noteOff(9, 0x26, false);
+
+ return 0;
+}
+
+void MidiDriver_Accolade_AdLib::close() {
+ delete _opl;
+ _isOpen = false;
+}
+
+void MidiDriver_Accolade_AdLib::setVolume(byte volume) {
+ _masterVolume = volume;
+ //renewNotes(-1, true);
+}
+
+void MidiDriver_Accolade_AdLib::onTimer() {
+ if (_adlibTimerProc)
+ (*_adlibTimerProc)(_adlibTimerParam);
+}
+
+void MidiDriver_Accolade_AdLib::resetAdLib() {
+ // The original driver sent 0x00 to register 0x00 up to 0xF5
+ setRegister(0xBD, 0x00); // Disable rhythm
+
+ // reset FM voice instrument data
+ resetAdLibOperatorRegisters(0x20, 0);
+ resetAdLibOperatorRegisters(0x60, 0);
+ resetAdLibOperatorRegisters(0x80, 0);
+ resetAdLibFMVoiceChannelRegisters(0xA0, 0);
+ resetAdLibFMVoiceChannelRegisters(0xB0, 0);
+ resetAdLibFMVoiceChannelRegisters(0xC0, 0);
+ resetAdLibOperatorRegisters(0xE0, 0);
+ resetAdLibOperatorRegisters(0x40, 0x3F); // original driver sent 0x00
+
+ setRegister(0x01, 0x20); // enable waveform control on both operators
+ setRegister(0x04, 0x60); // Timer control
+
+ setRegister(0x08, 0); // select FM music mode
+ setRegister(0xBD, 0x20); // Enable rhythm
+
+ // reset our percussion register
+ _percussionReg = 0x20;
+}
+
+void MidiDriver_Accolade_AdLib::resetAdLibOperatorRegisters(byte baseRegister, byte value) {
+ byte operatorIndex;
+
+ for (operatorIndex = 0; operatorIndex < 0x16; operatorIndex++) {
+ switch (operatorIndex) {
+ case 0x06:
+ case 0x07:
+ case 0x0E:
+ case 0x0F:
+ break;
+ default:
+ setRegister(baseRegister + operatorIndex, value);
+ }
+ }
+}
+
+void MidiDriver_Accolade_AdLib::resetAdLibFMVoiceChannelRegisters(byte baseRegister, byte value) {
+ byte FMvoiceChannel;
+
+ for (FMvoiceChannel = 0; FMvoiceChannel < AGOS_ADLIB_VOICES_COUNT; FMvoiceChannel++) {
+ setRegister(baseRegister + FMvoiceChannel, value);
+ }
+}
+
+// MIDI messages can be found at http://www.midi.org/techspecs/midimessages.php
+void MidiDriver_Accolade_AdLib::send(uint32 b) {
+ byte command = b & 0xf0;
+ byte channel = b & 0xf;
+ byte op1 = (b >> 8) & 0xff;
+ byte op2 = (b >> 16) & 0xff;
+
+ byte mappedChannel = _channelMapping[channel];
+ byte mappedInstrument = 0;
+
+ // Ignore everything that is outside of our channel range
+ if (mappedChannel >= AGOS_ADLIB_VOICES_COUNT)
+ return;
+
+ switch (command) {
+ case 0x80:
+ noteOff(mappedChannel, op1, false);
+ break;
+ case 0x90:
+ // Convert noteOn with velocity 0 to a noteOff
+ if (op2 == 0)
+ return noteOff(mappedChannel, op1, false);
+
+ noteOn(mappedChannel, op1, op2);
+ break;
+ case 0xb0: // Control change
+ // Doesn't seem to be implemented
+ break;
+ case 0xc0: // Program Change
+ mappedInstrument = _instrumentMapping[op1];
+ programChange(mappedChannel, mappedInstrument, op1);
+ break;
+ case 0xa0: // Polyphonic key pressure (aftertouch)
+ case 0xd0: // Channel pressure (aftertouch)
+ // Aftertouch doesn't seem to be implemented
+ break;
+ case 0xe0:
+ // No pitch bend change
+ break;
+ case 0xf0: // SysEx
+ warning("ADLIB: SysEx: %x", b);
+ break;
+ default:
+ warning("ADLIB: Unknown event %02x", command);
+ }
+}
+
+void MidiDriver_Accolade_AdLib::setTimerCallback(void *timerParam, Common::TimerManager::TimerProc timerProc) {
+ _adlibTimerProc = timerProc;
+ _adlibTimerParam = timerParam;
+}
+
+void MidiDriver_Accolade_AdLib::noteOn(byte FMvoiceChannel, byte note, byte velocity) {
+ byte adjustedNote = note;
+ byte adjustedVelocity = velocity;
+ byte regValueA0h = 0;
+ byte regValueB0h = 0;
+
+ // adjust velocity
+ int16 channelVolumeAdjust = _channels[FMvoiceChannel].volumeAdjust;
+ channelVolumeAdjust += adjustedVelocity;
+ channelVolumeAdjust = CLIP<int16>(channelVolumeAdjust, 0, 0x7F);
+
+ // TODO: adjust to global volume
+ // original drivers had a global volume variable, which was 0 for full volume, -64 for half volume
+ // and -128 for mute
+
+ adjustedVelocity = channelVolumeAdjust;
+
+ if (!_musicDrvMode) {
+ // INSTR.DAT
+ // force note-off
+ noteOff(FMvoiceChannel, note, true);
+
+ } else {
+ // MUSIC.DRV
+ if (FMvoiceChannel < AGOS_ADLIB_VOICES_PERCUSSION_START) {
+ // force note-off, but only for actual FM voice channels
+ noteOff(FMvoiceChannel, note, true);
+ }
+ }
+
+ if (FMvoiceChannel != 9) {
+ // regular FM voice
+
+ if (!_musicDrvMode) {
+ // INSTR.DAT: adjust key note
+ while (adjustedNote < 24)
+ adjustedNote += 12;
+ adjustedNote -= 12;
+ }
+
+ } else {
+ // percussion channel
+ // MUSIC.DRV variant didn't do this adjustment, it directly used a pointer
+ adjustedNote -= 36;
+ if (adjustedNote > 40) { // Security check
+ warning("ADLIB: bad percussion channel note");
+ return;
+ }
+
+ byte percussionChannel = percussionKeyNoteChannelTable[adjustedNote];
+ if (percussionChannel >= AGOS_ADLIB_VOICES_COUNT)
+ return; // INSTR.DAT variant checked for ">" instead of ">=", which seems to have been a bug
+
+ // Map the keynote accordingly
+ adjustedNote = _percussionKeyNoteMapping[adjustedNote];
+ // Now overwrite the FM voice channel
+ FMvoiceChannel = percussionChannel;
+ }
+
+ if (!_musicDrvMode) {
+ // INSTR.DAT
+
+ // Save this key note
+ _channels[FMvoiceChannel].currentNote = adjustedNote;
+
+ adjustedVelocity += 24;
+ if (adjustedVelocity > 120)
+ adjustedVelocity = 120;
+ adjustedVelocity = adjustedVelocity >> 1; // divide by 2
+
+ } else {
+ // MUSIC.DRV
+ adjustedVelocity = adjustedVelocity >> 1; // divide by 2
+ }
+
+ // Set volume of voice channel
+ noteOnSetVolume(FMvoiceChannel, 1, adjustedVelocity);
+ if (FMvoiceChannel <= AGOS_ADLIB_VOICES_PERCUSSION_START) {
+ // Set second operator for FM voices + first percussion
+ noteOnSetVolume(FMvoiceChannel, 2, adjustedVelocity);
+ }
+
+ if (FMvoiceChannel >= AGOS_ADLIB_VOICES_PERCUSSION_START) {
+ // Percussion
+ byte percussionIdx = FMvoiceChannel - AGOS_ADLIB_VOICES_PERCUSSION_START;
+
+ // Enable bit of the requested percussion type
+ assert(percussionIdx < AGOS_ADLIB_VOICES_PERCUSSION_COUNT);
+ _percussionReg |= percussionBits[percussionIdx];
+ setRegister(0xBD, _percussionReg);
+ }
+
+ if (FMvoiceChannel < AGOS_ADLIB_VOICES_PERCUSSION_CYMBAL) {
+ // FM voice, Base Drum, Snare Drum + Tom Tom
+ byte adlibNote = adjustedNote;
+ byte adlibOctave = 0;
+ byte adlibFrequencyIdx = 0;
+ uint16 adlibFrequency = 0;
+
+ if (!_musicDrvMode) {
+ // INSTR.DAT
+ if (adlibNote >= 0x60)
+ adlibNote = 0x5F;
+
+ adlibOctave = (adlibNote / 12) - 1;
+ adlibFrequencyIdx = adlibNote % 12;
+ adlibFrequency = frequencyLookUpTable[adlibFrequencyIdx];
+
+ if (adlibFrequency & 0x8000)
+ adlibOctave++;
+ if (adlibOctave & 0x80) {
+ adlibOctave++;
+ adlibFrequency = adlibFrequency >> 1;
+ }
+
+ } else {
+ // MUSIC.DRV variant
+ if (adlibNote >= 19)
+ adlibNote -= 19;
+
+ adlibOctave = (adlibNote / 12);
+ adlibFrequencyIdx = adlibNote % 12;
+ // additional code, that will lookup octave and do a multiplication with it
+ // noteOn however calls the frequency calculation in a way that it multiplies with 0
+ adlibFrequency = frequencyLookUpTableMusicDrv[adlibFrequencyIdx];
+ }
+
+ regValueA0h = adlibFrequency & 0xFF;
+ regValueB0h = ((adlibFrequency & 0x300) >> 8) | (adlibOctave << 2);
+ if (FMvoiceChannel < AGOS_ADLIB_VOICES_PERCUSSION_START) {
+ // set Key-On flag for regular FM voices, but not for percussion
+ regValueB0h |= 0x20;
+ }
+
+ setRegister(0xA0 + FMvoiceChannel, regValueA0h);
+ setRegister(0xB0 + FMvoiceChannel, regValueB0h);
+ _channels[FMvoiceChannel].currentA0hReg = regValueA0h;
+ _channels[FMvoiceChannel].currentB0hReg = regValueB0h;
+
+ if (_musicDrvMode) {
+ // MUSIC.DRV
+ if (FMvoiceChannel < AGOS_ADLIB_VOICES_MELODIC_COUNT) {
+ _channels[FMvoiceChannel].currentNote = adjustedNote;
+ }
+ }
+ }
+}
+
+// 100% the same for INSTR.DAT and MUSIC.DRV variants
+// except for a bug, that was introduced for MUSIC.DRV
+void MidiDriver_Accolade_AdLib::noteOnSetVolume(byte FMvoiceChannel, byte operatorNr, byte adjustedVelocity) {
+ byte operatorReg = 0;
+ byte regValue40h = 0;
+ const InstrumentEntry *curInstrument = NULL;
+
+ regValue40h = (63 - adjustedVelocity) & 0x3F;
+
+ if ((operatorNr == 1) && (FMvoiceChannel <= AGOS_ADLIB_VOICES_PERCUSSION_START)) {
+ // first operator of FM voice channels or first percussion channel
+ curInstrument = _channels[FMvoiceChannel].currentInstrumentPtr;
+ if (!(curInstrument->regC0 & 0x01)) { // check, if both operators produce sound
+ // only one does, instrument wants fixed volume
+ if (operatorNr == 1) {
+ regValue40h = curInstrument->reg40op1;
+ } else {
+ regValue40h = curInstrument->reg40op2;
+ }
+
+ // not sure, if we are supposed to implement these bugs, or not
+#if 0
+ if (!_musicDrvMode) {
+ // Table is 16 bytes instead of 18 bytes
+ if ((FMvoiceChannel == 7) || (FMvoiceChannel == 9)) {
+ regValue40h = 0;
+ warning("volume set bug (original)");
+ }
+ }
+ if (_musicDrvMode) {
+ // MUSIC.DRV variant has a bug, which will overwrite these registers
+ // for all operators above 11 / 0Bh, which means percussion will always
+ // get a value of 0 (the table holding those bytes was 12 bytes instead of 18
+ if (FMvoiceChannel >= AGOS_ADLIB_VOICES_PERCUSSION_START) {
+ regValue40h = 0;
+ warning("volume set bug (original)");
+ }
+ }
+#endif
+ }
+ }
+
+ if (operatorNr == 1) {
+ operatorReg = operator1Register[FMvoiceChannel];
+ } else {
+ operatorReg = operator2Register[FMvoiceChannel];
+ }
+ assert(operatorReg != 0xFF); // Security check
+ setRegister(0x40 + operatorReg, regValue40h);
+}
+
+void MidiDriver_Accolade_AdLib::noteOff(byte FMvoiceChannel, byte note, bool dontCheckNote) {
+ byte adjustedNote = note;
+ byte regValueB0h = 0;
+
+ if (FMvoiceChannel < AGOS_ADLIB_VOICES_PERCUSSION_START) {
+ // regular FM voice
+
+ if (!_musicDrvMode) {
+ // INSTR.DAT: adjust key note
+ while (adjustedNote < 24)
+ adjustedNote += 12;
+ adjustedNote -= 12;
+ }
+
+ if (!dontCheckNote) {
+ // check, if current note is also the current actually playing channel note
+ if (_channels[FMvoiceChannel].currentNote != adjustedNote)
+ return; // not the same -> ignore this note off command
+ }
+
+ regValueB0h = _channels[FMvoiceChannel].currentB0hReg & 0xDF; // Remove "key on" bit
+ setRegister(0xB0 + FMvoiceChannel, regValueB0h);
+
+ } else {
+ // percussion
+ adjustedNote -= 36;
+ if (adjustedNote > 40) { // Security check
+ warning("ADLIB: bad percussion channel note");
+ return;
+ }
+
+ byte percussionChannel = percussionKeyNoteChannelTable[adjustedNote];
+ if (percussionChannel > AGOS_ADLIB_VOICES_COUNT)
+ return;
+
+ byte percussionIdx = percussionChannel - AGOS_ADLIB_VOICES_PERCUSSION_START;
+
+ // Disable bit of the requested percussion type
+ assert(percussionIdx < AGOS_ADLIB_VOICES_PERCUSSION_COUNT);
+ _percussionReg &= ~percussionBits[percussionIdx];
+ setRegister(0xBD, _percussionReg);
+ }
+}
+
+void MidiDriver_Accolade_AdLib::programChange(byte FMvoiceChannel, byte mappedInstrumentNr, byte MIDIinstrumentNr) {
+ if (mappedInstrumentNr >= _instrumentCount) {
+ warning("ADLIB: tried to set non-existent instrument");
+ return; // out of range
+ }
+
+ // setup instrument
+ //warning("ADLIB: program change for FM voice channel %d, instrument id %d", FMvoiceChannel, mappedInstrumentNr);
+
+ if (FMvoiceChannel < AGOS_ADLIB_VOICES_PERCUSSION_START) {
+ // Regular FM voice
+ programChangeSetInstrument(FMvoiceChannel, mappedInstrumentNr, MIDIinstrumentNr);
+
+ } else {
+ // Percussion
+ // set default instrument (again)
+ byte percussionInstrumentNr = 0;
+ const InstrumentEntry *instrumentPtr;
+
+ if (!_musicDrvMode) {
+ // INSTR.DAT: percussion default instruments start at instrument 1
+ percussionInstrumentNr = FMvoiceChannel - AGOS_ADLIB_VOICES_PERCUSSION_START + 1;
+ } else {
+ // MUSIC.DRV: percussion default instruments start at instrument 0x80
+ percussionInstrumentNr = FMvoiceChannel - AGOS_ADLIB_VOICES_PERCUSSION_START + 0x80;
+ }
+ if (percussionInstrumentNr >= _instrumentCount) {
+ warning("ADLIB: tried to set non-existent instrument");
+ return;
+ }
+ instrumentPtr = &_instrumentTable[percussionInstrumentNr];
+ _channels[FMvoiceChannel].currentInstrumentPtr = instrumentPtr;
+ _channels[FMvoiceChannel].volumeAdjust = _instrumentVolumeAdjust[percussionInstrumentNr];
+ }
+}
+
+void MidiDriver_Accolade_AdLib::programChangeSetInstrument(byte FMvoiceChannel, byte mappedInstrumentNr, byte MIDIinstrumentNr) {
+ const InstrumentEntry *instrumentPtr;
+ byte op1Reg = 0;
+ byte op2Reg = 0;
+
+ if (mappedInstrumentNr >= _instrumentCount) {
+ warning("ADLIB: tried to set non-existent instrument");
+ return; // out of range
+ }
+
+ // setup instrument
+ instrumentPtr = &_instrumentTable[mappedInstrumentNr];
+ //warning("set instrument for FM voice channel %d, instrument id %d", FMvoiceChannel, mappedInstrumentNr);
+
+ op1Reg = operator1Register[FMvoiceChannel];
+ op2Reg = operator2Register[FMvoiceChannel];
+
+ setRegister(0x20 + op1Reg, instrumentPtr->reg20op1);
+ setRegister(0x40 + op1Reg, instrumentPtr->reg40op1);
+ setRegister(0x60 + op1Reg, instrumentPtr->reg60op1);
+ setRegister(0x80 + op1Reg, instrumentPtr->reg80op1);
+
+ if (FMvoiceChannel <= AGOS_ADLIB_VOICES_PERCUSSION_START) {
+ // set 2nd operator as well for FM voices and first percussion voice
+ setRegister(0x20 + op2Reg, instrumentPtr->reg20op2);
+ setRegister(0x40 + op2Reg, instrumentPtr->reg40op2);
+ setRegister(0x60 + op2Reg, instrumentPtr->reg60op2);
+ setRegister(0x80 + op2Reg, instrumentPtr->reg80op2);
+
+ if (!_musicDrvMode) {
+ // set Feedback / Algorithm as well
+ setRegister(0xC0 + FMvoiceChannel, instrumentPtr->regC0);
+ } else {
+ if (FMvoiceChannel < AGOS_ADLIB_VOICES_PERCUSSION_START) {
+ // set Feedback / Algorithm as well for regular FM voices only
+ setRegister(0xC0 + FMvoiceChannel, instrumentPtr->regC0);
+ }
+ }
+ }
+
+ // Remember instrument
+ _channels[FMvoiceChannel].currentInstrumentPtr = instrumentPtr;
+ _channels[FMvoiceChannel].volumeAdjust = _instrumentVolumeAdjust[MIDIinstrumentNr];
+}
+
+void MidiDriver_Accolade_AdLib::setRegister(int reg, int value) {
+ _opl->writeReg(reg, value);
+ //warning("OPL %x %x (%d)", reg, value, value);
+}
+
+uint32 MidiDriver_Accolade_AdLib::property(int prop, uint32 param) {
+ return 0;
+}
+
+// Called right at the start, we get an INSTR.DAT entry
+bool MidiDriver_Accolade_AdLib::setupInstruments(byte *driverData, uint16 driverDataSize, bool useMusicDrvFile) {
+ uint16 channelMappingOffset = 0;
+ uint16 channelMappingSize = 0;
+ uint16 instrumentMappingOffset = 0;
+ uint16 instrumentMappingSize = 0;
+ uint16 instrumentVolumeAdjustOffset = 0;
+ uint16 instrumentVolumeAdjustSize = 0;
+ uint16 keyNoteMappingOffset = 0;
+ uint16 keyNoteMappingSize = 0;
+ uint16 instrumentCount = 0;
+ uint16 instrumentDataOffset = 0;
+ uint16 instrumentDataSize = 0;
+ uint16 instrumentEntrySize = 0;
+
+ if (!useMusicDrvFile) {
+ // INSTR.DAT: we expect at least 354 bytes
+ if (driverDataSize < 354)
+ return false;
+
+ // Data is like this:
+ // 128 bytes instrument mapping
+ // 128 bytes instrument volume adjust (signed!)
+ // 16 bytes unknown
+ // 16 bytes channel mapping
+ // 64 bytes key note mapping (not used for MT32)
+ // 1 byte instrument count
+ // 1 byte bytes per instrument
+ // x bytes no instruments used for MT32
+
+ channelMappingOffset = 256 + 16;
+ channelMappingSize = 16;
+ instrumentMappingOffset = 0;
+ instrumentMappingSize = 128;
+ instrumentVolumeAdjustOffset = 128;
+ instrumentVolumeAdjustSize = 128;
+ keyNoteMappingOffset = 256 + 16 + 16;
+ keyNoteMappingSize = 64;
+
+ byte instrDatInstrumentCount = driverData[256 + 16 + 16 + 64];
+ byte instrDatBytesPerInstrument = driverData[256 + 16 + 16 + 64 + 1];
+
+ // We expect 9 bytes per instrument
+ if (instrDatBytesPerInstrument != 9)
+ return false;
+ // And we also expect at least one adlib instrument
+ if (!instrDatInstrumentCount)
+ return false;
+
+ instrumentCount = instrDatInstrumentCount;
+ instrumentDataOffset = 256 + 16 + 16 + 64 + 2;
+ instrumentDataSize = instrDatBytesPerInstrument * instrDatInstrumentCount;
+ instrumentEntrySize = instrDatBytesPerInstrument;
+
+ } else {
+ // MUSIC.DRV: we expect at least 468 bytes
+ if (driverDataSize < 468)
+ return false;
+
+ // music.drv is basically a driver, but with a few fixed locations for certain data
+
+ channelMappingOffset = 396;
+ channelMappingSize = 16;
+ instrumentMappingOffset = 140;
+ instrumentMappingSize = 128;
+ instrumentVolumeAdjustOffset = 140 + 128;
+ instrumentVolumeAdjustSize = 128;
+ keyNoteMappingOffset = 376 + 36; // adjust by 36, because we adjust keyNote before mapping (see noteOn)
+ keyNoteMappingSize = 64;
+
+ // seems to have used 128 + 5 instruments
+ // 128 regular ones and an additional 5 for percussion
+ instrumentCount = 128 + AGOS_ADLIB_EXTRA_INSTRUMENT_COUNT;
+ instrumentDataOffset = 722;
+ instrumentEntrySize = 9;
+ instrumentDataSize = instrumentCount * instrumentEntrySize;
+ }
+
+ // Channel mapping
+ if (channelMappingSize) {
+ // Get these 16 bytes for MIDI channel mapping
+ if (channelMappingSize != sizeof(_channelMapping))
+ return false;
+
+ memcpy(_channelMapping, driverData + channelMappingOffset, sizeof(_channelMapping));
+ } else {
+ // Set up straight mapping
+ for (uint16 channelNr = 0; channelNr < sizeof(_channelMapping); channelNr++) {
+ _channelMapping[channelNr] = channelNr;
+ }
+ }
+
+ if (instrumentMappingSize) {
+ // And these for instrument mapping
+ if (instrumentMappingSize > sizeof(_instrumentMapping))
+ return false;
+
+ memcpy(_instrumentMapping, driverData + instrumentMappingOffset, instrumentMappingSize);
+ }
+ // Set up straight mapping for the remaining data
+ for (uint16 instrumentNr = instrumentMappingSize; instrumentNr < sizeof(_instrumentMapping); instrumentNr++) {
+ _instrumentMapping[instrumentNr] = instrumentNr;
+ }
+
+ if (instrumentVolumeAdjustSize) {
+ if (instrumentVolumeAdjustSize != sizeof(_instrumentVolumeAdjust))
+ return false;
+
+ memcpy(_instrumentVolumeAdjust, driverData + instrumentVolumeAdjustOffset, instrumentVolumeAdjustSize);
+ }
+
+ // Get key note mapping, if available
+ if (keyNoteMappingSize) {
+ if (keyNoteMappingSize != sizeof(_percussionKeyNoteMapping))
+ return false;
+
+ memcpy(_percussionKeyNoteMapping, driverData + keyNoteMappingOffset, keyNoteMappingSize);
+ }
+
+ // Check, if there are enough bytes left to hold all instrument data
+ if (driverDataSize < (instrumentDataOffset + instrumentDataSize))
+ return false;
+
+ // We release previous instrument data, just in case
+ if (_instrumentTable)
+ delete[] _instrumentTable;
+
+ _instrumentTable = new InstrumentEntry[instrumentCount];
+ _instrumentCount = instrumentCount;
+
+ byte *instrDATReadPtr = driverData + instrumentDataOffset;
+ InstrumentEntry *instrumentWritePtr = _instrumentTable;
+
+ for (uint16 instrumentNr = 0; instrumentNr < _instrumentCount; instrumentNr++) {
+ memcpy(instrumentWritePtr, instrDATReadPtr, sizeof(InstrumentEntry));
+ instrDATReadPtr += instrumentEntrySize;
+ instrumentWritePtr++;
+ }
+
+ // Enable MUSIC.DRV-Mode (slightly different behaviour)
+ if (useMusicDrvFile)
+ _musicDrvMode = true;
+
+ if (_musicDrvMode) {
+ // Extra code for MUSIC.DRV
+
+ // This was done during "programChange" in the original driver
+ instrumentWritePtr = _instrumentTable;
+ for (uint16 instrumentNr = 0; instrumentNr < _instrumentCount; instrumentNr++) {
+ instrumentWritePtr->reg80op1 |= 0x03; // set release rate
+ instrumentWritePtr->reg80op2 |= 0x03;
+ instrumentWritePtr++;
+ }
+ }
+ return true;
+}
+
+MidiDriver *MidiDriver_Accolade_AdLib_create(Common::String driverFilename) {
+ byte *driverData = NULL;
+ uint16 driverDataSize = 0;
+ bool isMusicDrvFile = false;
+
+ MidiDriver_Accolade_readDriver(driverFilename, MT_ADLIB, driverData, driverDataSize, isMusicDrvFile);
+ if (!driverData)
+ error("ACCOLADE-ADLIB: error during readDriver()");
+
+ MidiDriver_Accolade_AdLib *driver = new MidiDriver_Accolade_AdLib();
+ if (driver) {
+ if (!driver->setupInstruments(driverData, driverDataSize, isMusicDrvFile)) {
+ delete driver;
+ driver = nullptr;
+ }
+ }
+
+ delete[] driverData;
+ return driver;
+}
+
+} // End of namespace AGOS
diff --git a/engines/agos/drivers/accolade/driverfile.cpp b/engines/agos/drivers/accolade/driverfile.cpp
new file mode 100644
index 0000000000..4ff2fd550f
--- /dev/null
+++ b/engines/agos/drivers/accolade/driverfile.cpp
@@ -0,0 +1,166 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public 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 "agos/agos.h"
+#include "audio/mididrv.h"
+#include "common/error.h"
+#include "common/file.h"
+
+namespace AGOS {
+
+// this reads and gets Accolade driver data
+// we need it for channel mapping, instrument mapping and other things
+// this driver data chunk gets passed to the actual music driver (MT32 / AdLib)
+void MidiDriver_Accolade_readDriver(Common::String filename, MusicType requestedDriverType, byte *&driverData, uint16 &driverDataSize, bool &isMusicDrvFile) {
+ Common::File *driverStream = new Common::File();
+
+ isMusicDrvFile = false;
+
+ if (!driverStream->open(filename)) {
+ error("%s: unable to open file", filename.c_str());
+ }
+
+ if (filename == "INSTR.DAT") {
+ // INSTR.DAT: used by Elvira 1
+ uint32 streamSize = driverStream->size();
+ uint32 streamLeft = streamSize;
+ uint16 skipChunks = 0; // 1 for MT32, 0 for AdLib
+ uint16 chunkSize = 0;
+
+ switch (requestedDriverType) {
+ case MT_ADLIB:
+ skipChunks = 0;
+ break;
+ case MT_MT32:
+ skipChunks = 1; // Skip one entry for MT32
+ break;
+ default:
+ assert(0);
+ break;
+ }
+
+ do {
+ if (streamLeft < 2)
+ error("%s: unexpected EOF", filename.c_str());
+
+ chunkSize = driverStream->readUint16LE();
+ streamLeft -= 2;
+
+ if (streamLeft < chunkSize)
+ error("%s: unexpected EOF", filename.c_str());
+
+ if (skipChunks) {
+ // Skip the chunk
+ driverStream->skip(chunkSize);
+ streamLeft -= chunkSize;
+
+ skipChunks--;
+ }
+ } while (skipChunks);
+
+ // Seek over the ASCII string until there is a NUL terminator
+ byte curByte = 0;
+
+ do {
+ if (chunkSize == 0)
+ error("%s: no actual instrument data found", filename.c_str());
+
+ curByte = driverStream->readByte();
+ chunkSize--;
+ } while (curByte);
+
+ driverDataSize = chunkSize;
+
+ // Read the requested instrument data entry
+ driverData = new byte[driverDataSize];
+ driverStream->read(driverData, driverDataSize);
+
+ } else if (filename == "MUSIC.DRV") {
+ // MUSIC.DRV / used by Elvira 2 / Waxworks / Simon 1 demo
+ uint32 streamSize = driverStream->size();
+ uint32 streamLeft = streamSize;
+ uint16 getChunk = 0; // 4 for MT32, 2 for AdLib
+
+ switch (requestedDriverType) {
+ case MT_ADLIB:
+ getChunk = 2;
+ break;
+ case MT_MT32:
+ getChunk = 4;
+ break;
+ default:
+ assert(0);
+ break;
+ }
+
+ if (streamLeft < 2)
+ error("%s: unexpected EOF", filename.c_str());
+
+ uint16 chunkCount = driverStream->readUint16LE();
+ streamLeft -= 2;
+
+ if (getChunk >= chunkCount)
+ error("%s: required chunk not available", filename.c_str());
+
+ uint16 headerOffset = 2 + (28 * getChunk);
+ streamLeft -= (28 * getChunk);
+
+ if (streamLeft < 28)
+ error("%s: unexpected EOF", filename.c_str());
+
+ // Seek to required chunk
+ driverStream->seek(headerOffset);
+ driverStream->skip(20); // skip over name
+ streamLeft -= 20;
+
+ uint16 musicDrvSignature = driverStream->readUint16LE();
+ uint16 musicDrvType = driverStream->readUint16LE();
+ uint16 chunkOffset = driverStream->readUint16LE();
+ uint16 chunkSize = driverStream->readUint16LE();
+
+ // Security checks
+ if (musicDrvSignature != 0xFEDC)
+ error("%s: chunk signature mismatch", filename.c_str());
+ if (musicDrvType != 1)
+ error("%s: not a music driver", filename.c_str());
+ if (chunkOffset >= streamSize)
+ error("%s: driver chunk points outside of file", filename.c_str());
+
+ streamLeft = streamSize - chunkOffset;
+ if (streamLeft < chunkSize)
+ error("%s: driver chunk is larger than file", filename.c_str());
+
+ driverDataSize = chunkSize;
+
+ // Read the requested instrument data entry
+ driverData = new byte[driverDataSize];
+
+ driverStream->seek(chunkOffset);
+ driverStream->read(driverData, driverDataSize);
+ isMusicDrvFile = true;
+ }
+
+ driverStream->close();
+ delete driverStream;
+}
+
+} // End of namespace AGOS
diff --git a/engines/agos/drivers/accolade/mididriver.h b/engines/agos/drivers/accolade/mididriver.h
new file mode 100644
index 0000000000..253fb6b736
--- /dev/null
+++ b/engines/agos/drivers/accolade/mididriver.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 AGOS_DRIVERS_ACCOLADE_MIDIDRIVER_H
+#define AGOS_DRIVERS_ACCOLADE_MIDIDRIVER_H
+
+#include "agos/agos.h"
+#include "audio/mididrv.h"
+#include "common/error.h"
+
+namespace AGOS {
+
+#define AGOS_MIDI_CHANNEL_COUNT 16
+#define AGOS_MIDI_INSTRUMENT_COUNT 128
+
+#define AGOS_MIDI_KEYNOTE_COUNT 64
+
+extern void MidiDriver_Accolade_readDriver(Common::String filename, MusicType requestedDriverType, byte *&driverData, uint16 &driverDataSize, bool &isMusicDrvFile);
+
+extern MidiDriver *MidiDriver_Accolade_AdLib_create(Common::String driverFilename);
+extern MidiDriver *MidiDriver_Accolade_MT32_create(Common::String driverFilename);
+
+} // End of namespace AGOS
+
+#endif // AGOS_DRIVERS_ACCOLADE_MIDIDRIVER_H
diff --git a/engines/agos/drivers/accolade/mt32.cpp b/engines/agos/drivers/accolade/mt32.cpp
new file mode 100644
index 0000000000..319e0ebf56
--- /dev/null
+++ b/engines/agos/drivers/accolade/mt32.cpp
@@ -0,0 +1,278 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public 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 "agos/agos.h"
+#include "agos/drivers/accolade/mididriver.h"
+
+#include "audio/mididrv.h"
+
+#include "common/config-manager.h"
+#include "common/file.h"
+#include "common/mutex.h"
+#include "common/system.h"
+#include "common/textconsole.h"
+
+namespace AGOS {
+
+class MidiDriver_Accolade_MT32 : public MidiDriver {
+public:
+ MidiDriver_Accolade_MT32();
+ virtual ~MidiDriver_Accolade_MT32();
+
+ // MidiDriver
+ int open();
+ void close();
+ bool isOpen() const { return _isOpen; }
+
+ void send(uint32 b);
+
+ MidiChannel *allocateChannel() {
+ if (_driver)
+ return _driver->allocateChannel();
+ return NULL;
+ }
+ MidiChannel *getPercussionChannel() {
+ if (_driver)
+ return _driver->getPercussionChannel();
+ return NULL;
+ }
+
+ void setTimerCallback(void *timer_param, Common::TimerManager::TimerProc timer_proc) {
+ if (_driver)
+ _driver->setTimerCallback(timer_param, timer_proc);
+ }
+
+ uint32 getBaseTempo() {
+ if (_driver) {
+ return _driver->getBaseTempo();
+ }
+ return 1000000 / _baseFreq;
+ }
+
+protected:
+ Common::Mutex _mutex;
+ MidiDriver *_driver;
+ bool _nativeMT32; // native MT32, may also be our MUNT, or MUNT over MIDI
+
+ bool _isOpen;
+ int _baseFreq;
+
+private:
+ // simple mapping between MIDI channel and MT32 channel
+ byte _channelMapping[AGOS_MIDI_CHANNEL_COUNT];
+ // simple mapping between MIDI instruments and MT32 instruments
+ byte _instrumentMapping[AGOS_MIDI_INSTRUMENT_COUNT];
+
+public:
+ bool setupInstruments(byte *instrumentData, uint16 instrumentDataSize, bool useMusicDrvFile);
+};
+
+MidiDriver_Accolade_MT32::MidiDriver_Accolade_MT32() {
+ _driver = NULL;
+ _isOpen = false;
+ _nativeMT32 = false;
+ _baseFreq = 250;
+
+ memset(_channelMapping, 0, sizeof(_channelMapping));
+ memset(_instrumentMapping, 0, sizeof(_instrumentMapping));
+}
+
+MidiDriver_Accolade_MT32::~MidiDriver_Accolade_MT32() {
+ Common::StackLock lock(_mutex);
+ if (_driver) {
+ _driver->setTimerCallback(0, 0);
+ _driver->close();
+ delete _driver;
+ }
+ _driver = NULL;
+}
+
+int MidiDriver_Accolade_MT32::open() {
+ assert(!_driver);
+
+// debugC(kDebugLevelMT32Driver, "MT32: starting driver");
+
+ // Setup midi driver
+ MidiDriver::DeviceHandle dev = MidiDriver::detectDevice(MDT_MIDI | MDT_PREFER_MT32);
+ MusicType musicType = MidiDriver::getMusicType(dev);
+
+ // check, if we got a real MT32 (or MUNT, or MUNT over MIDI)
+ switch (musicType) {
+ case MT_MT32:
+ _nativeMT32 = true;
+ break;
+ case MT_GM:
+ if (ConfMan.getBool("native_mt32")) {
+ _nativeMT32 = true;
+ }
+ break;
+ default:
+ break;
+ }
+
+ _driver = MidiDriver::createMidi(dev);
+ if (!_driver)
+ return 255;
+
+ int ret = _driver->open();
+ if (ret)
+ return ret;
+
+ if (_nativeMT32)
+ _driver->sendMT32Reset();
+ else
+ _driver->sendGMReset();
+
+ return 0;
+}
+
+void MidiDriver_Accolade_MT32::close() {
+ if (_driver) {
+ _driver->close();
+ }
+}
+
+// MIDI messages can be found at http://www.midi.org/techspecs/midimessages.php
+void MidiDriver_Accolade_MT32::send(uint32 b) {
+ byte command = b & 0xf0;
+ byte channel = b & 0xf;
+
+ if (command == 0xF0) {
+ if (_driver) {
+ _driver->send(b);
+ }
+ return;
+ }
+
+ byte mappedChannel = _channelMapping[channel];
+
+ if (mappedChannel < AGOS_MIDI_CHANNEL_COUNT) {
+ // channel mapped to an actual MIDI channel, so use that one
+ b = (b & 0xFFFFFFF0) | mappedChannel;
+ if (command == 0xC0) {
+ // Program change
+ // Figure out the requested instrument
+ byte midiInstrument = (b >> 8) & 0xFF;
+ byte mappedInstrument = _instrumentMapping[midiInstrument];
+
+ // If there is no actual MT32 (or MUNT), we make a second mapping to General MIDI instruments
+ if (!_nativeMT32) {
+ mappedInstrument = (MidiDriver::_mt32ToGm[mappedInstrument]);
+ }
+ // And replace it
+ b = (b & 0xFFFF00FF) | (mappedInstrument << 8);
+ }
+
+ if (_driver) {
+ _driver->send(b);
+ }
+ }
+}
+
+// Called right at the start, we get an INSTR.DAT entry
+bool MidiDriver_Accolade_MT32::setupInstruments(byte *driverData, uint16 driverDataSize, bool useMusicDrvFile) {
+ uint16 channelMappingOffset = 0;
+ uint16 channelMappingSize = 0;
+ uint16 instrumentMappingOffset = 0;
+ uint16 instrumentMappingSize = 0;
+
+ if (!useMusicDrvFile) {
+ // INSTR.DAT: we expect at least 354 bytes
+ if (driverDataSize < 354)
+ return false;
+
+ // Data is like this:
+ // 128 bytes instrument mapping
+ // 128 bytes instrument volume adjust (signed!) (not used for MT32)
+ // 16 bytes unknown
+ // 16 bytes channel mapping
+ // 64 bytes key note mapping (not really used for MT32)
+ // 1 byte instrument count
+ // 1 byte bytes per instrument
+ // x bytes no instruments used for MT32
+
+ channelMappingOffset = 256 + 16;
+ channelMappingSize = 16;
+ instrumentMappingOffset = 0;
+ instrumentMappingSize = 128;
+
+ } else {
+ // MUSIC.DRV: we expect at least 468 bytes
+ if (driverDataSize < 468)
+ return false;
+
+ channelMappingOffset = 396;
+ channelMappingSize = 16;
+ instrumentMappingOffset = 140;
+ instrumentMappingSize = 128;
+ }
+
+ // Channel mapping
+ if (channelMappingSize) {
+ // Get these 16 bytes for MIDI channel mapping
+ if (channelMappingSize != sizeof(_channelMapping))
+ return false;
+
+ memcpy(_channelMapping, driverData + channelMappingOffset, sizeof(_channelMapping));
+ } else {
+ // Set up straight mapping
+ for (uint16 channelNr = 0; channelNr < sizeof(_channelMapping); channelNr++) {
+ _channelMapping[channelNr] = channelNr;
+ }
+ }
+
+ if (instrumentMappingSize) {
+ // And these for instrument mapping
+ if (instrumentMappingSize > sizeof(_instrumentMapping))
+ return false;
+
+ memcpy(_instrumentMapping, driverData + instrumentMappingOffset, instrumentMappingSize);
+ }
+ // Set up straight mapping for the remaining data
+ for (uint16 instrumentNr = instrumentMappingSize; instrumentNr < sizeof(_instrumentMapping); instrumentNr++) {
+ _instrumentMapping[instrumentNr] = instrumentNr;
+ }
+ return true;
+}
+
+MidiDriver *MidiDriver_Accolade_MT32_create(Common::String driverFilename) {
+ byte *driverData = NULL;
+ uint16 driverDataSize = 0;
+ bool isMusicDrvFile = false;
+
+ MidiDriver_Accolade_readDriver(driverFilename, MT_MT32, driverData, driverDataSize, isMusicDrvFile);
+ if (!driverData)
+ error("ACCOLADE-ADLIB: error during readDriver()");
+
+ MidiDriver_Accolade_MT32 *driver = new MidiDriver_Accolade_MT32();
+ if (driver) {
+ if (!driver->setupInstruments(driverData, driverDataSize, isMusicDrvFile)) {
+ delete driver;
+ driver = nullptr;
+ }
+ }
+
+ delete[] driverData;
+ return driver;
+}
+
+} // End of namespace AGOS
diff --git a/engines/agos/drivers/simon1/adlib.cpp b/engines/agos/drivers/simon1/adlib.cpp
new file mode 100644
index 0000000000..7f1370e8bd
--- /dev/null
+++ b/engines/agos/drivers/simon1/adlib.cpp
@@ -0,0 +1,516 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public 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 "agos/drivers/simon1/adlib.h"
+
+#include "common/textconsole.h"
+#include "common/util.h"
+#include "common/file.h"
+
+namespace AGOS {
+
+enum {
+ kChannelUnused = 0xFF,
+ kChannelOrphanedFlag = 0x80,
+
+ kOPLVoicesCount = 9
+};
+
+MidiDriver_Simon1_AdLib::Voice::Voice()
+ : channel(kChannelUnused), note(0), instrTotalLevel(0), instrScalingLevel(0), frequency(0) {
+}
+
+MidiDriver_Simon1_AdLib::MidiDriver_Simon1_AdLib(const byte *instrumentData)
+ : _isOpen(false), _opl(nullptr), _timerProc(nullptr), _timerParam(nullptr),
+ _melodyVoices(0), _amvdrBits(0), _rhythmEnabled(false), _voices(), _midiPrograms(),
+ _instruments(instrumentData) {
+}
+
+MidiDriver_Simon1_AdLib::~MidiDriver_Simon1_AdLib() {
+ close();
+ delete[] _instruments;
+}
+
+int MidiDriver_Simon1_AdLib::open() {
+ if (_isOpen) {
+ return MERR_ALREADY_OPEN;
+ }
+
+ _opl = OPL::Config::create();
+ if (!_opl) {
+ return MERR_DEVICE_NOT_AVAILABLE;
+ }
+
+ if (!_opl->init()) {
+ delete _opl;
+ _opl = nullptr;
+
+ return MERR_CANNOT_CONNECT;
+ }
+
+ _opl->start(new Common::Functor0Mem<void, MidiDriver_Simon1_AdLib>(this, &MidiDriver_Simon1_AdLib::onTimer));
+
+ _opl->writeReg(0x01, 0x20);
+ _opl->writeReg(0x08, 0x40);
+ _opl->writeReg(0xBD, 0xC0);
+ reset();
+
+ _isOpen = true;
+ return 0;
+}
+
+bool MidiDriver_Simon1_AdLib::isOpen() const {
+ return _isOpen;
+}
+
+void MidiDriver_Simon1_AdLib::close() {
+ setTimerCallback(nullptr, nullptr);
+
+ if (_isOpen) {
+ _opl->stop();
+ delete _opl;
+ _opl = nullptr;
+
+ _isOpen = false;
+ }
+}
+
+void MidiDriver_Simon1_AdLib::send(uint32 b) {
+ int channel = b & 0x0F;
+ int command = b & 0xF0;
+ int param1 = (b >> 8) & 0xFF;
+ int param2 = (b >> 16) & 0xFF;
+
+ // The percussion channel is handled specially. The AdLib output uses
+ // channels 11 to 15 for percussions. For this, the original converted
+ // note on on the percussion channel to note on channels 11 to 15 before
+ // giving it to the AdLib output. We do this in here for simplicity.
+ if (command == 0x90 && channel == 9) {
+ param1 -= 36;
+ if (param1 < 0 || param1 >= ARRAYSIZE(_rhythmMap)) {
+ return;
+ }
+
+ channel = _rhythmMap[param1].channel;
+ MidiDriver::send(0xC0 | channel, _rhythmMap[param1].program, 0);
+
+ param1 = _rhythmMap[param1].note;
+ MidiDriver::send(0x80 | channel, param1, param2);
+
+ param2 >>= 1;
+ }
+
+ switch (command) {
+ case 0x80: // note OFF
+ noteOff(channel, param1);
+ break;
+
+ case 0x90: // note ON
+ if (param2 == 0) {
+ noteOff(channel, param1);
+ } else {
+ noteOn(channel, param1, param2);
+ }
+ break;
+
+ case 0xB0: // control change
+ controlChange(channel, param1, param2);
+ break;
+
+ case 0xC0: // program change
+ programChange(channel, param1);
+ break;
+
+ default:
+ break;
+ }
+}
+
+void MidiDriver_Simon1_AdLib::setTimerCallback(void *timer_param, Common::TimerManager::TimerProc timer_proc) {
+ _timerParam = timer_param;
+ _timerProc = timer_proc;
+}
+
+uint32 MidiDriver_Simon1_AdLib::getBaseTempo() {
+ return 1000000 / OPL::OPL::kDefaultCallbackFrequency;
+}
+
+void MidiDriver_Simon1_AdLib::onTimer() {
+ if (_timerProc) {
+ (*_timerProc)(_timerParam);
+ }
+}
+
+void MidiDriver_Simon1_AdLib::reset() {
+ resetOPLVoices();
+ resetRhythm();
+ for (int i = 0; i < kNumberOfVoices; ++i) {
+ _voices[i].channel = kChannelUnused;
+ }
+ resetVoices();
+}
+
+void MidiDriver_Simon1_AdLib::resetOPLVoices() {
+ _amvdrBits &= 0xE0;
+ _opl->writeReg(0xBD, _amvdrBits);
+ for (int i = 8; i >= 0; --i) {
+ _opl->writeReg(0xB0 + i, 0);
+ }
+}
+
+void MidiDriver_Simon1_AdLib::resetRhythm() {
+ _melodyVoices = 9;
+ _amvdrBits = 0xC0;
+ _opl->writeReg(0xBD, _amvdrBits);
+}
+
+void MidiDriver_Simon1_AdLib::resetVoices() {
+ memset(_midiPrograms, 0, sizeof(_midiPrograms));
+ for (int i = 0; i < kNumberOfVoices; ++i) {
+ _voices[i].channel = kChannelUnused;
+ }
+
+ for (int i = 0; i < kOPLVoicesCount; ++i) {
+ resetRhythm();
+ _opl->writeReg(0x08, 0x00);
+
+ int oplRegister = _operatorMap[i];
+ for (int j = 0; j < 4; ++j) {
+ oplRegister += 0x20;
+
+ _opl->writeReg(oplRegister + 0, _operatorDefaults[2 * j + 0]);
+ _opl->writeReg(oplRegister + 3, _operatorDefaults[2 * j + 1]);
+ }
+
+ _opl->writeReg(oplRegister + 0x60, 0x00);
+ _opl->writeReg(oplRegister + 0x63, 0x00);
+
+ // This seems to be serious bug but the original does it the same way.
+ _opl->writeReg(_operatorMap[i] + i, 0x08);
+ }
+}
+
+int MidiDriver_Simon1_AdLib::allocateVoice(uint channel) {
+ for (int i = 0; i < _melodyVoices; ++i) {
+ if (_voices[i].channel == (channel | kChannelOrphanedFlag)) {
+ return i;
+ }
+ }
+
+ for (int i = 0; i < _melodyVoices; ++i) {
+ if (_voices[i].channel == kChannelUnused) {
+ return i;
+ }
+ }
+
+ for (int i = 0; i < _melodyVoices; ++i) {
+ if (_voices[i].channel > 0x7F) {
+ return i;
+ }
+ }
+
+ // The original had some logic for a priority based reuse of channels.
+ // However, the priority value is always 0, which causes the first channel
+ // to be picked all the time.
+ const int voice = 0;
+ _opl->writeReg(0xA0 + voice, (_voices[voice].frequency ) & 0xFF);
+ _opl->writeReg(0xB0 + voice, (_voices[voice].frequency >> 8) & 0xFF);
+ return voice;
+}
+
+void MidiDriver_Simon1_AdLib::noteOff(uint channel, uint note) {
+ if (_melodyVoices <= 6 && channel >= 11) {
+ _amvdrBits &= ~(_rhythmInstrumentMask[channel - 11]);
+ _opl->writeReg(0xBD, _amvdrBits);
+ } else {
+ for (int i = 0; i < _melodyVoices; ++i) {
+ if (_voices[i].note == note && _voices[i].channel == channel) {
+ _voices[i].channel |= kChannelOrphanedFlag;
+ _opl->writeReg(0xA0 + i, (_voices[i].frequency ) & 0xFF);
+ _opl->writeReg(0xB0 + i, (_voices[i].frequency >> 8) & 0xFF);
+ return;
+ }
+ }
+ }
+}
+
+void MidiDriver_Simon1_AdLib::noteOn(uint channel, uint note, uint velocity) {
+ if (_rhythmEnabled && channel >= 11) {
+ noteOnRhythm(channel, note, velocity);
+ return;
+ }
+
+ const int voiceNum = allocateVoice(channel);
+ Voice &voice = _voices[voiceNum];
+
+ if ((voice.channel & 0x7F) != channel) {
+ setupInstrument(voiceNum, _midiPrograms[channel]);
+ }
+ voice.channel = channel;
+
+ _opl->writeReg(0x43 + _operatorMap[voiceNum], (0x3F - (((velocity | 0x80) * voice.instrTotalLevel) >> 8)) | voice.instrScalingLevel);
+
+ voice.note = note;
+ if (note >= 0x80) {
+ note = 0;
+ }
+
+ const int frequencyAndOctave = _frequencyIndexAndOctaveTable[note];
+ const uint frequency = _frequencyTable[frequencyAndOctave & 0x0F];
+
+ uint highByte = ((frequency & 0xFF00) >> 8) | ((frequencyAndOctave & 0x70) >> 2);
+ uint lowByte = frequency & 0x00FF;
+ voice.frequency = (highByte << 8) | lowByte;
+
+ _opl->writeReg(0xA0 + voiceNum, lowByte);
+ _opl->writeReg(0xB0 + voiceNum, highByte | 0x20);
+}
+
+void MidiDriver_Simon1_AdLib::noteOnRhythm(uint channel, uint note, uint velocity) {
+ const uint voiceNum = channel - 5;
+ Voice &voice = _voices[voiceNum];
+
+ _amvdrBits |= _rhythmInstrumentMask[voiceNum - 6];
+
+ const uint level = (0x3F - (((velocity | 0x80) * voice.instrTotalLevel) >> 8)) | voice.instrScalingLevel;
+ if (voiceNum == 6) {
+ _opl->writeReg(0x43 + _rhythmOperatorMap[voiceNum - 6], level);
+ } else {
+ _opl->writeReg(0x40 + _rhythmOperatorMap[voiceNum - 6], level);
+ }
+
+ voice.note = note;
+ if (note >= 0x80) {
+ note = 0;
+ }
+
+ const int frequencyAndOctave = _frequencyIndexAndOctaveTable[note];
+ const uint frequency = _frequencyTable[frequencyAndOctave & 0x0F];
+
+ uint highByte = ((frequency & 0xFF00) >> 8) | ((frequencyAndOctave & 0x70) >> 2);
+ uint lowByte = frequency & 0x00FF;
+ voice.frequency = (highByte << 8) | lowByte;
+
+ const uint oplOperator = _rhythmVoiceMap[voiceNum - 6];
+ _opl->writeReg(0xA0 + oplOperator, lowByte);
+ _opl->writeReg(0xB0 + oplOperator, highByte);
+
+ _opl->writeReg(0xBD, _amvdrBits);
+}
+
+void MidiDriver_Simon1_AdLib::controlChange(uint channel, uint controller, uint value) {
+ // Enable/Disable Rhythm Section
+ if (controller == 0x67) {
+ resetVoices();
+ _rhythmEnabled = (value != 0);
+
+ if (_rhythmEnabled) {
+ _melodyVoices = 6;
+ _amvdrBits = 0xE0;
+ } else {
+ _melodyVoices = 9;
+ _amvdrBits = 0xC0;
+ }
+
+ _voices[6].channel = kChannelUnused;
+ _voices[7].channel = kChannelUnused;
+ _voices[8].channel = kChannelUnused;
+
+ _opl->writeReg(0xBD, _amvdrBits);
+ }
+}
+
+void MidiDriver_Simon1_AdLib::programChange(uint channel, uint program) {
+ _midiPrograms[channel] = program;
+
+ if (_rhythmEnabled && channel >= 11) {
+ setupInstrument(channel - 5, program);
+ } else {
+ // Fully unallocate all previously allocated but now unused voices for
+ // this MIDI channel.
+ for (uint i = 0; i < kOPLVoicesCount; ++i) {
+ if (_voices[i].channel == (channel | kChannelOrphanedFlag)) {
+ _voices[i].channel = kChannelUnused;
+ }
+ }
+
+ // Set the program for all voices allocted for this MIDI channel.
+ for (uint i = 0; i < kOPLVoicesCount; ++i) {
+ if (_voices[i].channel == channel) {
+ setupInstrument(i, program);
+ }
+ }
+ }
+}
+
+void MidiDriver_Simon1_AdLib::setupInstrument(uint voice, uint instrument) {
+ const byte *instrumentData = _instruments + instrument * 16;
+
+ int scaling = instrumentData[3];
+ if (_rhythmEnabled && voice >= 7) {
+ scaling = instrumentData[2];
+ }
+
+ const int scalingLevel = scaling & 0xC0;
+ const int totalLevel = scaling & 0x3F;
+
+ _voices[voice].instrScalingLevel = scalingLevel;
+ _voices[voice].instrTotalLevel = (-(totalLevel - 0x3F)) & 0xFF;
+
+ if (!_rhythmEnabled || voice <= 6) {
+ int oplRegister = _operatorMap[voice];
+ for (int j = 0; j < 4; ++j) {
+ oplRegister += 0x20;
+ _opl->writeReg(oplRegister + 0, *instrumentData++);
+ _opl->writeReg(oplRegister + 3, *instrumentData++);
+ }
+ oplRegister += 0x60;
+ _opl->writeReg(oplRegister + 0, *instrumentData++);
+ _opl->writeReg(oplRegister + 3, *instrumentData++);
+
+ _opl->writeReg(0xC0 + voice, *instrumentData++);
+ } else {
+ voice -= 7;
+
+ int oplRegister = _rhythmOperatorMap[voice + 1];
+ for (int j = 0; j < 4; ++j) {
+ oplRegister += 0x20;
+ _opl->writeReg(oplRegister + 0, *instrumentData++);
+ ++instrumentData;
+ }
+ oplRegister += 0x60;
+ _opl->writeReg(oplRegister + 0, *instrumentData++);
+ ++instrumentData;
+
+ _opl->writeReg(0xC0 + _rhythmVoiceMap[voice + 1], *instrumentData++);
+ }
+}
+
+const int MidiDriver_Simon1_AdLib::_operatorMap[9] = {
+ 0x00, 0x01, 0x02, 0x08, 0x09, 0x0A, 0x10, 0x11,
+ 0x12
+};
+
+const int MidiDriver_Simon1_AdLib::_operatorDefaults[8] = {
+ 0x01, 0x11, 0x4F, 0x00, 0xF1, 0xF2, 0x53, 0x74
+};
+
+const int MidiDriver_Simon1_AdLib::_rhythmOperatorMap[5] = {
+ 0x10, 0x14, 0x12, 0x15, 0x11
+};
+
+const uint MidiDriver_Simon1_AdLib::_rhythmInstrumentMask[5] = {
+ 0x10, 0x08, 0x04, 0x02, 0x01
+};
+
+const int MidiDriver_Simon1_AdLib::_rhythmVoiceMap[5] = {
+ 6, 7, 8, 8, 7
+};
+
+const int MidiDriver_Simon1_AdLib::_frequencyIndexAndOctaveTable[128] = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0A, 0x0B, 0x00, 0x01, 0x02, 0x03,
+ 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+ 0x18, 0x19, 0x1A, 0x1B, 0x20, 0x21, 0x22, 0x23,
+ 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B,
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
+ 0x38, 0x39, 0x3A, 0x3B, 0x40, 0x41, 0x42, 0x43,
+ 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B,
+ 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
+ 0x58, 0x59, 0x5A, 0x5B, 0x60, 0x61, 0x62, 0x63,
+ 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B,
+ 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
+ 0x78, 0x79, 0x7A, 0x7B, 0x70, 0x71, 0x72, 0x73,
+ 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x7B,
+ 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B
+};
+
+const int MidiDriver_Simon1_AdLib::_frequencyTable[16] = {
+ 0x0157, 0x016B, 0x0181, 0x0198, 0x01B0, 0x01CA, 0x01E5, 0x0202,
+ 0x0220, 0x0241, 0x0263, 0x0287, 0x2100, 0xD121, 0xA307, 0x46A4
+};
+
+const MidiDriver_Simon1_AdLib::RhythmMap MidiDriver_Simon1_AdLib::_rhythmMap[39] = {
+ { 11, 123, 40 },
+ { 12, 127, 50 },
+ { 12, 124, 1 },
+ { 12, 124, 90 },
+ { 13, 125, 50 },
+ { 13, 125, 25 },
+ { 15, 127, 80 },
+ { 13, 125, 25 },
+ { 15, 127, 40 },
+ { 13, 125, 35 },
+ { 15, 127, 90 },
+ { 13, 125, 35 },
+ { 13, 125, 45 },
+ { 14, 126, 90 },
+ { 13, 125, 45 },
+ { 15, 127, 90 },
+ { 0, 0, 0 },
+ { 15, 127, 60 },
+ { 0, 0, 0 },
+ { 13, 125, 60 },
+ { 0, 0, 0 },
+ { 0, 0, 0 },
+ { 0, 0, 0 },
+ { 13, 125, 45 },
+ { 13, 125, 40 },
+ { 13, 125, 35 },
+ { 13, 125, 30 },
+ { 13, 125, 25 },
+ { 13, 125, 80 },
+ { 13, 125, 40 },
+ { 13, 125, 80 },
+ { 13, 125, 40 },
+ { 14, 126, 40 },
+ { 15, 127, 60 },
+ { 0, 0, 0 },
+ { 0, 0, 0 },
+ { 14, 126, 80 },
+ { 0, 0, 0 },
+ { 13, 125, 100 }
+};
+
+MidiDriver *createMidiDriverSimon1AdLib(const char *instrumentFilename) {
+ // Load instrument data.
+ Common::File ibk;
+
+ if (!ibk.open(instrumentFilename)) {
+ return nullptr;
+ }
+
+ if (ibk.readUint32BE() != 0x49424b1a) {
+ return nullptr;
+ }
+
+ byte *instrumentData = new byte[128 * 16];
+ if (ibk.read(instrumentData, 128 * 16) != 128 * 16) {
+ delete[] instrumentData;
+ return nullptr;
+ }
+
+ return new MidiDriver_Simon1_AdLib(instrumentData);
+}
+
+} // End of namespace AGOS
diff --git a/engines/agos/drivers/simon1/adlib.h b/engines/agos/drivers/simon1/adlib.h
new file mode 100644
index 0000000000..6057bf1b16
--- /dev/null
+++ b/engines/agos/drivers/simon1/adlib.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 AGOS_SIMON1_ADLIB_H
+#define AGOS_SIMON1_ADLIB_H
+
+#include "audio/mididrv.h"
+#include "audio/fmopl.h"
+
+namespace AGOS {
+
+class MidiDriver_Simon1_AdLib : public MidiDriver {
+public:
+ MidiDriver_Simon1_AdLib(const byte *instrumentData);
+ virtual ~MidiDriver_Simon1_AdLib();
+
+ // MidiDriver API
+ virtual int open();
+ virtual bool isOpen() const;
+ virtual void close();
+
+ virtual void send(uint32 b);
+
+ virtual void setTimerCallback(void *timer_param, Common::TimerManager::TimerProc timer_proc);
+ virtual uint32 getBaseTempo();
+
+ virtual MidiChannel *allocateChannel() { return 0; }
+ virtual MidiChannel *getPercussionChannel() { return 0; }
+private:
+ bool _isOpen;
+
+ OPL::OPL *_opl;
+
+ Common::TimerManager::TimerProc _timerProc;
+ void *_timerParam;
+ void onTimer();
+
+ void reset();
+ void resetOPLVoices();
+
+ void resetRhythm();
+ int _melodyVoices;
+ uint8 _amvdrBits;
+ bool _rhythmEnabled;
+
+ enum {
+ kNumberOfVoices = 11,
+ kNumberOfMidiChannels = 16
+ };
+
+ struct Voice {
+ Voice();
+
+ uint channel;
+ uint note;
+ uint instrTotalLevel;
+ uint instrScalingLevel;
+ uint frequency;
+ };
+
+ void resetVoices();
+ int allocateVoice(uint channel);
+
+ Voice _voices[kNumberOfVoices];
+ uint _midiPrograms[kNumberOfMidiChannels];
+
+ void noteOff(uint channel, uint note);
+ void noteOn(uint channel, uint note, uint velocity);
+ void noteOnRhythm(uint channel, uint note, uint velocity);
+ void controlChange(uint channel, uint controller, uint value);
+ void programChange(uint channel, uint program);
+
+ void setupInstrument(uint voice, uint instrument);
+ const byte *_instruments;
+
+ static const int _operatorMap[9];
+ static const int _operatorDefaults[8];
+
+ static const int _rhythmOperatorMap[5];
+ static const uint _rhythmInstrumentMask[5];
+ static const int _rhythmVoiceMap[5];
+
+ static const int _frequencyIndexAndOctaveTable[128];
+ static const int _frequencyTable[16];
+
+ struct RhythmMap {
+ int channel;
+ int program;
+ int note;
+ };
+
+ static const RhythmMap _rhythmMap[39];
+};
+
+MidiDriver *createMidiDriverSimon1AdLib(const char *instrumentFilename);
+
+} // End of namespace AGOS
+
+#endif
diff --git a/engines/agos/gfx.cpp b/engines/agos/gfx.cpp
index 5a1f9f1917..867842276a 100644
--- a/engines/agos/gfx.cpp
+++ b/engines/agos/gfx.cpp
@@ -1303,6 +1303,13 @@ void AGOSEngine::setWindowImageEx(uint16 mode, uint16 vgaSpriteId) {
} else {
setWindowImage(mode, vgaSpriteId);
}
+
+ // Amiga versions wait for verb area to be displayed.
+ if (getGameType() == GType_SIMON1 && getPlatform() == Common::kPlatformAmiga && vgaSpriteId == 1) {
+ _copyScnFlag = 5;
+ while (_copyScnFlag && !shouldQuit())
+ delay(1);
+ }
}
void AGOSEngine::setWindowImage(uint16 mode, uint16 vgaSpriteId, bool specialCase) {
diff --git a/engines/agos/input.cpp b/engines/agos/input.cpp
index 687a8ef1cf..686b1c35b2 100644
--- a/engines/agos/input.cpp
+++ b/engines/agos/input.cpp
@@ -707,6 +707,7 @@ bool AGOSEngine::processSpecialKeys() {
if (_midiEnabled) {
_midi->pause(_musicPaused);
}
+ _mixer->pauseHandle(_modHandle, _musicPaused);
syncSoundSettings();
break;
case 's':
diff --git a/engines/agos/midi.cpp b/engines/agos/midi.cpp
index e5875a8353..d11ff201ea 100644
--- a/engines/agos/midi.cpp
+++ b/engines/agos/midi.cpp
@@ -23,10 +23,21 @@
#include "common/config-manager.h"
#include "common/file.h"
#include "common/textconsole.h"
+#include "common/memstream.h"
#include "agos/agos.h"
#include "agos/midi.h"
+#include "agos/drivers/accolade/mididriver.h"
+#include "agos/drivers/simon1/adlib.h"
+// Miles Audio for Simon 2
+#include "audio/miles.h"
+
+// PKWARE data compression library decompressor required for Simon 2
+#include "common/dcl.h"
+
+#include "gui/message.h"
+
namespace AGOS {
@@ -42,8 +53,7 @@ MidiPlayer::MidiPlayer() {
_driver = 0;
_map_mt32_to_gm = false;
- _adlibPatches = NULL;
-
+ _adLibMusic = false;
_enable_sfx = true;
_current = 0;
@@ -54,9 +64,11 @@ MidiPlayer::MidiPlayer() {
_paused = false;
_currentTrack = 255;
- _loopTrackDefault = false;
+ _loopTrack = 0;
_queuedTrack = 255;
_loopQueuedTrack = 0;
+
+ _musicMode = kMusicModeDisabled;
}
MidiPlayer::~MidiPlayer() {
@@ -70,15 +82,183 @@ MidiPlayer::~MidiPlayer() {
}
_driver = NULL;
clearConstructs();
- unloadAdlibPatches();
}
-int MidiPlayer::open(int gameType) {
+int MidiPlayer::open(int gameType, bool isDemo) {
// Don't call open() twice!
assert(!_driver);
- // Setup midi driver
- MidiDriver::DeviceHandle dev = MidiDriver::detectDevice(MDT_ADLIB | MDT_MIDI | (gameType == GType_SIMON1 ? MDT_PREFER_MT32 : MDT_PREFER_GM));
+ Common::String accoladeDriverFilename;
+ MusicType musicType = MT_INVALID;
+
+ switch (gameType) {
+ case GType_ELVIRA1:
+ _musicMode = kMusicModeAccolade;
+ accoladeDriverFilename = "INSTR.DAT";
+ break;
+ case GType_ELVIRA2:
+ case GType_WW:
+ // Attention: Elvira 2 shipped with INSTR.DAT and MUSIC.DRV
+ // MUSIC.DRV is the correct one. INSTR.DAT seems to be a left-over
+ _musicMode = kMusicModeAccolade;
+ accoladeDriverFilename = "MUSIC.DRV";
+ break;
+ case GType_SIMON1:
+ if (isDemo) {
+ _musicMode = kMusicModeAccolade;
+ accoladeDriverFilename = "MUSIC.DRV";
+ } else if (Common::File::exists("MT_FM.IBK")) {
+ _musicMode = kMusicModeSimon1;
+ }
+ break;
+ case GType_SIMON2:
+ //_musicMode = kMusicModeMilesAudio;
+ // currently disabled, because there are a few issues
+ // MT32 seems to work fine now, AdLib seems to use bad instruments and is also outputting music on
+ // the right speaker only. The original driver did initialize the panning to 0 and the Simon2 XMIDI
+ // tracks don't set panning at all. We can reset panning to be centered, which would solve this
+ // issue, but we still don't know who's setting it in the original interpreter.
+ break;
+ default:
+ break;
+ }
+
+ MidiDriver::DeviceHandle dev;
+ int ret = 0;
+
+ if (_musicMode != kMusicModeDisabled) {
+ dev = MidiDriver::detectDevice(MDT_MIDI | MDT_ADLIB | MDT_PREFER_MT32);
+ musicType = MidiDriver::getMusicType(dev);
+
+ switch (musicType) {
+ case MT_ADLIB:
+ case MT_MT32:
+ break;
+ case MT_GM:
+ if (!ConfMan.getBool("native_mt32")) {
+ // Not a real MT32 / no MUNT
+ ::GUI::MessageDialog dialog(("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."));
+ dialog.runModal();
+ }
+ // Switch to MT32 driver in any case
+ musicType = MT_MT32;
+ break;
+ default:
+ _musicMode = kMusicModeDisabled;
+ break;
+ }
+ }
+
+ switch (_musicMode) {
+ case kMusicModeAccolade: {
+ // Setup midi driver
+ switch (musicType) {
+ case MT_ADLIB:
+ _driver = MidiDriver_Accolade_AdLib_create(accoladeDriverFilename);
+ break;
+ case MT_MT32:
+ _driver = MidiDriver_Accolade_MT32_create(accoladeDriverFilename);
+ break;
+ default:
+ assert(0);
+ break;
+ }
+ if (!_driver)
+ return 255;
+
+ ret = _driver->open();
+ if (ret == 0) {
+ // Reset is done inside our MIDI driver
+ _driver->setTimerCallback(this, &onTimer);
+ }
+
+ //setTimerRate(_driver->getBaseTempo());
+ return 0;
+ }
+
+ case kMusicModeMilesAudio: {
+ switch (musicType) {
+ case MT_ADLIB: {
+ Common::File instrumentDataFile;
+ if (instrumentDataFile.exists("MIDPAK.AD")) {
+ // if there is a file called MIDPAK.AD, use it directly
+ warning("SIMON 2: using MIDPAK.AD");
+ _driver = Audio::MidiDriver_Miles_AdLib_create("MIDPAK.AD", "MIDPAK.AD");
+ } else {
+ // if there is no file called MIDPAK.AD, try to extract it from the file SETUP.SHR
+ // if we didn't do this, the user would be forced to "install" the game instead of simply
+ // copying all files from CD-ROM.
+ Common::SeekableReadStream *midpakAdLibStream;
+ midpakAdLibStream = simon2SetupExtractFile("MIDPAK.AD");
+ if (!midpakAdLibStream)
+ error("MidiPlayer: could not extract MIDPAK.AD from SETUP.SHR");
+
+ // Pass this extracted data to the driver
+ warning("SIMON 2: using MIDPAK.AD extracted from SETUP.SHR");
+ _driver = Audio::MidiDriver_Miles_AdLib_create("", "", midpakAdLibStream);
+ delete midpakAdLibStream;
+ }
+ // TODO: not sure what's going wrong with AdLib
+ // it doesn't seem to matter if we use the regular XMIDI tracks or the 2nd set meant for MT32
+ break;
+ }
+ case MT_MT32:
+ _driver = Audio::MidiDriver_Miles_MT32_create("");
+ _nativeMT32 = true; // use 2nd set of XMIDI tracks
+ break;
+ case MT_GM:
+ if (ConfMan.getBool("native_mt32")) {
+ _driver = Audio::MidiDriver_Miles_MT32_create("");
+ _nativeMT32 = true; // use 2nd set of XMIDI tracks
+ }
+ break;
+
+ default:
+ break;
+ }
+ if (!_driver)
+ return 255;
+
+ ret = _driver->open();
+ if (ret == 0) {
+ // Reset is done inside our MIDI driver
+ _driver->setTimerCallback(this, &onTimer);
+ }
+ return 0;
+ }
+
+ case kMusicModeSimon1: {
+ // This only handles the original AdLib driver of Simon1.
+ if (musicType == MT_ADLIB) {
+ _adLibMusic = true;
+ _map_mt32_to_gm = false;
+ _nativeMT32 = false;
+
+ _driver = createMidiDriverSimon1AdLib("MT_FM.IBK");
+ if (_driver && _driver->open() == 0) {
+ _driver->setTimerCallback(this, &onTimer);
+ // Like the original, we enable the rhythm support by default.
+ _driver->send(0xB0, 0x67, 0x01);
+ return 0;
+ }
+
+ delete _driver;
+ _driver = nullptr;
+ }
+
+ _musicMode = kMusicModeDisabled;
+ }
+
+ default:
+ break;
+ }
+
+ dev = MidiDriver::detectDevice(MDT_ADLIB | MDT_MIDI | (gameType == GType_SIMON1 ? MDT_PREFER_MT32 : MDT_PREFER_GM));
+ _adLibMusic = (MidiDriver::getMusicType(dev) == MT_ADLIB);
_nativeMT32 = ((MidiDriver::getMusicType(dev) == MT_MT32) || ConfMan.getBool("native_mt32"));
_driver = MidiDriver::createMidi(dev);
@@ -88,15 +268,9 @@ int MidiPlayer::open(int gameType) {
if (_nativeMT32)
_driver->property(MidiDriver::PROP_CHANNEL_MASK, 0x03FE);
- /* Disabled due to not sounding right, and low volume level
- if (gameType == GType_SIMON1 && MidiDriver::getMusicType(dev) == MT_ADLIB) {
- loadAdlibPatches();
- }
- */
-
_map_mt32_to_gm = (gameType != GType_SIMON2 && !_nativeMT32);
- int ret = _driver->open();
+ ret = _driver->open();
if (ret)
return ret;
_driver->setTimerCallback(this, &onTimer);
@@ -113,6 +287,33 @@ void MidiPlayer::send(uint32 b) {
if (!_current)
return;
+ if (_musicMode != kMusicModeDisabled) {
+ // Handle volume control for Simon1 output.
+ if (_musicMode == kMusicModeSimon1) {
+ // The driver does not support any volume control, thus we simply
+ // scale the velocities on note on for now.
+ // TODO: We should probably handle this at output level at some
+ // point. Then we can allow volume changes to affect already
+ // playing notes too. For now this simple change allows us to
+ // have some simple volume control though.
+ if ((b & 0xF0) == 0x90) {
+ byte volume = (b >> 16) & 0x7F;
+
+ if (_current == &_sfx) {
+ volume = volume * _sfxVolume / 255;
+ } else if (_current == &_music) {
+ volume = volume * _musicVolume / 255;
+ }
+
+ b = (b & 0xFF00FFFF) | (volume << 16);
+ }
+ }
+
+ // Send directly to Accolade/Miles/Simon1 Audio driver
+ _driver->send(b);
+ return;
+ }
+
byte channel = (byte)(b & 0x0F);
if ((b & 0xFFF0) == 0x07B0) {
// Adjust volume changes by master music and master sfx volume.
@@ -123,10 +324,8 @@ void MidiPlayer::send(uint32 b) {
else if (_current == &_music)
volume = volume * _musicVolume / 255;
b = (b & 0xFF00FFFF) | (volume << 16);
- } else if ((b & 0xF0) == 0xC0) {
- if (_map_mt32_to_gm && !_adlibPatches) {
- b = (b & 0xFFFF00FF) | (MidiDriver::_mt32ToGm[(b >> 8) & 0xFF] << 8);
- }
+ } else if ((b & 0xF0) == 0xC0 && _map_mt32_to_gm) {
+ b = (b & 0xFFFF00FF) | (MidiDriver::_mt32ToGm[(b >> 8) & 0xFF] << 8);
} else if ((b & 0xFFF0) == 0x007BB0) {
// Only respond to an All Notes Off if this channel
// has already been allocated.
@@ -146,8 +345,10 @@ void MidiPlayer::send(uint32 b) {
_current->volume[channel] = 127;
}
+ // Allocate channels if needed
if (!_current->channel[channel])
_current->channel[channel] = (channel == 9) ? _driver->getPercussionChannel() : _driver->allocateChannel();
+
if (_current->channel[channel]) {
if (channel == 9) {
if (_current == &_sfx)
@@ -155,16 +356,7 @@ void MidiPlayer::send(uint32 b) {
else if (_current == &_music)
_current->channel[9]->volume(_current->volume[9] * _musicVolume / 255);
}
-
- if ((b & 0xF0) == 0xC0 && _adlibPatches) {
- // NOTE: In the percussion channel, this function is a
- // no-op. Any percussion instruments you hear may
- // be the stock ones from adlib.cpp.
- _driver->sysEx_customInstrument(_current->channel[channel]->getNumber(), 'ADL ', _adlibPatches + 30 * ((b >> 8) & 0xFF));
- } else {
- _current->channel[channel]->send(b);
- }
-
+ _current->channel[channel]->send(b);
if ((b & 0xFFF0) == 0x79B0) {
// We have received a "Reset All Controllers" message
// and passed it on to the MIDI driver. This may or may
@@ -186,13 +378,13 @@ void MidiPlayer::metaEvent(byte type, byte *data, uint16 length) {
return;
} else if (_current == &_sfx) {
clearConstructs(_sfx);
- } else if (_current->loopTrack) {
+ } else if (_loopTrack) {
_current->parser->jumpToTick(0);
} else if (_queuedTrack != 255) {
_currentTrack = 255;
byte destination = _queuedTrack;
_queuedTrack = 255;
- _current->loopTrack = _loopQueuedTrack;
+ _loopTrack = _loopQueuedTrack;
_loopQueuedTrack = false;
// Remember, we're still inside the locked mutex.
@@ -320,7 +512,7 @@ void MidiPlayer::setVolume(int musicVol, int sfxVol) {
void MidiPlayer::setLoop(bool loop) {
Common::StackLock lock(_mutex);
- _loopTrackDefault = loop;
+ _loopTrack = loop;
}
void MidiPlayer::queueTrack(int track, bool loop) {
@@ -375,47 +567,6 @@ void MidiPlayer::resetVolumeTable() {
}
}
-void MidiPlayer::loadAdlibPatches() {
- Common::File ibk;
-
- if (!ibk.open("mt_fm.ibk"))
- return;
-
- if (ibk.readUint32BE() == 0x49424b1a) {
- _adlibPatches = new byte[128 * 30];
- byte *ptr = _adlibPatches;
-
- memset(_adlibPatches, 0, 128 * 30);
-
- for (int i = 0; i < 128; i++) {
- byte instr[16];
-
- ibk.read(instr, 16);
-
- ptr[0] = instr[0]; // Modulator Sound Characteristics
- ptr[1] = instr[2]; // Modulator Scaling/Output Level
- ptr[2] = ~instr[4]; // Modulator Attack/Decay
- ptr[3] = ~instr[6]; // Modulator Sustain/Release
- ptr[4] = instr[8]; // Modulator Wave Select
- ptr[5] = instr[1]; // Carrier Sound Characteristics
- ptr[6] = instr[3]; // Carrier Scaling/Output Level
- ptr[7] = ~instr[5]; // Carrier Attack/Delay
- ptr[8] = ~instr[7]; // Carrier Sustain/Release
- ptr[9] = instr[9]; // Carrier Wave Select
- ptr[10] = instr[10]; // Feedback/Connection
-
- // The remaining six bytes are reserved for future use
-
- ptr += 30;
- }
- }
-}
-
-void MidiPlayer::unloadAdlibPatches() {
- delete[] _adlibPatches;
- _adlibPatches = NULL;
-}
-
static const int simon1_gmf_size[] = {
8900, 12166, 2848, 3442, 4034, 4508, 7064, 9730, 6014, 4742, 3138,
6570, 5384, 8909, 6457, 16321, 2742, 8968, 4804, 8442, 7717,
@@ -472,24 +623,27 @@ void MidiPlayer::loadSMF(Common::File *in, int song, bool sfx) {
// 1 BYTE : Major version
// 1 BYTE : Minor version
// 1 BYTE : Ticks (Ranges from 2 - 8, always 2 for SFX)
- // 1 BYTE : Loop control. 0 = no loop, 1 = loop
-
- // In the original, the ticks value indicated how many
- // times the music timer was called before it actually
- // did something. The larger the value the slower the
- // music.
- //
- // We, on the other hand, have a timer rate which is
- // used to control by how much the music advances on
- // each onTimer() call. The larger the value, the
- // faster the music.
- //
- // It seems that 4 corresponds to our base tempo, so
- // this should be the right way to calculate it.
- timerRate = (4 * _driver->getBaseTempo()) / p->data[5];
- p->loopTrack = (p->data[6] != 0);
- } else {
- p->loopTrack = _loopTrackDefault;
+ // 1 BYTE : Loop control. 0 = no loop, 1 = loop (Music only)
+ if (!sfx) {
+ // In the original, the ticks value indicated how many
+ // times the music timer was called before it actually
+ // did something. The larger the value the slower the
+ // music.
+ //
+ // We, on the other hand, have a timer rate which is
+ // used to control by how much the music advances on
+ // each onTimer() call. The larger the value, the
+ // faster the music.
+ //
+ // It seems that 4 corresponds to our base tempo, so
+ // this should be the right way to calculate it.
+ timerRate = (4 * _driver->getBaseTempo()) / p->data[5];
+
+ // According to bug #1004919 calling setLoop() from
+ // within a lock causes a lockup, though I have no
+ // idea when this actually happens.
+ _loopTrack = (p->data[6] != 0);
+ }
}
MidiParser *parser = MidiParser::createParser_SMF();
@@ -559,8 +713,6 @@ void MidiPlayer::loadMultipleSMF(Common::File *in, bool sfx) {
p->song_sizes[i] = size;
}
- p->loopTrack = _loopTrackDefault;
-
if (!sfx) {
_currentTrack = 255;
resetVolumeTable();
@@ -592,7 +744,6 @@ void MidiPlayer::loadXMIDI(Common::File *in, bool sfx) {
in->seek(pos, 0);
p->data = (byte *)calloc(size, 1);
in->read(p->data, size);
- p->loopTrack = _loopTrackDefault;
} else {
error("Expected 'FORM' tag but found '%c%c%c%c' instead", buf[0], buf[1], buf[2], buf[3]);
}
@@ -637,8 +788,105 @@ void MidiPlayer::loadS1D(Common::File *in, bool sfx) {
_currentTrack = 255;
resetVolumeTable();
}
- p->loopTrack = _loopTrackDefault;
p->parser = parser; // That plugs the power cord into the wall
}
+#define MIDI_SETUP_BUNDLE_HEADER_SIZE 56
+#define MIDI_SETUP_BUNDLE_FILEHEADER_SIZE 48
+#define MIDI_SETUP_BUNDLE_FILENAME_MAX_SIZE 12
+
+// PKWARE data compression library (called "DCL" in ScummVM) was used for storing files within SETUP.SHR
+// we need it to be able to get the file MIDPAK.AD, otherwise we would have to require the user
+// to "install" the game before being able to actually play it, when using AdLib.
+//
+// SETUP.SHR file format:
+// [bundle file header]
+// [compressed file header] [compressed file data]
+// * compressed file count
+Common::SeekableReadStream *MidiPlayer::simon2SetupExtractFile(const Common::String &requestedFileName) {
+ Common::File *setupBundleStream = new Common::File();
+ uint32 bundleSize = 0;
+ uint32 bundleBytesLeft = 0;
+ byte bundleHeader[MIDI_SETUP_BUNDLE_HEADER_SIZE];
+ byte bundleFileHeader[MIDI_SETUP_BUNDLE_FILEHEADER_SIZE];
+ uint16 bundleFileCount = 0;
+ uint16 bundleFileNr = 0;
+
+ Common::String fileName;
+ uint32 fileCompressedSize = 0;
+ byte *fileCompressedDataPtr = nullptr;
+
+ Common::SeekableReadStream *extractedStream = nullptr;
+
+ if (!setupBundleStream->open("setup.shr"))
+ error("MidiPlayer: could not open setup.shr");
+
+ bundleSize = setupBundleStream->size();
+ bundleBytesLeft = bundleSize;
+
+ if (bundleSize < MIDI_SETUP_BUNDLE_HEADER_SIZE)
+ error("MidiPlayer: unexpected EOF in setup.shr");
+
+ if (setupBundleStream->read(bundleHeader, MIDI_SETUP_BUNDLE_HEADER_SIZE) != MIDI_SETUP_BUNDLE_HEADER_SIZE)
+ error("MidiPlayer: setup.shr read error");
+ bundleBytesLeft -= MIDI_SETUP_BUNDLE_HEADER_SIZE;
+
+ // Verify header byte
+ if (bundleHeader[13] != 't')
+ error("MidiPlayer: setup.shr bundle header data mismatch");
+
+ bundleFileCount = READ_LE_UINT16(&bundleHeader[14]);
+
+ // Search for requested file
+ while (bundleFileNr < bundleFileCount) {
+ if (bundleBytesLeft < sizeof(bundleFileHeader))
+ error("MidiPlayer: unexpected EOF in setup.shr");
+
+ if (setupBundleStream->read(bundleFileHeader, sizeof(bundleFileHeader)) != sizeof(bundleFileHeader))
+ error("MidiPlayer: setup.shr read error");
+ bundleBytesLeft -= MIDI_SETUP_BUNDLE_FILEHEADER_SIZE;
+
+ // Extract filename from file-header
+ fileName.clear();
+ for (byte curPos = 0; curPos < MIDI_SETUP_BUNDLE_FILENAME_MAX_SIZE; curPos++) {
+ if (!bundleFileHeader[curPos]) // terminating NUL
+ break;
+ fileName.insertChar(bundleFileHeader[curPos], curPos);
+ }
+
+ // Get compressed
+ fileCompressedSize = READ_LE_UINT32(&bundleFileHeader[20]);
+ if (!fileCompressedSize)
+ error("MidiPlayer: compressed file is 0 bytes, data corruption?");
+ if (bundleBytesLeft < fileCompressedSize)
+ error("MidiPlayer: unexpected EOF in setup.shr");
+
+ if (fileName == requestedFileName) {
+ // requested file found
+ fileCompressedDataPtr = new byte[fileCompressedSize];
+
+ if (setupBundleStream->read(fileCompressedDataPtr, fileCompressedSize) != fileCompressedSize)
+ error("MidiPlayer: setup.shr read error");
+
+ Common::MemoryReadStream *compressedStream = nullptr;
+
+ compressedStream = new Common::MemoryReadStream(fileCompressedDataPtr, fileCompressedSize);
+ // we don't know the unpacked size, let decompressor figure it out
+ extractedStream = Common::decompressDCL(compressedStream);
+ delete compressedStream;
+ break;
+ }
+
+ // skip compressed size
+ setupBundleStream->skip(fileCompressedSize);
+ bundleBytesLeft -= fileCompressedSize;
+
+ bundleFileNr++;
+ }
+ setupBundleStream->close();
+ delete setupBundleStream;
+
+ return extractedStream;
+}
+
} // End of namespace AGOS
diff --git a/engines/agos/midi.h b/engines/agos/midi.h
index 7e78bfef28..fb987fddcf 100644
--- a/engines/agos/midi.h
+++ b/engines/agos/midi.h
@@ -33,10 +33,16 @@ class File;
namespace AGOS {
+enum kMusicMode {
+ kMusicModeDisabled = 0,
+ kMusicModeAccolade = 1,
+ kMusicModeMilesAudio = 2,
+ kMusicModeSimon1 = 3
+};
+
struct MusicInfo {
MidiParser *parser;
byte *data;
- bool loopTrack;
byte num_songs; // For Type 1 SMF resources
byte *songs[16]; // For Type 1 SMF resources
uint32 song_sizes[16]; // For Type 1 SMF resources
@@ -47,7 +53,6 @@ struct MusicInfo {
MusicInfo() { clear(); }
void clear() {
parser = 0; data = 0; num_songs = 0;
- loopTrack = false;
memset(songs, 0, sizeof(songs));
memset(song_sizes, 0, sizeof(song_sizes));
memset(channel, 0, sizeof(channel));
@@ -73,21 +78,18 @@ protected:
// These are only used for music.
byte _currentTrack;
- bool _loopTrackDefault;
+ bool _loopTrack;
byte _queuedTrack;
bool _loopQueuedTrack;
- byte *_adlibPatches;
-
protected:
static void onTimer(void *data);
void clearConstructs();
void clearConstructs(MusicInfo &info);
void resetVolumeTable();
- void loadAdlibPatches();
- void unloadAdlibPatches();
public:
+ bool _adLibMusic;
bool _enable_sfx;
public:
@@ -113,12 +115,17 @@ public:
void setVolume(int musicVol, int sfxVol);
public:
- int open(int gameType);
+ int open(int gameType, bool isDemo);
// MidiDriver_BASE interface implementation
virtual void send(uint32 b);
virtual void metaEvent(byte type, byte *data, uint16 length);
+private:
+ kMusicMode _musicMode;
+
+private:
+ Common::SeekableReadStream *simon2SetupExtractFile(const Common::String &requestedFileName);
};
} // End of namespace AGOS
diff --git a/engines/agos/midiparser_s1d.cpp b/engines/agos/midiparser_s1d.cpp
index c2c08bf451..7b9a058efc 100644
--- a/engines/agos/midiparser_s1d.cpp
+++ b/engines/agos/midiparser_s1d.cpp
@@ -179,12 +179,43 @@ void MidiParser_S1D::parseNextEvent(EventInfo &info) {
bool MidiParser_S1D::loadMusic(byte *data, uint32 size) {
unloadMusic();
+ if (!size)
+ return false;
+
// The original actually just ignores the first two bytes.
byte *pos = data;
- if (*(pos++) != 0xFC)
- debug(1, "Expected 0xFC header but found 0x%02X instead", (int) *pos);
-
- pos += 1;
+ if (*pos == 0xFC) {
+ // SysEx found right at the start
+ // this seems to happen since Elvira 2, we ignore it
+ // 3rd byte after the SysEx seems to be saved into a global
+
+ // We expect at least 4 bytes in total
+ if (size < 4)
+ return false;
+
+ byte skipOffset = pos[2]; // get second byte after the SysEx
+ // pos[1] seems to have been ignored
+ // pos[3] is saved into a global inside the original interpreters
+
+ // Waxworks + Simon 1 demo typical header is:
+ // 0xFC 0x29 0x07 0x01 [0x00/0x01]
+ // Elvira 2 typical header is:
+ // 0xFC 0x04 0x06 0x06
+
+ if (skipOffset >= 6) {
+ // should be at least 6, so that we skip over the 2 size bytes and the
+ // smallest SysEx possible
+ skipOffset -= 2; // 2 size bytes were already read by previous code outside of this method
+
+ if (size <= skipOffset) // Skip to the end of file? -> something is not correct
+ return false;
+
+ // Do skip over the bytes
+ pos += skipOffset;
+ } else {
+ warning("MidiParser_S1D: unexpected skip offset in music file");
+ }
+ }
// And now we're at the actual data. Only one track.
_numTracks = 1;
diff --git a/engines/agos/module.mk b/engines/agos/module.mk
index 7069d8005b..e7b773d76f 100644
--- a/engines/agos/module.mk
+++ b/engines/agos/module.mk
@@ -1,6 +1,10 @@
MODULE := engines/agos
MODULE_OBJS := \
+ drivers/accolade/adlib.o \
+ drivers/accolade/driverfile.o \
+ drivers/accolade/mt32.o \
+ drivers/simon1/adlib.o \
agos.o \
charset.o \
charset-fontdata.o \
diff --git a/engines/agos/res_snd.cpp b/engines/agos/res_snd.cpp
index 5d6ab60c8b..d04f1735d6 100644
--- a/engines/agos/res_snd.cpp
+++ b/engines/agos/res_snd.cpp
@@ -220,6 +220,7 @@ void AGOSEngine::playModule(uint16 music) {
}
_mixer->playStream(Audio::Mixer::kMusicSoundType, &_modHandle, audioStream);
+ _mixer->pauseHandle(_modHandle, _musicPaused);
}
void AGOSEngine_Simon1::playMusic(uint16 music, uint16 track) {
@@ -309,7 +310,9 @@ void AGOSEngine::stopMusic() {
}
void AGOSEngine::playSting(uint16 soundId) {
- if (!_midi->_enable_sfx)
+ // The sound effects in floppy disk version of
+ // Simon the Sorcerer 1 are only meant for AdLib
+ if (!_midi->_adLibMusic || !_midi->_enable_sfx)
return;
char filename[15];
diff --git a/engines/agos/sound.cpp b/engines/agos/sound.cpp
index 812f46504f..762f60bd91 100644
--- a/engines/agos/sound.cpp
+++ b/engines/agos/sound.cpp
@@ -515,7 +515,7 @@ void Sound::readSfxFile(const Common::String &filename) {
// This method is only used by Simon2
void Sound::loadSfxTable(const char *gameFilename, uint32 base) {
- stopAll();
+ stopAllSfx();
delete _effects;
const bool dataIsUnsigned = true;
@@ -684,7 +684,7 @@ void Sound::playRawData(byte *soundData, uint sound, uint size, uint freq) {
memcpy(buffer, soundData, size);
byte flags = 0;
- if (_vm->getPlatform() == Common::kPlatformDOS)
+ if (_vm->getPlatform() == Common::kPlatformDOS && _vm->getGameId() != GID_ELVIRA2)
flags = Audio::FLAG_UNSIGNED;
Audio::AudioStream *stream = Audio::makeRawStream(buffer, size, freq, flags);
diff --git a/engines/agos/zones.cpp b/engines/agos/zones.cpp
index 1644213579..5a753d9b4b 100644
--- a/engines/agos/zones.cpp
+++ b/engines/agos/zones.cpp
@@ -94,8 +94,7 @@ void AGOSEngine::loadZone(uint16 zoneNum, bool useError) {
vpe->sfxFile = NULL;
- if ((getPlatform() == Common::kPlatformAmiga || getPlatform() == Common::kPlatformAtariST) &&
- getGameType() == GType_ELVIRA2) {
+ if (getGameType() == GType_ELVIRA2) {
// A singe sound file is used for Amiga and AtariST versions
if (loadVGASoundFile(1, 3)) {
vpe->sfxFile = _block;
diff --git a/engines/bbvs/sound.h b/engines/bbvs/sound.h
index 4e44c2b962..4d3253c48e 100644
--- a/engines/bbvs/sound.h
+++ b/engines/bbvs/sound.h
@@ -38,7 +38,7 @@ public:
void stop();
bool isPlaying();
protected:
- Audio::SeekableAudioStream *_stream;
+ Audio::RewindableAudioStream *_stream;
Audio::SoundHandle _handle;
// Keep the filename for debugging purposes
Common::String _filename;
diff --git a/engines/cine/sound.cpp b/engines/cine/sound.cpp
index 069a4787ac..0c788b816c 100644
--- a/engines/cine/sound.cpp
+++ b/engines/cine/sound.cpp
@@ -101,7 +101,7 @@ struct AdLibSoundInstrument {
byte amDepth;
};
-class AdLibSoundDriver : public PCSoundDriver, Audio::AudioStream {
+class AdLibSoundDriver : public PCSoundDriver {
public:
AdLibSoundDriver(Audio::Mixer *mixer);
virtual ~AdLibSoundDriver();
@@ -112,14 +112,8 @@ public:
virtual void stopChannel(int channel);
virtual void stopAll();
- // AudioStream interface
- virtual int readBuffer(int16 *buffer, const int numSamples);
- virtual bool isStereo() const { return false; }
- virtual bool endOfData() const { return false; }
- virtual int getRate() const { return _sampleRate; }
-
void initCard();
- void update(int16 *buf, int len);
+ void onTimer();
void setupInstrument(const byte *data, int channel);
void loadRegisterInstrument(const byte *data, AdLibRegisterSoundInstrument *reg);
virtual void loadInstrument(const byte *data, AdLibSoundInstrument *asi) = 0;
@@ -128,10 +122,8 @@ protected:
UpdateCallback _upCb;
void *_upRef;
- FM_OPL *_opl;
- int _sampleRate;
+ OPL::OPL *_opl;
Audio::Mixer *_mixer;
- Audio::SoundHandle _soundHandle;
byte _vibrato;
int _channelsVolumeTable[4];
@@ -282,17 +274,19 @@ void PCSoundDriver::resetChannel(int channel) {
AdLibSoundDriver::AdLibSoundDriver(Audio::Mixer *mixer)
: _upCb(0), _upRef(0), _mixer(mixer) {
- _sampleRate = _mixer->getOutputRate();
- _opl = makeAdLibOPL(_sampleRate);
+
+ _opl = OPL::Config::create();
+ if (!_opl || !_opl->init())
+ error("Failed to create OPL");
+
memset(_channelsVolumeTable, 0, sizeof(_channelsVolumeTable));
memset(_instrumentsTable, 0, sizeof(_instrumentsTable));
initCard();
- _mixer->playStream(Audio::Mixer::kPlainSoundType, &_soundHandle, this, -1, Audio::Mixer::kMaxChannelVolume, 0, DisposeAfterUse::NO, true);
+ _opl->start(new Common::Functor0Mem<void, AdLibSoundDriver>(this, &AdLibSoundDriver::onTimer), 50);
}
AdLibSoundDriver::~AdLibSoundDriver() {
- _mixer->stopHandle(_soundHandle);
- OPLDestroy(_opl);
+ delete _opl;
}
void AdLibSoundDriver::setUpdateCallback(UpdateCallback upCb, void *ref) {
@@ -322,71 +316,52 @@ void AdLibSoundDriver::stopChannel(int channel) {
channel = 6;
}
if (ins->mode == 0 || channel == 6) {
- OPLWriteReg(_opl, 0xB0 | channel, 0);
+ _opl->writeReg(0xB0 | channel, 0);
}
if (ins->mode != 0) {
_vibrato &= ~(1 << (10 - ins->channel));
- OPLWriteReg(_opl, 0xBD, _vibrato);
+ _opl->writeReg(0xBD, _vibrato);
}
}
void AdLibSoundDriver::stopAll() {
int i;
for (i = 0; i < 18; ++i) {
- OPLWriteReg(_opl, 0x40 | _operatorsTable[i], 63);
+ _opl->writeReg(0x40 | _operatorsTable[i], 63);
}
for (i = 0; i < 9; ++i) {
- OPLWriteReg(_opl, 0xB0 | i, 0);
+ _opl->writeReg(0xB0 | i, 0);
}
- OPLWriteReg(_opl, 0xBD, 0);
-}
-
-int AdLibSoundDriver::readBuffer(int16 *buffer, const int numSamples) {
- update(buffer, numSamples);
- return numSamples;
+ _opl->writeReg(0xBD, 0);
}
void AdLibSoundDriver::initCard() {
_vibrato = 0x20;
- OPLWriteReg(_opl, 0xBD, _vibrato);
- OPLWriteReg(_opl, 0x08, 0x40);
+ _opl->writeReg(0xBD, _vibrato);
+ _opl->writeReg(0x08, 0x40);
static const int oplRegs[] = { 0x40, 0x60, 0x80, 0x20, 0xE0 };
for (int i = 0; i < 9; ++i) {
- OPLWriteReg(_opl, 0xB0 | i, 0);
+ _opl->writeReg(0xB0 | i, 0);
}
for (int i = 0; i < 9; ++i) {
- OPLWriteReg(_opl, 0xC0 | i, 0);
+ _opl->writeReg(0xC0 | i, 0);
}
for (int j = 0; j < 5; j++) {
for (int i = 0; i < 18; ++i) {
- OPLWriteReg(_opl, oplRegs[j] | _operatorsTable[i], 0);
+ _opl->writeReg(oplRegs[j] | _operatorsTable[i], 0);
}
}
- OPLWriteReg(_opl, 1, 0x20);
- OPLWriteReg(_opl, 1, 0);
+ _opl->writeReg(1, 0x20);
+ _opl->writeReg(1, 0);
}
-void AdLibSoundDriver::update(int16 *buf, int len) {
- static int samplesLeft = 0;
- while (len != 0) {
- int count = samplesLeft;
- if (count > len) {
- count = len;
- }
- samplesLeft -= count;
- len -= count;
- YM3812UpdateOne(_opl, buf, count);
- if (samplesLeft == 0) {
- if (_upCb) {
- (*_upCb)(_upRef);
- }
- samplesLeft = _sampleRate / 50;
- }
- buf += count;
+void AdLibSoundDriver::onTimer() {
+ if (_upCb) {
+ (*_upCb)(_upRef);
}
}
@@ -408,32 +383,32 @@ void AdLibSoundDriver::setupInstrument(const byte *data, int channel) {
if (ins->mode == 0 || ins->channel == 6) {
reg = &ins->regMod;
- OPLWriteReg(_opl, 0x20 | mod, reg->vibrato);
+ _opl->writeReg(0x20 | mod, reg->vibrato);
if (reg->freqMod) {
tmp = reg->outputLevel & 0x3F;
} else {
tmp = (63 - (reg->outputLevel & 0x3F)) * _channelsVolumeTable[channel];
tmp = 63 - (2 * tmp + 127) / (2 * 127);
}
- OPLWriteReg(_opl, 0x40 | mod, tmp | (reg->keyScaling << 6));
- OPLWriteReg(_opl, 0x60 | mod, reg->attackDecay);
- OPLWriteReg(_opl, 0x80 | mod, reg->sustainRelease);
+ _opl->writeReg(0x40 | mod, tmp | (reg->keyScaling << 6));
+ _opl->writeReg(0x60 | mod, reg->attackDecay);
+ _opl->writeReg(0x80 | mod, reg->sustainRelease);
if (ins->mode != 0) {
- OPLWriteReg(_opl, 0xC0 | ins->channel, reg->feedbackStrength);
+ _opl->writeReg(0xC0 | ins->channel, reg->feedbackStrength);
} else {
- OPLWriteReg(_opl, 0xC0 | channel, reg->feedbackStrength);
+ _opl->writeReg(0xC0 | channel, reg->feedbackStrength);
}
- OPLWriteReg(_opl, 0xE0 | mod, ins->waveSelectMod);
+ _opl->writeReg(0xE0 | mod, ins->waveSelectMod);
}
reg = &ins->regCar;
- OPLWriteReg(_opl, 0x20 | car, reg->vibrato);
+ _opl->writeReg(0x20 | car, reg->vibrato);
tmp = (63 - (reg->outputLevel & 0x3F)) * _channelsVolumeTable[channel];
tmp = 63 - (2 * tmp + 127) / (2 * 127);
- OPLWriteReg(_opl, 0x40 | car, tmp | (reg->keyScaling << 6));
- OPLWriteReg(_opl, 0x60 | car, reg->attackDecay);
- OPLWriteReg(_opl, 0x80 | car, reg->sustainRelease);
- OPLWriteReg(_opl, 0xE0 | car, ins->waveSelectCar);
+ _opl->writeReg(0x40 | car, tmp | (reg->keyScaling << 6));
+ _opl->writeReg(0x60 | car, reg->attackDecay);
+ _opl->writeReg(0x80 | car, reg->sustainRelease);
+ _opl->writeReg(0xE0 | car, ins->waveSelectCar);
}
void AdLibSoundDriver::loadRegisterInstrument(const byte *data, AdLibRegisterSoundInstrument *reg) {
@@ -490,16 +465,16 @@ void AdLibSoundDriverINS::setChannelFrequency(int channel, int frequency) {
if (channel == 6)
oct = 0;
freq = _freqTable[note % 12];
- OPLWriteReg(_opl, 0xA0 | channel, freq);
+ _opl->writeReg(0xA0 | channel, freq);
freq = (oct << 2) | ((freq & 0x300) >> 8);
if (ins->mode == 0) {
freq |= 0x20;
}
- OPLWriteReg(_opl, 0xB0 | channel, freq);
+ _opl->writeReg(0xB0 | channel, freq);
}
if (ins->mode != 0) {
_vibrato |= 1 << (10 - ins->channel);
- OPLWriteReg(_opl, 0xBD, _vibrato);
+ _opl->writeReg(0xBD, _vibrato);
}
}
@@ -515,16 +490,16 @@ void AdLibSoundDriverINS::playSample(const byte *data, int size, int channel, in
if (ins->mode == 0 || channel == 6) {
uint16 note = 12;
int freq = _freqTable[note % 12];
- OPLWriteReg(_opl, 0xA0 | channel, freq);
+ _opl->writeReg(0xA0 | channel, freq);
freq = ((note / 12) << 2) | ((freq & 0x300) >> 8);
if (ins->mode == 0) {
freq |= 0x20;
}
- OPLWriteReg(_opl, 0xB0 | channel, freq);
+ _opl->writeReg(0xB0 | channel, freq);
}
if (ins->mode != 0) {
_vibrato |= 1 << (10 - ins->channel);
- OPLWriteReg(_opl, 0xBD, _vibrato);
+ _opl->writeReg(0xBD, _vibrato);
}
}
@@ -562,15 +537,15 @@ void AdLibSoundDriverADL::setChannelFrequency(int channel, int frequency) {
}
freq = _freqTable[note % 12];
- OPLWriteReg(_opl, 0xA0 | channel, freq);
+ _opl->writeReg(0xA0 | channel, freq);
freq = (oct << 2) | ((freq & 0x300) >> 8);
if (ins->mode == 0) {
freq |= 0x20;
}
- OPLWriteReg(_opl, 0xB0 | channel, freq);
+ _opl->writeReg(0xB0 | channel, freq);
if (ins->mode != 0) {
_vibrato |= 1 << (10 - channel);
- OPLWriteReg(_opl, 0xBD, _vibrato);
+ _opl->writeReg(0xBD, _vibrato);
}
}
@@ -580,11 +555,11 @@ void AdLibSoundDriverADL::playSample(const byte *data, int size, int channel, in
setupInstrument(data, channel);
AdLibSoundInstrument *ins = &_instrumentsTable[channel];
if (ins->mode != 0 && ins->channel == 6) {
- OPLWriteReg(_opl, 0xB0 | channel, 0);
+ _opl->writeReg(0xB0 | channel, 0);
}
if (ins->mode != 0) {
_vibrato &= ~(1 << (10 - ins->channel));
- OPLWriteReg(_opl, 0xBD, _vibrato);
+ _opl->writeReg(0xBD, _vibrato);
}
if (ins->mode != 0) {
channel = ins->channel;
@@ -599,15 +574,15 @@ void AdLibSoundDriverADL::playSample(const byte *data, int size, int channel, in
note = ins->amDepth;
}
int freq = _freqTable[note % 12];
- OPLWriteReg(_opl, 0xA0 | channel, freq);
+ _opl->writeReg(0xA0 | channel, freq);
freq = ((note / 12) << 2) | ((freq & 0x300) >> 8);
if (ins->mode == 0) {
freq |= 0x20;
}
- OPLWriteReg(_opl, 0xB0 | channel, freq);
+ _opl->writeReg(0xB0 | channel, freq);
if (ins->mode != 0) {
_vibrato |= 1 << (10 - channel);
- OPLWriteReg(_opl, 0xBD, _vibrato);
+ _opl->writeReg(0xBD, _vibrato);
}
}
diff --git a/engines/cruise/sound.cpp b/engines/cruise/sound.cpp
index 0b0fab8c4a..f57435f4f7 100644
--- a/engines/cruise/sound.cpp
+++ b/engines/cruise/sound.cpp
@@ -108,7 +108,7 @@ struct VolumeEntry {
int adjusted;
};
-class AdLibSoundDriver : public PCSoundDriver, Audio::AudioStream {
+class AdLibSoundDriver : public PCSoundDriver {
public:
AdLibSoundDriver(Audio::Mixer *mixer);
virtual ~AdLibSoundDriver();
@@ -118,14 +118,8 @@ public:
virtual void stopChannel(int channel);
virtual void stopAll();
- // AudioStream interface
- virtual int readBuffer(int16 *buffer, const int numSamples);
- virtual bool isStereo() const { return false; }
- virtual bool endOfData() const { return false; }
- virtual int getRate() const { return _sampleRate; }
-
void initCard();
- void update(int16 *buf, int len);
+ void onTimer();
void setupInstrument(const byte *data, int channel);
void setupInstrument(const AdLibSoundInstrument *ins, int channel);
void loadRegisterInstrument(const byte *data, AdLibRegisterSoundInstrument *reg);
@@ -135,10 +129,8 @@ public:
void adjustVolume(int channel, int volume);
protected:
- FM_OPL *_opl;
- int _sampleRate;
+ OPL::OPL *_opl;
Audio::Mixer *_mixer;
- Audio::SoundHandle _soundHandle;
byte _vibrato;
VolumeEntry _channelsVolumeTable[5];
@@ -302,8 +294,9 @@ void PCSoundDriver::syncSounds() {
AdLibSoundDriver::AdLibSoundDriver(Audio::Mixer *mixer)
: _mixer(mixer) {
- _sampleRate = _mixer->getOutputRate();
- _opl = makeAdLibOPL(_sampleRate);
+ _opl = OPL::Config::create();
+ if (!_opl || !_opl->init())
+ error("Failed to create OPL");
for (int i = 0; i < 5; ++i) {
_channelsVolumeTable[i].original = 0;
@@ -311,15 +304,15 @@ AdLibSoundDriver::AdLibSoundDriver(Audio::Mixer *mixer)
}
memset(_instrumentsTable, 0, sizeof(_instrumentsTable));
initCard();
- _mixer->playStream(Audio::Mixer::kPlainSoundType, &_soundHandle, this, -1, Audio::Mixer::kMaxChannelVolume, 0, DisposeAfterUse::NO, true);
_musicVolume = ConfMan.getBool("music_mute") ? 0 : MIN(255, ConfMan.getInt("music_volume"));
_sfxVolume = ConfMan.getBool("sfx_mute") ? 0 : MIN(255, ConfMan.getInt("sfx_volume"));
+
+ _opl->start(new Common::Functor0Mem<void, AdLibSoundDriver>(this, &AdLibSoundDriver::onTimer), 50);
}
AdLibSoundDriver::~AdLibSoundDriver() {
- _mixer->stopHandle(_soundHandle);
- OPLDestroy(_opl);
+ delete _opl;
}
void AdLibSoundDriver::syncSounds() {
@@ -368,70 +361,51 @@ void AdLibSoundDriver::stopChannel(int channel) {
channel = 6;
}
if (ins->mode == 0 || channel == 6) {
- OPLWriteReg(_opl, 0xB0 | channel, 0);
+ _opl->writeReg(0xB0 | channel, 0);
}
if (ins->mode != 0) {
_vibrato &= ~(1 << (10 - ins->channel));
- OPLWriteReg(_opl, 0xBD, _vibrato);
+ _opl->writeReg(0xBD, _vibrato);
}
}
void AdLibSoundDriver::stopAll() {
for (int i = 0; i < 18; ++i)
- OPLWriteReg(_opl, 0x40 | _operatorsTable[i], 63);
+ _opl->writeReg(0x40 | _operatorsTable[i], 63);
for (int i = 0; i < 9; ++i)
- OPLWriteReg(_opl, 0xB0 | i, 0);
-
- OPLWriteReg(_opl, 0xBD, 0);
-}
+ _opl->writeReg(0xB0 | i, 0);
-int AdLibSoundDriver::readBuffer(int16 *buffer, const int numSamples) {
- update(buffer, numSamples);
- return numSamples;
+ _opl->writeReg(0xBD, 0);
}
void AdLibSoundDriver::initCard() {
_vibrato = 0x20;
- OPLWriteReg(_opl, 0xBD, _vibrato);
- OPLWriteReg(_opl, 0x08, 0x40);
+ _opl->writeReg(0xBD, _vibrato);
+ _opl->writeReg(0x08, 0x40);
static const int oplRegs[] = { 0x40, 0x60, 0x80, 0x20, 0xE0 };
for (int i = 0; i < 9; ++i) {
- OPLWriteReg(_opl, 0xB0 | i, 0);
+ _opl->writeReg(0xB0 | i, 0);
}
for (int i = 0; i < 9; ++i) {
- OPLWriteReg(_opl, 0xC0 | i, 0);
+ _opl->writeReg(0xC0 | i, 0);
}
for (int j = 0; j < 5; j++) {
for (int i = 0; i < 18; ++i) {
- OPLWriteReg(_opl, oplRegs[j] | _operatorsTable[i], 0);
+ _opl->writeReg(oplRegs[j] | _operatorsTable[i], 0);
}
}
- OPLWriteReg(_opl, 1, 0x20);
- OPLWriteReg(_opl, 1, 0);
+ _opl->writeReg(1, 0x20);
+ _opl->writeReg(1, 0);
}
-void AdLibSoundDriver::update(int16 *buf, int len) {
- static int samplesLeft = 0;
- while (len != 0) {
- int count = samplesLeft;
- if (count > len) {
- count = len;
- }
- samplesLeft -= count;
- len -= count;
- YM3812UpdateOne(_opl, buf, count);
- if (samplesLeft == 0) {
- if (_upCb) {
- (*_upCb)(_upRef);
- }
- samplesLeft = _sampleRate / 50;
- }
- buf += count;
+void AdLibSoundDriver::onTimer() {
+ if (_upCb) {
+ (*_upCb)(_upRef);
}
}
@@ -457,32 +431,32 @@ void AdLibSoundDriver::setupInstrument(const AdLibSoundInstrument *ins, int chan
if (ins->mode == 0 || ins->channel == 6) {
reg = &ins->regMod;
- OPLWriteReg(_opl, 0x20 | mod, reg->vibrato);
+ _opl->writeReg(0x20 | mod, reg->vibrato);
if (reg->freqMod) {
tmp = reg->outputLevel & 0x3F;
} else {
tmp = (63 - (reg->outputLevel & 0x3F)) * _channelsVolumeTable[channel].adjusted;
tmp = 63 - (2 * tmp + 127) / (2 * 127);
}
- OPLWriteReg(_opl, 0x40 | mod, tmp | (reg->keyScaling << 6));
- OPLWriteReg(_opl, 0x60 | mod, reg->attackDecay);
- OPLWriteReg(_opl, 0x80 | mod, reg->sustainRelease);
+ _opl->writeReg(0x40 | mod, tmp | (reg->keyScaling << 6));
+ _opl->writeReg(0x60 | mod, reg->attackDecay);
+ _opl->writeReg(0x80 | mod, reg->sustainRelease);
if (ins->mode != 0) {
- OPLWriteReg(_opl, 0xC0 | ins->channel, reg->feedbackStrength);
+ _opl->writeReg(0xC0 | ins->channel, reg->feedbackStrength);
} else {
- OPLWriteReg(_opl, 0xC0 | channel, reg->feedbackStrength);
+ _opl->writeReg(0xC0 | channel, reg->feedbackStrength);
}
- OPLWriteReg(_opl, 0xE0 | mod, ins->waveSelectMod);
+ _opl->writeReg(0xE0 | mod, ins->waveSelectMod);
}
reg = &ins->regCar;
- OPLWriteReg(_opl, 0x20 | car, reg->vibrato);
+ _opl->writeReg(0x20 | car, reg->vibrato);
tmp = (63 - (reg->outputLevel & 0x3F)) * _channelsVolumeTable[channel].adjusted;
tmp = 63 - (2 * tmp + 127) / (2 * 127);
- OPLWriteReg(_opl, 0x40 | car, tmp | (reg->keyScaling << 6));
- OPLWriteReg(_opl, 0x60 | car, reg->attackDecay);
- OPLWriteReg(_opl, 0x80 | car, reg->sustainRelease);
- OPLWriteReg(_opl, 0xE0 | car, ins->waveSelectCar);
+ _opl->writeReg(0x40 | car, tmp | (reg->keyScaling << 6));
+ _opl->writeReg(0x60 | car, reg->attackDecay);
+ _opl->writeReg(0x80 | car, reg->sustainRelease);
+ _opl->writeReg(0xE0 | car, ins->waveSelectCar);
}
void AdLibSoundDriver::loadRegisterInstrument(const byte *data, AdLibRegisterSoundInstrument *reg) {
@@ -551,15 +525,15 @@ void AdLibSoundDriverADL::setChannelFrequency(int channel, int frequency) {
}
freq = _freqTable[note % 12];
- OPLWriteReg(_opl, 0xA0 | channel, freq);
+ _opl->writeReg(0xA0 | channel, freq);
freq = ((note / 12) << 2) | ((freq & 0x300) >> 8);
if (ins->mode == 0) {
freq |= 0x20;
}
- OPLWriteReg(_opl, 0xB0 | channel, freq);
+ _opl->writeReg(0xB0 | channel, freq);
if (ins->mode != 0) {
_vibrato |= 1 << (10 - channel);
- OPLWriteReg(_opl, 0xBD, _vibrato);
+ _opl->writeReg(0xBD, _vibrato);
}
}
@@ -570,11 +544,11 @@ void AdLibSoundDriverADL::playSample(const byte *data, int size, int channel, in
setupInstrument(data, channel);
AdLibSoundInstrument *ins = &_instrumentsTable[channel];
if (ins->mode != 0 && ins->channel == 6) {
- OPLWriteReg(_opl, 0xB0 | channel, 0);
+ _opl->writeReg(0xB0 | channel, 0);
}
if (ins->mode != 0) {
_vibrato &= ~(1 << (10 - ins->channel));
- OPLWriteReg(_opl, 0xBD, _vibrato);
+ _opl->writeReg(0xBD, _vibrato);
}
if (ins->mode != 0) {
channel = ins->channel;
@@ -589,15 +563,15 @@ void AdLibSoundDriverADL::playSample(const byte *data, int size, int channel, in
note = ins->amDepth;
}
int freq = _freqTable[note % 12];
- OPLWriteReg(_opl, 0xA0 | channel, freq);
+ _opl->writeReg(0xA0 | channel, freq);
freq = ((note / 12) << 2) | ((freq & 0x300) >> 8);
if (ins->mode == 0) {
freq |= 0x20;
}
- OPLWriteReg(_opl, 0xB0 | channel, freq);
+ _opl->writeReg(0xB0 | channel, freq);
if (ins->mode != 0) {
_vibrato |= 1 << (10 - channel);
- OPLWriteReg(_opl, 0xBD, _vibrato);
+ _opl->writeReg(0xBD, _vibrato);
}
}
diff --git a/engines/fullpipe/motion.cpp b/engines/fullpipe/motion.cpp
index 9573e0517b..5845ad1501 100644
--- a/engines/fullpipe/motion.cpp
+++ b/engines/fullpipe/motion.cpp
@@ -1232,7 +1232,7 @@ MessageQueue *MovGraph::method50(StaticANIObject *ani, MovArr *movarr, int stati
return 0;
uint idx;
- int movidx;
+ int movidx = 0;
bool done = false;
for (idx = 0; idx <= _items.size() && !done; idx++) {
diff --git a/engines/gob/gob.cpp b/engines/gob/gob.cpp
index 5ab3271a8f..24bdb858d8 100644
--- a/engines/gob/gob.cpp
+++ b/engines/gob/gob.cpp
@@ -389,6 +389,9 @@ void GobEngine::syncSoundSettings() {
Engine::syncSoundSettings();
_init->updateConfig();
+
+ if (_sound)
+ _sound->adlibSyncVolume();
}
void GobEngine::pauseGame() {
diff --git a/engines/gob/map_v2.cpp b/engines/gob/map_v2.cpp
index cb5abe9644..370e62c88f 100644
--- a/engines/gob/map_v2.cpp
+++ b/engines/gob/map_v2.cpp
@@ -163,11 +163,9 @@ void Map_v2::loadMapObjects(const char *avjFile) {
mapHeight = _screenHeight / _tilesHeight;
mapWidth = _screenWidth / _tilesWidth;
- for (int i = 0; i < mapHeight; i++) {
+ for (int i = 0; i < mapHeight; i++)
for (int j = 0; j < mapWidth; j++)
setPass(j, i, mapData.readSByte());
- _vm->_inter->_variables->getAddressOff8(var + i * _passWidth);
- }
}
mapData.seek(tmpPos);
diff --git a/engines/gob/sound/adlib.cpp b/engines/gob/sound/adlib.cpp
index 65b43cae7a..1e024d5a50 100644
--- a/engines/gob/sound/adlib.cpp
+++ b/engines/gob/sound/adlib.cpp
@@ -37,6 +37,28 @@ static const int kPitchTomToSnare = 7;
static const int kPitchSnareDrum = kPitchTom + kPitchTomToSnare;
+// Attenuation map for GUI volume slider
+// Note: no volume control in the original engine
+const uint8 AdLib::kVolumeTable[Audio::Mixer::kMaxMixerVolume + 1] = {
+ 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 62, 61, 59, 57, 56, 55,
+ 53, 52, 51, 50, 49, 48, 47, 46, 46, 45, 44, 43, 43, 42, 41, 41,
+ 40, 39, 39, 38, 38, 37, 37, 36, 36, 35, 35, 34, 34, 33, 33, 33,
+ 32, 32, 31, 31, 31, 30, 30, 30, 29, 29, 29, 28, 28, 28, 27, 27,
+ 27, 26, 26, 26, 26, 25, 25, 25, 24, 24, 24, 24, 23, 23, 23, 23,
+ 22, 22, 22, 22, 21, 21, 21, 21, 21, 20, 20, 20, 20, 19, 19, 19,
+ 19, 19, 18, 18, 18, 18, 18, 18, 17, 17, 17, 17, 17, 16, 16, 16,
+ 16, 16, 16, 15, 15, 15, 15, 15, 15, 14, 14, 14, 14, 14, 14, 13,
+ 13, 13, 13, 13, 13, 13, 12, 12, 12, 12, 12, 12, 12, 11, 11, 11,
+ 11, 11, 11, 11, 11, 10, 10, 10, 10, 10, 10, 10, 10, 9, 9, 9,
+ 9, 9, 9, 9, 9, 8, 8, 8, 8, 8, 8, 8, 8, 8, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+ 6, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,
+ 0
+};
+
// Is the operator a modulator (0) or a carrier (1)?
const uint8 AdLib::kOperatorType[kOperatorCount] = {
0, 0, 0, 1, 1, 1,
@@ -93,23 +115,20 @@ const uint16 AdLib::kHihatParams [kParamCount] = {
0, 1, 0, 15, 11, 0, 7, 5, 0, 0, 0, 0, 0, 0 };
-AdLib::AdLib(Audio::Mixer &mixer) : _mixer(&mixer), _opl(0),
- _toPoll(0), _repCount(0), _first(true), _playing(false), _ended(true) {
-
- _rate = _mixer->getOutputRate();
+AdLib::AdLib(int callbackFreq) : _opl(0),
+ _toPoll(0), _repCount(0), _first(true), _playing(false), _ended(true), _volume(0) {
initFreqs();
createOPL();
initOPL();
- _mixer->playStream(Audio::Mixer::kMusicSoundType, &_handle,
- this, -1, Audio::Mixer::kMaxChannelVolume, 0, DisposeAfterUse::NO, true);
+ syncVolume();
+
+ _opl->start(new Common::Functor0Mem<void, AdLib>(this, &AdLib::onTimer), callbackFreq);
}
AdLib::~AdLib() {
- _mixer->stopHandle(_handle);
-
delete _opl;
}
@@ -136,46 +155,38 @@ void AdLib::createOPL() {
}
_opl = OPL::Config::create(OPL::Config::parse(oplDriver), OPL::Config::kOpl2);
- if (!_opl || !_opl->init(_rate)) {
+ if (!_opl || !_opl->init()) {
delete _opl;
error("Could not create an AdLib emulator");
}
}
-int AdLib::readBuffer(int16 *buffer, const int numSamples) {
+void AdLib::onTimer() {
Common::StackLock slock(_mutex);
- // Nothing to do, fill with silence
- if (!_playing) {
- memset(buffer, 0, numSamples * sizeof(int16));
- return numSamples;
+ // Nothing to do
+ if (!_playing)
+ return;
+
+ // Check if there's anything to do on this step
+ // If not, decrease the poll number and move on
+ if (_toPoll > 0) {
+ _toPoll--;
+ return;
}
- // Read samples from the OPL, polling in more music when necessary
- uint32 samples = numSamples;
- while (samples && _playing) {
- if (_toPoll) {
- const uint32 render = MIN(samples, _toPoll);
-
- _opl->readBuffer(buffer, render);
-
- buffer += render;
- samples -= render;
- _toPoll -= render;
-
- } else {
- // Song ended, fill the rest with silence
- if (_ended) {
- memset(buffer, 0, samples * sizeof(int16));
- samples = 0;
- break;
- }
-
- // Poll more music
- _toPoll = pollMusic(_first);
- _first = false;
+ // Poll until we have to delay until the next poll
+ while (_toPoll == 0 && _playing) {
+ // Song ended, break out
+ if (_ended) {
+ _toPoll = 0;
+ break;
}
+
+ // Poll more music
+ _toPoll = pollMusic(_first);
+ _first = false;
}
// Song ended, loop if requested
@@ -195,24 +206,6 @@ int AdLib::readBuffer(int16 *buffer, const int numSamples) {
} else
_playing = false;
}
-
- return numSamples;
-}
-
-bool AdLib::isStereo() const {
- return _opl->isStereo();
-}
-
-bool AdLib::endOfData() const {
- return !_playing;
-}
-
-bool AdLib::endOfStream() const {
- return false;
-}
-
-int AdLib::getRate() const {
- return _rate;
}
bool AdLib::isPlaying() const {
@@ -231,10 +224,6 @@ void AdLib::setRepeating(int32 repCount) {
_repCount = repCount;
}
-uint32 AdLib::getSamplesPerSecond() const {
- return _rate * (isStereo() ? 2 : 1);
-}
-
void AdLib::startPlay() {
Common::StackLock slock(_mutex);
@@ -442,6 +431,13 @@ void AdLib::writeKeyScaleLevelVolume(uint8 oper) {
volume = (63 - (_operatorParams[oper][kParamLevel] & 0x3F)) * _operatorVolume[oper];
volume = 63 - ((2 * volume + kMaxVolume) / (2 * kMaxVolume));
+ // Adjust carriers for GUI volume slider
+ if (kOperatorType[oper] == 1) {
+ volume += kVolumeTable[_volume];
+ if (volume > 63)
+ volume = 63;
+ }
+
uint8 keyScale = _operatorParams[oper][kParamKeyScaleLevel] << 6;
writeOPL(0x40 + kOperatorOffset[oper], volume | keyScale);
@@ -639,4 +635,23 @@ void AdLib::setFreq(uint8 voice, uint16 note, bool on) {
writeOPL(0xB0 + voice, value);
}
+void AdLib::setTimerFrequency(int timerFrequency) {
+ _opl->setCallbackFrequency(timerFrequency);
+}
+
+void AdLib::syncVolume() {
+ Common::StackLock slock(_mutex);
+
+ bool mute = false;
+ if (ConfMan.hasKey("mute"))
+ mute = ConfMan.getBool("mute");
+
+ _volume = (mute ? 0 : ConfMan.getInt("music_volume"));
+
+ if (_playing) {
+ for(int i = 0; i < kOperatorCount; i++)
+ writeKeyScaleLevelVolume(i);
+ }
+}
+
} // End of namespace Gob
diff --git a/engines/gob/sound/adlib.h b/engines/gob/sound/adlib.h
index 8071249374..d60458295c 100644
--- a/engines/gob/sound/adlib.h
+++ b/engines/gob/sound/adlib.h
@@ -35,9 +35,9 @@ namespace OPL {
namespace Gob {
/** Base class for a player of an AdLib music format. */
-class AdLib : public Audio::AudioStream {
+class AdLib {
public:
- AdLib(Audio::Mixer &mixer);
+ AdLib(int callbackFrequency);
virtual ~AdLib();
bool isPlaying() const; ///< Are we currently playing?
@@ -53,13 +53,7 @@ public:
void startPlay();
void stopPlay();
-
-// AudioStream API
- int readBuffer(int16 *buffer, const int numSamples);
- bool isStereo() const;
- bool endOfData() const;
- bool endOfStream() const;
- int getRate() const;
+ void syncVolume();
protected:
enum kVoice {
@@ -120,8 +114,6 @@ protected:
static const int kOPLMidC = 48; ///< A mid C for the OPL.
- /** Return the number of samples per second. */
- uint32 getSamplesPerSecond() const;
/** Write a value into an OPL register. */
void writeOPL(byte reg, byte val);
@@ -135,7 +127,7 @@ protected:
/** The callback function that's called for polling more AdLib commands.
*
* @param first Is this the first poll since the start of the song?
- * @return The number of samples until the next poll.
+ * @return The number of ticks until the next poll.
*/
virtual uint32 pollMusic(bool first) = 0;
@@ -207,7 +199,14 @@ protected:
/** Switch a voice off. */
void noteOff(uint8 voice);
+ /**
+ * Set the OPL timer frequency
+ */
+ void setTimerFrequency(int timerFrequency);
+
private:
+ static const uint8 kVolumeTable[Audio::Mixer::kMaxMixerVolume + 1];
+
static const uint8 kOperatorType [kOperatorCount];
static const uint8 kOperatorOffset[kOperatorCount];
static const uint8 kOperatorVoice [kOperatorCount];
@@ -226,13 +225,11 @@ private:
static const uint16 kHihatParams [kParamCount];
- Audio::Mixer *_mixer;
- Audio::SoundHandle _handle;
OPL::OPL *_opl;
Common::Mutex _mutex;
- uint32 _rate;
+ int _volume;
uint32 _toPoll;
@@ -300,6 +297,11 @@ private:
void changePitch(uint8 voice, uint16 pitchBend);
void setFreq(uint8 voice, uint16 note, bool on);
+
+ /**
+ * Callback function for OPL
+ */
+ void onTimer();
};
} // End of namespace Gob
diff --git a/engines/gob/sound/adlplayer.cpp b/engines/gob/sound/adlplayer.cpp
index 384a928360..6354d8c37f 100644
--- a/engines/gob/sound/adlplayer.cpp
+++ b/engines/gob/sound/adlplayer.cpp
@@ -28,7 +28,7 @@
namespace Gob {
-ADLPlayer::ADLPlayer(Audio::Mixer &mixer) : AdLib(mixer),
+ADLPlayer::ADLPlayer() : AdLib(1000),
_songData(0), _songDataSize(0), _playPos(0) {
}
@@ -135,14 +135,7 @@ uint32 ADLPlayer::pollMusic(bool first) {
if (delay & 0x80)
delay = ((delay & 3) << 8) | *_playPos++;
- return getSampleDelay(delay);
-}
-
-uint32 ADLPlayer::getSampleDelay(uint16 delay) const {
- if (delay == 0)
- return 0;
-
- return ((uint32)delay * getSamplesPerSecond()) / 1000;
+ return delay;
}
void ADLPlayer::rewind() {
diff --git a/engines/gob/sound/adlplayer.h b/engines/gob/sound/adlplayer.h
index 3edd238343..50e1db5b70 100644
--- a/engines/gob/sound/adlplayer.h
+++ b/engines/gob/sound/adlplayer.h
@@ -36,7 +36,7 @@ namespace Gob {
/** A player for Coktel Vision's ADL music format. */
class ADLPlayer : public AdLib {
public:
- ADLPlayer(Audio::Mixer &mixer);
+ ADLPlayer();
~ADLPlayer();
bool load(Common::SeekableReadStream &adl);
@@ -76,8 +76,6 @@ private:
bool readHeader (Common::SeekableReadStream &adl, int &timbreCount);
bool readTimbres (Common::SeekableReadStream &adl, int timbreCount);
bool readSongData(Common::SeekableReadStream &adl);
-
- uint32 getSampleDelay(uint16 delay) const;
};
} // End of namespace Gob
diff --git a/engines/gob/sound/musplayer.cpp b/engines/gob/sound/musplayer.cpp
index 7001a5724b..dcbb712b56 100644
--- a/engines/gob/sound/musplayer.cpp
+++ b/engines/gob/sound/musplayer.cpp
@@ -27,7 +27,7 @@
namespace Gob {
-MUSPlayer::MUSPlayer(Audio::Mixer &mixer) : AdLib(mixer),
+MUSPlayer::MUSPlayer() : AdLib(60),
_songData(0), _songDataSize(0), _playPos(0), _songID(0) {
}
@@ -43,15 +43,6 @@ void MUSPlayer::unload() {
unloadMUS();
}
-uint32 MUSPlayer::getSampleDelay(uint16 delay) const {
- if (delay == 0)
- return 0;
-
- uint32 freq = (_ticksPerBeat * _tempo) / 60;
-
- return ((uint32)delay * getSamplesPerSecond()) / freq;
-}
-
void MUSPlayer::skipToTiming() {
while (*_playPos < 0x80)
_playPos++;
@@ -66,8 +57,12 @@ uint32 MUSPlayer::pollMusic(bool first) {
return 0;
}
- if (first)
- return getSampleDelay(*_playPos++);
+ if (first) {
+ // Set the timer frequency on first run.
+ // Do not set it in rewind() for thread safety reasons.
+ setTimerFrequency((_ticksPerBeat * _tempo) / 60);
+ return *_playPos++;
+ }
uint16 delay = 0;
while (delay == 0) {
@@ -100,6 +95,7 @@ uint32 MUSPlayer::pollMusic(bool first) {
uint32 denom = *_playPos++;
_tempo = _baseTempo * num + ((_baseTempo * denom) >> 7);
+ setTimerFrequency((_ticksPerBeat * _tempo) / 60);
_playPos++;
} else {
@@ -182,7 +178,7 @@ uint32 MUSPlayer::pollMusic(bool first) {
delay += *_playPos++;
}
- return getSampleDelay(delay);
+ return delay;
}
void MUSPlayer::rewind() {
diff --git a/engines/gob/sound/musplayer.h b/engines/gob/sound/musplayer.h
index c76c5aab38..973192ffd9 100644
--- a/engines/gob/sound/musplayer.h
+++ b/engines/gob/sound/musplayer.h
@@ -40,7 +40,7 @@ namespace Gob {
*/
class MUSPlayer : public AdLib {
public:
- MUSPlayer(Audio::Mixer &mixer);
+ MUSPlayer();
~MUSPlayer();
/** Load the instruments (.SND or .TBR) */
@@ -97,7 +97,6 @@ private:
bool readMUSHeader(Common::SeekableReadStream &mus);
bool readMUSSong (Common::SeekableReadStream &mus);
- uint32 getSampleDelay(uint16 delay) const;
void setInstrument(uint8 voice, uint8 instrument);
void skipToTiming();
diff --git a/engines/gob/sound/sound.cpp b/engines/gob/sound/sound.cpp
index d2b2d3d6e8..22dfe9d3c3 100644
--- a/engines/gob/sound/sound.cpp
+++ b/engines/gob/sound/sound.cpp
@@ -234,7 +234,7 @@ bool Sound::adlibLoadADL(const char *fileName) {
return false;
if (!_adlPlayer)
- _adlPlayer = new ADLPlayer(*_vm->_mixer);
+ _adlPlayer = new ADLPlayer();
debugC(1, kDebugSound, "AdLib: Loading ADL data (\"%s\")", fileName);
@@ -256,7 +256,7 @@ bool Sound::adlibLoadADL(byte *data, uint32 size, int index) {
return false;
if (!_adlPlayer)
- _adlPlayer = new ADLPlayer(*_vm->_mixer);
+ _adlPlayer = new ADLPlayer();
debugC(1, kDebugSound, "AdLib: Loading ADL data (%d)", index);
@@ -425,6 +425,16 @@ int32 Sound::adlibGetRepeating() const {
return false;
}
+void Sound::adlibSyncVolume() {
+ if (!_hasAdLib)
+ return;
+
+ if (_adlPlayer)
+ _adlPlayer->syncVolume();
+ if (_mdyPlayer)
+ _mdyPlayer->syncVolume();
+}
+
void Sound::adlibSetRepeating(int32 repCount) {
if (!_hasAdLib)
return;
@@ -739,7 +749,7 @@ void Sound::createMDYPlayer() {
delete _adlPlayer;
_adlPlayer = 0;
- _mdyPlayer = new MUSPlayer(*_vm->_mixer);
+ _mdyPlayer = new MUSPlayer();
}
void Sound::createADLPlayer() {
@@ -749,7 +759,7 @@ void Sound::createADLPlayer() {
delete _mdyPlayer;
_mdyPlayer= 0;
- _adlPlayer = new ADLPlayer(*_vm->_mixer);
+ _adlPlayer = new ADLPlayer();
}
} // End of namespace Gob
diff --git a/engines/gob/sound/sound.h b/engines/gob/sound/sound.h
index c959959755..6ebc323b18 100644
--- a/engines/gob/sound/sound.h
+++ b/engines/gob/sound/sound.h
@@ -96,6 +96,7 @@ public:
int32 adlibGetRepeating() const;
void adlibSetRepeating(int32 repCount);
+ void adlibSyncVolume();
// Infogrames
diff --git a/engines/groovie/music.cpp b/engines/groovie/music.cpp
index 2c164e020c..c00290b155 100644
--- a/engines/groovie/music.cpp
+++ b/engines/groovie/music.cpp
@@ -36,6 +36,7 @@
#include "common/textconsole.h"
#include "audio/audiostream.h"
#include "audio/midiparser.h"
+#include "audio/miles.h"
namespace Groovie {
@@ -379,14 +380,56 @@ bool MusicPlayerMidi::loadParser(Common::SeekableReadStream *stream, bool loop)
MusicPlayerXMI::MusicPlayerXMI(GroovieEngine *vm, const Common::String &gtlName) :
MusicPlayerMidi(vm) {
- // Create the parser
- _midiParser = MidiParser::createParser_XMIDI();
// Create the driver
MidiDriver::DeviceHandle dev = MidiDriver::detectDevice(MDT_MIDI | MDT_ADLIB | MDT_PREFER_GM);
- _driver = MidiDriver::createMidi(dev);
+ MusicType musicType = MidiDriver::getMusicType(dev);
+ _driver = NULL;
+
+ // new Miles Audio support, to disable set milesAudioEnabled to false
+ _milesAudioMode = false;
+ bool milesAudioEnabled = true;
+ MidiParser::XMidiNewTimbreListProc newTimbreListProc = NULL;
+
+ if (milesAudioEnabled) {
+ // 7th Guest uses FAT.AD/FAT.OPL/FAT.MT
+ // 11th Hour uses SAMPLE.AD/SAMPLE.OPL/SAMPLE.MT
+ switch (musicType) {
+ case MT_ADLIB:
+ _driver = Audio::MidiDriver_Miles_AdLib_create(gtlName + ".AD", gtlName + ".OPL");
+ break;
+ case MT_MT32:
+ _driver = Audio::MidiDriver_Miles_MT32_create(gtlName + ".MT");
+ break;
+ case MT_GM:
+ if (ConfMan.getBool("native_mt32")) {
+ _driver = Audio::MidiDriver_Miles_MT32_create(gtlName + ".MT");
+ musicType = MT_MT32;
+ }
+ break;
+ default:
+ break;
+ }
+
+ if (musicType == MT_MT32) {
+ newTimbreListProc = Audio::MidiDriver_Miles_MT32_processXMIDITimbreChunk;
+ }
+ }
+
+ if (_driver) {
+ _milesAudioMode = true;
+ }
+
+ if (!_driver) {
+ // No driver yet? create a generic one
+ _driver = MidiDriver::createMidi(dev);
+ }
+
assert(_driver);
+ // Create the parser
+ _midiParser = MidiParser::createParser_XMIDI(NULL, NULL, newTimbreListProc, _driver);
+
_driver->open(); // TODO: Handle return value != 0 (indicating an error)
// Set the parser's driver
@@ -400,6 +443,9 @@ MusicPlayerXMI::MusicPlayerXMI(GroovieEngine *vm, const Common::String &gtlName)
_chanBanks[i] = 0;
}
+ if (_milesAudioMode)
+ return;
+
// Load the Global Timbre Library
if (MidiDriver::getMusicType(dev) == MT_ADLIB) {
// MIDI through AdLib
@@ -433,6 +479,11 @@ MusicPlayerXMI::~MusicPlayerXMI() {
}
void MusicPlayerXMI::send(uint32 b) {
+ if (_milesAudioMode) {
+ MusicPlayerMidi::send(b);
+ return;
+ }
+
if ((b & 0xFFF0) == 0x72B0) { // XMIDI Patch Bank Select 114
// From AIL2's documentation: XMIDI Patch Bank Select controller (114)
// selects a bank to be used when searching the next patches
diff --git a/engines/groovie/music.h b/engines/groovie/music.h
index 4853840673..dcb91d42a8 100644
--- a/engines/groovie/music.h
+++ b/engines/groovie/music.h
@@ -134,6 +134,8 @@ private:
// Output music type
uint8 _musicType;
+ bool _milesAudioMode;
+
// Timbres
class Timbre {
public:
diff --git a/engines/kyra/sound_adlib.cpp b/engines/kyra/sound_adlib.cpp
index c0e0f67b8e..1d741d8bd0 100644
--- a/engines/kyra/sound_adlib.cpp
+++ b/engines/kyra/sound_adlib.cpp
@@ -55,7 +55,7 @@
namespace Kyra {
-class AdLibDriver : public Audio::AudioStream {
+class AdLibDriver {
public:
AdLibDriver(Audio::Mixer *mixer, int version);
~AdLibDriver();
@@ -70,34 +70,6 @@ public:
void callback();
- // AudioStream API
- int readBuffer(int16 *buffer, const int numSamples) {
- int32 samplesLeft = numSamples;
- memset(buffer, 0, sizeof(int16) * numSamples);
- while (samplesLeft) {
- if (!_samplesTillCallback) {
- callback();
- _samplesTillCallback = _samplesPerCallback;
- _samplesTillCallbackRemainder += _samplesPerCallbackRemainder;
- if (_samplesTillCallbackRemainder >= CALLBACKS_PER_SECOND) {
- _samplesTillCallback++;
- _samplesTillCallbackRemainder -= CALLBACKS_PER_SECOND;
- }
- }
-
- int32 render = MIN(samplesLeft, _samplesTillCallback);
- samplesLeft -= render;
- _samplesTillCallback -= render;
- YM3812UpdateOne(_adlib, buffer, render);
- buffer += render;
- }
- return numSamples;
- }
-
- bool isStereo() const { return false; }
- bool endOfData() const { return false; }
- int getRate() const { return _mixer->getOutputRate(); }
-
void setSyncJumpMask(uint16 mask) { _syncJumpMask = mask; }
void setMusicVolume(uint8 volume);
@@ -334,11 +306,6 @@ private:
// _unkTable2_2[] - One of the tables in _unkTable2[]
// _unkTable2_3[] - One of the tables in _unkTable2[]
- int32 _samplesPerCallback;
- int32 _samplesPerCallbackRemainder;
- int32 _samplesTillCallback;
- int32 _samplesTillCallbackRemainder;
-
int _curChannel;
uint8 _soundTrigger;
@@ -365,7 +332,7 @@ private:
uint8 _unkValue19;
uint8 _unkValue20;
- FM_OPL *_adlib;
+ OPL::OPL *_adlib;
uint8 *_soundData;
uint32 _soundDataSize;
@@ -411,7 +378,6 @@ private:
Common::Mutex _mutex;
Audio::Mixer *_mixer;
- Audio::SoundHandle _soundHandle;
uint8 _musicVolume, _sfxVolume;
@@ -427,8 +393,9 @@ AdLibDriver::AdLibDriver(Audio::Mixer *mixer, int version) {
_mixer = mixer;
- _adlib = makeAdLibOPL(getRate());
- assert(_adlib);
+ _adlib = OPL::Config::create();
+ if (!_adlib || !_adlib->init())
+ error("Failed to create OPL");
memset(_channels, 0, sizeof(_channels));
_soundData = 0;
@@ -451,13 +418,6 @@ AdLibDriver::AdLibDriver(Audio::Mixer *mixer, int version) {
_tablePtr1 = _tablePtr2 = 0;
- _mixer->playStream(Audio::Mixer::kPlainSoundType, &_soundHandle, this, -1, Audio::Mixer::kMaxChannelVolume, 0, DisposeAfterUse::NO, true);
-
- _samplesPerCallback = getRate() / CALLBACKS_PER_SECOND;
- _samplesPerCallbackRemainder = getRate() % CALLBACKS_PER_SECOND;
- _samplesTillCallback = 0;
- _samplesTillCallbackRemainder = 0;
-
_syncJumpMask = 0;
_musicVolume = 0;
@@ -467,11 +427,12 @@ AdLibDriver::AdLibDriver(Audio::Mixer *mixer, int version) {
_programQueueStart = _programQueueEnd = 0;
_retrySounds = false;
+
+ _adlib->start(new Common::Functor0Mem<void, AdLibDriver>(this, &AdLibDriver::callback), CALLBACKS_PER_SECOND);
}
AdLibDriver::~AdLibDriver() {
- _mixer->stopHandle(_soundHandle);
- OPLDestroy(_adlib);
+ delete _adlib;
_adlib = 0;
}
@@ -877,7 +838,7 @@ void AdLibDriver::resetAdLibState() {
// New calling style: writeOPL(0xAB, 0xCD)
void AdLibDriver::writeOPL(byte reg, byte val) {
- OPLWriteReg(_adlib, reg, val);
+ _adlib->writeReg(reg, val);
}
void AdLibDriver::initChannel(Channel &channel) {
diff --git a/engines/lure/res.h b/engines/lure/res.h
index 9002ca3056..19fbde1aad 100644
--- a/engines/lure/res.h
+++ b/engines/lure/res.h
@@ -100,7 +100,6 @@ public:
static Resources &getReference();
void reset();
- byte *getResource(uint16 resId);
RoomDataList &roomData() { return _roomData; }
RoomData *getRoom(uint16 roomNumber);
bool checkHotspotExtent(HotspotData *hotspot);
diff --git a/engines/made/made.cpp b/engines/made/made.cpp
index af8156fc3e..ab07ef757b 100644
--- a/engines/made/made.cpp
+++ b/engines/made/made.cpp
@@ -275,7 +275,7 @@ void MadeEngine::handleEvents() {
}
Common::Error MadeEngine::run() {
- _music = new MusicPlayer();
+ _music = new MusicPlayer(getGameID() == GID_RTZ);
syncSoundSettings();
// Initialize backend
diff --git a/engines/made/music.cpp b/engines/made/music.cpp
index b2917b58ed..f57da833c2 100644
--- a/engines/made/music.cpp
+++ b/engines/made/music.cpp
@@ -25,27 +25,67 @@
// MIDI and digital music class
#include "made/music.h"
+#include "made/redreader.h"
#include "made/resource.h"
#include "audio/midiparser.h"
+#include "audio/miles.h"
+
+#include "common/file.h"
+#include "common/stream.h"
namespace Made {
-MusicPlayer::MusicPlayer() : _isGM(false) {
- MidiPlayer::createDriver();
+MusicPlayer::MusicPlayer(bool milesAudio) : _isGM(false),_milesAudioMode(false) {
+ MusicType musicType = MT_INVALID;
+ if (milesAudio) {
+ MidiDriver::DeviceHandle dev = MidiDriver::detectDevice(MDT_MIDI | MDT_ADLIB | MDT_PREFER_MT32);
+ musicType = MidiDriver::getMusicType(dev);
+ Common::SeekableReadStream *adLibInstrumentStream = nullptr;
+ switch (musicType) {
+ case MT_ADLIB:
+ _milesAudioMode = true;
+ if (Common::File::exists("rtzcd.red")) {
+ // Installing Return to Zork produces both a SAMPLE.AD and
+ // a SAMPLE.OPL file, but they are identical. The resource
+ // file appears to only contain SAMPLE.AD.
+ adLibInstrumentStream = RedReader::loadFromRed("rtzcd.red", "SAMPLE.AD");
+ }
+ _driver = Audio::MidiDriver_Miles_AdLib_create("SAMPLE.AD", "SAMPLE.OPL", adLibInstrumentStream);
+ delete adLibInstrumentStream;
+ break;
+ case MT_MT32:
+ _milesAudioMode = true;
+ _driver = Audio::MidiDriver_Miles_MT32_create("");
+ break;
+ default:
+ _milesAudioMode = false;
+ MidiPlayer::createDriver();
+ break;
+ }
+ } else {
+ MidiPlayer::createDriver();
+ }
int ret = _driver->open();
if (ret == 0) {
- if (_nativeMT32)
- _driver->sendMT32Reset();
- else
- _driver->sendGMReset();
+ if (musicType != MT_ADLIB) {
+ if (_nativeMT32)
+ _driver->sendMT32Reset();
+ else
+ _driver->sendGMReset();
+ }
_driver->setTimerCallback(this, &timerCallback);
}
}
void MusicPlayer::send(uint32 b) {
+ if (_milesAudioMode) {
+ _driver->send(b);
+ return;
+ }
+
if ((b & 0xF0) == 0xC0 && !_isGM && !_nativeMT32) {
b = (b & 0xFFFF00FF) | MidiDriver::_mt32ToGm[(b >> 8) & 0xFF] << 8;
}
diff --git a/engines/made/music.h b/engines/made/music.h
index 95d1bd35c1..558b41c2e2 100644
--- a/engines/made/music.h
+++ b/engines/made/music.h
@@ -38,7 +38,7 @@ enum MusicFlags {
class MusicPlayer : public Audio::MidiPlayer {
public:
- MusicPlayer();
+ MusicPlayer(bool milesAudio);
void playXMIDI(GenericResource *midiResource, MusicFlags flags = MUSIC_NORMAL);
void playSMF(GenericResource *midiResource, MusicFlags flags = MUSIC_NORMAL);
@@ -51,6 +51,7 @@ public:
protected:
bool _isGM;
+ bool _milesAudioMode;
};
} // End of namespace Made
diff --git a/engines/made/pmvplayer.cpp b/engines/made/pmvplayer.cpp
index 6ea0dc24d0..453e2a4872 100644
--- a/engines/made/pmvplayer.cpp
+++ b/engines/made/pmvplayer.cpp
@@ -118,6 +118,8 @@ bool PmvPlayer::play(const char *filename) {
// get it to work well?
_audioStream = Audio::makeQueuingAudioStream(soundFreq, false);
+ SoundDecoderData *soundDecoderData = new SoundDecoderData();
+
while (!_vm->shouldQuit() && !_aborted && !_fd->eos() && frameNumber < frameCount) {
int32 frameTime = _vm->_system->getMillis();
@@ -153,7 +155,7 @@ bool PmvPlayer::play(const char *filename) {
soundSize = chunkCount * chunkSize;
soundData = (byte *)malloc(soundSize);
- decompressSound(audioData + 8, soundData, chunkSize, chunkCount);
+ decompressSound(audioData + 8, soundData, chunkSize, chunkCount, NULL, soundDecoderData);
_audioStream->queueBuffer(soundData, soundSize, DisposeAfterUse::YES, Audio::FLAG_UNSIGNED);
}
@@ -213,6 +215,7 @@ bool PmvPlayer::play(const char *filename) {
}
+ delete soundDecoderData;
delete[] frameData;
_audioStream->finish();
diff --git a/engines/made/screenfx.cpp b/engines/made/screenfx.cpp
index 3f98cbb9ab..bae59f05cc 100644
--- a/engines/made/screenfx.cpp
+++ b/engines/made/screenfx.cpp
@@ -201,7 +201,7 @@ void ScreenEffects::startBlendedPalette(byte *palette, byte *newPalette, int col
}
void ScreenEffects::stepBlendedPalette() {
- if (_blendedPaletteStatus._active && _blendedPaletteStatus._value < _blendedPaletteStatus._maxValue) {
+ if (_blendedPaletteStatus._active && _blendedPaletteStatus._value <= _blendedPaletteStatus._maxValue) {
setBlendedPalette(_blendedPaletteStatus._palette, _blendedPaletteStatus._newPalette,
_blendedPaletteStatus._colorCount, _blendedPaletteStatus._value, _blendedPaletteStatus._maxValue);
if (_blendedPaletteStatus._value == _blendedPaletteStatus._maxValue)
diff --git a/engines/made/sound.cpp b/engines/made/sound.cpp
index 91e855cbf5..ad49031e7b 100644
--- a/engines/made/sound.cpp
+++ b/engines/made/sound.cpp
@@ -133,10 +133,10 @@ void ManholeEgaSoundDecompressor::update3() {
_sample2 += _sample1;
}
-void decompressSound(byte *source, byte *dest, uint16 chunkSize, uint16 chunkCount, SoundEnergyArray *soundEnergyArray) {
+void decompressSound(byte *source, byte *dest, uint16 chunkSize, uint16 chunkCount, SoundEnergyArray *soundEnergyArray, SoundDecoderData *soundDecoderData) {
- int16 prevSample = 0, workSample = 0;
- byte soundBuffer[1025];
+ int16 prevSample, workSample;
+ byte* soundBuffer;
byte deltaSoundBuffer[1024];
int16 soundBuffer2[16];
byte deltaType, type;
@@ -159,6 +159,15 @@ void decompressSound(byte *source, byte *dest, uint16 chunkSize, uint16 chunkCou
if (soundEnergyArray)
soundEnergyArray->clear();
+ if (soundDecoderData) {
+ soundBuffer = soundDecoderData->_soundBuffer;
+ prevSample = soundDecoderData->_prevSample;
+ } else {
+ soundBuffer = new byte[1025];
+ memset(soundBuffer, 0x80, 1025);
+ prevSample = 0;
+ }
+
while (chunkCount--) {
deltaType = (*source) >> 6;
workChunkSize = chunkSize;
@@ -233,6 +242,11 @@ void decompressSound(byte *source, byte *dest, uint16 chunkSize, uint16 chunkCou
}
if (deltaType > 0) {
+ // NB: The original did not add this extra value at the end (as far
+ // as I can tell), and so technically read past the filled part of
+ // soundBuffer.
+ soundBuffer[workChunkSize] = soundBuffer[workChunkSize - 1];
+
if (deltaType == 1) {
for (i = 0; i < chunkSize - 1; i += 2) {
l = i / 2;
@@ -255,9 +269,13 @@ void decompressSound(byte *source, byte *dest, uint16 chunkSize, uint16 chunkCou
prevSample = workSample;
memcpy(dest, soundBuffer, chunkSize);
dest += chunkSize;
-
}
+ if (soundDecoderData) {
+ soundDecoderData->_prevSample = prevSample;
+ } else {
+ delete[] soundBuffer;
+ }
}
} // End of namespace Made
diff --git a/engines/made/sound.h b/engines/made/sound.h
index 6ffca13aaa..72537322f9 100644
--- a/engines/made/sound.h
+++ b/engines/made/sound.h
@@ -53,7 +53,22 @@ struct SoundEnergyItem {
typedef Common::Array<SoundEnergyItem> SoundEnergyArray;
-void decompressSound(byte *source, byte *dest, uint16 chunkSize, uint16 chunkCount, SoundEnergyArray *soundEnergyArray = NULL);
+
+// Persistent data for decompressSound(). When calling decompressSound()
+// repeatedly (for the same stream), pass the same SoundDecoderData object to
+// ensure decoding properly resumes.
+class SoundDecoderData {
+public:
+ SoundDecoderData() {
+ memset(_soundBuffer, 0x80, sizeof(_soundBuffer));
+ _prevSample = 0;
+ }
+
+ byte _soundBuffer[1025];
+ int16 _prevSample;
+};
+
+void decompressSound(byte *source, byte *dest, uint16 chunkSize, uint16 chunkCount, SoundEnergyArray *soundEnergyArray = NULL, SoundDecoderData *decoderData = NULL);
} // End of namespace Made
diff --git a/engines/mads/hotspots.cpp b/engines/mads/hotspots.cpp
index bd28645504..8afef2e524 100644
--- a/engines/mads/hotspots.cpp
+++ b/engines/mads/hotspots.cpp
@@ -193,9 +193,8 @@ Hotspot::Hotspot(Common::SeekableReadStream &f, bool isV2) {
_active = f.readByte() != 0;
_cursor = (CursorType)f.readByte();
if (isV2) {
- // This looks to be some sort of bitmask. Perhaps it signifies
- // the valid verbs for this hotspot
- f.skip(2); // unknown
+ f.skip(1); // cursor
+ f.skip(1); // syntax
}
_vocabId = f.readUint16LE();
_verbId = f.readUint16LE();
diff --git a/engines/mads/nebular/sound_nebular.cpp b/engines/mads/nebular/sound_nebular.cpp
index 240c18f6dc..711f82a05b 100644
--- a/engines/mads/nebular/sound_nebular.cpp
+++ b/engines/mads/nebular/sound_nebular.cpp
@@ -21,6 +21,7 @@
*/
#include "audio/audiostream.h"
+#include "audio/fmopl.h"
#include "audio/decoders/raw.h"
#include "common/algorithm.h"
#include "common/debug.h"
@@ -156,7 +157,7 @@ AdlibSample::AdlibSample(Common::SeekableReadStream &s) {
/*-----------------------------------------------------------------------*/
-ASound::ASound(Audio::Mixer *mixer, FM_OPL *opl, const Common::String &filename, int dataOffset) {
+ASound::ASound(Audio::Mixer *mixer, OPL::OPL *opl, const Common::String &filename, int dataOffset) {
// Open up the appropriate sound file
if (!_soundFile.open(filename))
error("Could not open file - %s", filename.c_str());
@@ -188,11 +189,6 @@ ASound::ASound(Audio::Mixer *mixer, FM_OPL *opl, const Common::String &filename,
_randomSeed = 1234;
_amDep = _vibDep = _splitPoint = true;
- _samplesTillCallback = 0;
- _samplesTillCallbackRemainder = 0;
- _samplesPerCallback = getRate() / CALLBACKS_PER_SECOND;
- _samplesPerCallbackRemainder = getRate() % CALLBACKS_PER_SECOND;
-
for (int i = 0; i < 11; ++i) {
_channelData[i]._field0 = 0;
_channelData[i]._freqMask = 0;
@@ -210,23 +206,19 @@ ASound::ASound(Audio::Mixer *mixer, FM_OPL *opl, const Common::String &filename,
_mixer = mixer;
_opl = opl;
- _opl->init(getRate());
- _mixer->playStream(Audio::Mixer::kPlainSoundType, &_soundHandle, this, -1,
- Audio::Mixer::kMaxChannelVolume, 0, DisposeAfterUse::NO, true);
-
// Initialize the Adlib
adlibInit();
// Reset the adlib
command0();
+
+ _opl->start(new Common::Functor0Mem<void, ASound>(this, &ASound::onTimer), CALLBACKS_PER_SECOND);
}
ASound::~ASound() {
Common::List<CachedDataEntry>::iterator i;
for (i = _dataCache.begin(); i != _dataCache.end(); ++i)
delete[] (*i)._data;
-
- _mixer->stopHandle(_soundHandle);
}
void ASound::validate() {
@@ -832,32 +824,10 @@ void ASound::updateFNumber() {
write2(8, hiReg, val2);
}
-int ASound::readBuffer(int16 *buffer, const int numSamples) {
+void ASound::onTimer() {
Common::StackLock slock(_driverMutex);
-
- int32 samplesLeft = numSamples;
- memset(buffer, 0, sizeof(int16) * numSamples);
- while (samplesLeft) {
- if (!_samplesTillCallback) {
- poll();
- flush();
-
- _samplesTillCallback = _samplesPerCallback;
- _samplesTillCallbackRemainder += _samplesPerCallbackRemainder;
- if (_samplesTillCallbackRemainder >= CALLBACKS_PER_SECOND) {
- _samplesTillCallback++;
- _samplesTillCallbackRemainder -= CALLBACKS_PER_SECOND;
- }
- }
-
- int32 render = MIN<int>(samplesLeft, _samplesTillCallback);
- samplesLeft -= render;
- _samplesTillCallback -= render;
-
- _opl->readBuffer(buffer, render);
- buffer += render;
- }
- return numSamples;
+ poll();
+ flush();
}
void ASound::setVolume(int volume) {
@@ -984,7 +954,7 @@ const ASound1::CommandPtr ASound1::_commandList[42] = {
&ASound1::command40, &ASound1::command41
};
-ASound1::ASound1(Audio::Mixer *mixer, FM_OPL *opl)
+ASound1::ASound1(Audio::Mixer *mixer, OPL::OPL *opl)
: ASound(mixer, opl, "asound.001", 0x1520) {
_cmd23Toggle = false;
@@ -1285,7 +1255,7 @@ const ASound2::CommandPtr ASound2::_commandList[44] = {
&ASound2::command40, &ASound2::command41, &ASound2::command42, &ASound2::command43
};
-ASound2::ASound2(Audio::Mixer *mixer, FM_OPL *opl) : ASound(mixer, opl, "asound.002", 0x15E0) {
+ASound2::ASound2(Audio::Mixer *mixer, OPL::OPL *opl) : ASound(mixer, opl, "asound.002", 0x15E0) {
_command12Param = 0xFD;
// Load sound samples
@@ -1656,7 +1626,7 @@ const ASound3::CommandPtr ASound3::_commandList[61] = {
&ASound3::command60
};
-ASound3::ASound3(Audio::Mixer *mixer, FM_OPL *opl) : ASound(mixer, opl, "asound.003", 0x15B0) {
+ASound3::ASound3(Audio::Mixer *mixer, OPL::OPL *opl) : ASound(mixer, opl, "asound.003", 0x15B0) {
_command39Flag = false;
// Load sound samples
@@ -2060,7 +2030,7 @@ const ASound4::CommandPtr ASound4::_commandList[61] = {
&ASound4::command60
};
-ASound4::ASound4(Audio::Mixer *mixer, FM_OPL *opl) : ASound(mixer, opl, "asound.004", 0x14F0) {
+ASound4::ASound4(Audio::Mixer *mixer, OPL::OPL *opl) : ASound(mixer, opl, "asound.004", 0x14F0) {
// Load sound samples
_soundFile.seek(_dataOffset + 0x122);
for (int i = 0; i < 210; ++i)
@@ -2316,7 +2286,7 @@ const ASound5::CommandPtr ASound5::_commandList[42] = {
&ASound5::command40, &ASound5::command41
};
-ASound5::ASound5(Audio::Mixer *mixer, FM_OPL *opl) : ASound(mixer, opl, "asound.002", 0x15E0) {
+ASound5::ASound5(Audio::Mixer *mixer, OPL::OPL *opl) : ASound(mixer, opl, "asound.002", 0x15E0) {
// Load sound samples
_soundFile.seek(_dataOffset + 0x144);
for (int i = 0; i < 164; ++i)
@@ -2557,7 +2527,7 @@ const ASound6::CommandPtr ASound6::_commandList[30] = {
&ASound6::nullCommand, &ASound6::command29
};
-ASound6::ASound6(Audio::Mixer *mixer, FM_OPL *opl) : ASound(mixer, opl, "asound.006", 0x1390) {
+ASound6::ASound6(Audio::Mixer *mixer, OPL::OPL *opl) : ASound(mixer, opl, "asound.006", 0x1390) {
// Load sound samples
_soundFile.seek(_dataOffset + 0x122);
for (int i = 0; i < 200; ++i)
@@ -2713,7 +2683,7 @@ const ASound7::CommandPtr ASound7::_commandList[38] = {
&ASound7::command36, &ASound7::command37
};
-ASound7::ASound7(Audio::Mixer *mixer, FM_OPL *opl) : ASound(mixer, opl, "asound.007", 0x1460) {
+ASound7::ASound7(Audio::Mixer *mixer, OPL::OPL *opl) : ASound(mixer, opl, "asound.007", 0x1460) {
// Load sound samples
_soundFile.seek(_dataOffset + 0x122);
for (int i = 0; i < 214; ++i)
@@ -2919,7 +2889,7 @@ const ASound8::CommandPtr ASound8::_commandList[38] = {
&ASound8::command36, &ASound8::command37
};
-ASound8::ASound8(Audio::Mixer *mixer, FM_OPL *opl) : ASound(mixer, opl, "asound.008", 0x1490) {
+ASound8::ASound8(Audio::Mixer *mixer, OPL::OPL *opl) : ASound(mixer, opl, "asound.008", 0x1490) {
// Load sound samples
_soundFile.seek(_dataOffset + 0x122);
for (int i = 0; i < 174; ++i)
@@ -3175,7 +3145,7 @@ const ASound9::CommandPtr ASound9::_commandList[52] = {
&ASound9::command48, &ASound9::command49, &ASound9::command50, &ASound9::command51
};
-ASound9::ASound9(Audio::Mixer *mixer, FM_OPL *opl) : ASound(mixer, opl, "asound.009", 0x16F0) {
+ASound9::ASound9(Audio::Mixer *mixer, OPL::OPL *opl) : ASound(mixer, opl, "asound.009", 0x16F0) {
_v1 = _v2 = 0;
_soundPtr = nullptr;
diff --git a/engines/mads/nebular/sound_nebular.h b/engines/mads/nebular/sound_nebular.h
index 9bc1a49458..2b80b08d89 100644
--- a/engines/mads/nebular/sound_nebular.h
+++ b/engines/mads/nebular/sound_nebular.h
@@ -28,9 +28,12 @@
#include "common/mutex.h"
#include "common/queue.h"
#include "audio/audiostream.h"
-#include "audio/fmopl.h"
#include "audio/mixer.h"
+namespace OPL {
+class OPL;
+}
+
namespace MADS {
class SoundManager;
@@ -142,7 +145,7 @@ struct CachedDataEntry {
/**
* Base class for the sound player resource files
*/
-class ASound : public Audio::AudioStream {
+class ASound {
private:
Common::List<CachedDataEntry> _dataCache;
uint16 _randomSeed;
@@ -192,6 +195,11 @@ private:
void processSample();
void updateFNumber();
+
+ /**
+ * Timer function for OPL
+ */
+ void onTimer();
protected:
int _commandParam;
@@ -273,8 +281,7 @@ protected:
int nullCommand() { return 0; }
public:
Audio::Mixer *_mixer;
- FM_OPL *_opl;
- Audio::SoundHandle _soundHandle;
+ OPL::OPL *_opl;
AdlibChannel _channels[ADLIB_CHANNEL_COUNT];
AdlibChannel *_activeChannelPtr;
AdlibChannelData _channelData[11];
@@ -306,10 +313,6 @@ public:
int _activeChannelReg;
int _v11;
bool _amDep, _vibDep, _splitPoint;
- int _samplesPerCallback;
- int _samplesPerCallbackRemainder;
- int _samplesTillCallback;
- int _samplesTillCallbackRemainder;
public:
/**
* Constructor
@@ -318,7 +321,7 @@ public:
* @param filename Specifies the adlib sound player file to use
* @param dataOffset Offset in the file of the data segment
*/
- ASound(Audio::Mixer *mixer, FM_OPL *opl, const Common::String &filename, int dataOffset);
+ ASound(Audio::Mixer *mixer, OPL::OPL *opl, const Common::String &filename, int dataOffset);
/**
* Destructor
@@ -363,27 +366,6 @@ public:
*/
CachedDataEntry &getCachedData(byte *pData);
- // AudioStream interface
- /**
- * Main buffer read
- */
- virtual int readBuffer(int16 *buffer, const int numSamples);
-
- /**
- * Mono sound only
- */
- virtual bool isStereo() const { return false; }
-
- /**
- * Data is continuously pushed, so definitive end
- */
- virtual bool endOfData() const { return false; }
-
- /**
- * Return sample rate
- */
- virtual int getRate() const { return 11025; }
-
/**
* Set the volume
*/
@@ -433,7 +415,7 @@ private:
void command111213();
int command2627293032();
public:
- ASound1(Audio::Mixer *mixer, FM_OPL *opl);
+ ASound1(Audio::Mixer *mixer, OPL::OPL *opl);
virtual int command(int commandId, int param);
};
@@ -485,7 +467,7 @@ private:
void command9Randomize();
void command9Apply(byte *data, int val, int incr);
public:
- ASound2(Audio::Mixer *mixer, FM_OPL *opl);
+ ASound2(Audio::Mixer *mixer, OPL::OPL *opl);
virtual int command(int commandId, int param);
};
@@ -545,7 +527,7 @@ private:
void command9Randomize();
void command9Apply(byte *data, int val, int incr);
public:
- ASound3(Audio::Mixer *mixer, FM_OPL *opl);
+ ASound3(Audio::Mixer *mixer, OPL::OPL *opl);
virtual int command(int commandId, int param);
};
@@ -583,7 +565,7 @@ private:
void method1();
public:
- ASound4(Audio::Mixer *mixer, FM_OPL *opl);
+ ASound4(Audio::Mixer *mixer, OPL::OPL *opl);
virtual int command(int commandId, int param);
};
@@ -629,7 +611,7 @@ private:
int command42();
int command43();
public:
- ASound5(Audio::Mixer *mixer, FM_OPL *opl);
+ ASound5(Audio::Mixer *mixer, OPL::OPL *opl);
virtual int command(int commandId, int param);
};
@@ -658,7 +640,7 @@ private:
int command25();
int command29();
public:
- ASound6(Audio::Mixer *mixer, FM_OPL *opl);
+ ASound6(Audio::Mixer *mixer, OPL::OPL *opl);
virtual int command(int commandId, int param);
};
@@ -690,7 +672,7 @@ private:
int command36();
int command37();
public:
- ASound7(Audio::Mixer *mixer, FM_OPL *opl);
+ ASound7(Audio::Mixer *mixer, OPL::OPL *opl);
virtual int command(int commandId, int param);
};
@@ -733,7 +715,7 @@ private:
void method1(byte *pData);
void adjustRange(byte *pData, byte v, int incr);
public:
- ASound8(Audio::Mixer *mixer, FM_OPL *opl);
+ ASound8(Audio::Mixer *mixer, OPL::OPL *opl);
virtual int command(int commandId, int param);
};
@@ -792,7 +774,7 @@ private:
int command59();
int command60();
public:
- ASound9(Audio::Mixer *mixer, FM_OPL *opl);
+ ASound9(Audio::Mixer *mixer, OPL::OPL *opl);
virtual int command(int commandId, int param);
};
diff --git a/engines/mads/phantom/game_phantom.cpp b/engines/mads/phantom/game_phantom.cpp
index 959a726edf..592a108aea 100644
--- a/engines/mads/phantom/game_phantom.cpp
+++ b/engines/mads/phantom/game_phantom.cpp
@@ -52,31 +52,74 @@ void GamePhantom::startGame() {
void GamePhantom::initializeGlobals() {
_globals.reset();
- warning("TODO: sub_316DA()");
+ // TODO: Catacombs setup
_player._facing = FACING_NORTH;
_player._turnToFacing = FACING_NORTH;
- _globals[kCurrentYear] = 1993;
-
- /* Section #1 variables */
- // TODO
-
- /* Section #2 variables */
- // TODO
-
- /* Section #3 variables */
- // TODO
-
- /* Section #4 variables */
- // TODO
-
- /* Section #5 variables */
- // TODO
-
- /* Section #9 variables */
- // TODO
-
+ _globals[kTempVar] = false;
+ _globals[kRoom103104Transition] = 1; // new room
+ _globals[kCurrentYear] = 1993;
+ _globals[kTrapDoorStatus] = 0; // open
+ _globals[kChristineDoorStatus] = 0; // Christine is in her room
+ _globals[kSandbagStatus] = 0; // sandbag is secure
+ _globals[kJacquesStatus] = 0; // alive
+ _globals[kChrisFStatus] = 1; // Christine F. is alive in 1993
+ _globals[kBrieTalkStatus] = 0; // before Brie motions
+ _globals[kPanelIn206] = 0; // not discovered
+ _globals[kFightStatus] = 0;
+ _globals[kJuliesDoor] = 1; // cracked open
+ _globals[kPrompterStandStatus] = 0;
+ _globals[kChrisDStatus] = 0; // before love
+ _globals[kJulieNameIsKnown] = 0;
+ _globals[kDoorsIn205] = 0; // both locked
+ _globals[kMadameGiryLocation] = 1; // middle
+ _globals[kTicketPeoplePresent] = 0;
+ _globals[kCoffinStatus] = 0; // closed and locked
+ _globals[kDoneBrieConv203] = 0;
+ _globals[kFlorentNameIsKnown] = 0;
+ _globals[kDegasNameIsKnown] = 0;
+ _globals[kMadameGiryShowsUp] = false;
+ _globals[kJacquesNameIsKnown] = 0;
+ _globals[kCharlesNameIsKnown] = false;
+ _globals[kTopFloorLocked] = true;
+ _globals[kMadameNameIsKnown] = 0;
+ _globals[kChrisKickedRaoulOut] = false;
+ _globals[kLookedAtCase] = false;
+ _globals[kRingIsOnFinger] = false;
+ _globals[kHeListened] = false;
+ _globals[kKnockedOverHead] = false;
+ _globals[kObservedPhan104] = false;
+ _globals[kReadBook] = false;
+ _globals[kCanFindBookInLibrary] = false;
+ _globals[kLookedAtSkullFace] = false;
+ _globals[kScannedBookcase] = false;
+ _globals[kRanConvIn205] = false;
+ _globals[kDoneRichConv203] = false;
+ _globals[kHintThatDaaeIsHome1] = false;
+ _globals[kHintThatDaaeIsHome2] = false;
+ _globals[kMakeBrieLeave203] = false;
+ _globals[kMakeRichLeave203] = false;
+ _globals[kCameFromFade] = false;
+ _globals[kChristineToldEnvelope] = false;
+ _globals[kLeaveAngelMusicOn] = false;
+ _globals[kDoorIn409IsOpen] = false;
+ _globals[kUnknown] = false;
+ _globals[kCobwebIsCut] = false;
+ _globals[kChristineIsInBoat] = false;
+ _globals[kRightDoorIsOpen504] = false;
+ _globals[kChrisLeft505] = false;
+ _globals[kChrisWillTakeSeat] = true;
+ _globals[kFlickedLever1] = 0;
+ _globals[kFlickedLever2] = 0;
+ _globals[kFlickedLever3] = 0;
+ _globals[kFlickedLever4] = 0;
+ _globals[kPlayerScore] = 0;
+ _globals[kPlayerScoreFlags] = 0;
+
+ _globals[kMusicSelected] = _vm->getRandomNumber(1, 4);
+
+ _player._spritesPrefix = "RAL"; // Fixed prefix
Player::preloadSequences("RAL", 1);
}
@@ -108,6 +151,11 @@ void GamePhantom::checkShowDialog() {
// TODO: Copied from Nebular
if (_vm->_dialogs->_pendingDialog && _player._stepEnabled && !_globals[5]) {
_player.releasePlayerSprites();
+
+ // HACK: Skip the main menu (since it'll then try to show Rex's main menu)
+ if (_vm->_dialogs->_pendingDialog == DIALOG_MAIN_MENU)
+ _vm->_dialogs->_pendingDialog = DIALOG_NONE;
+
_vm->_dialogs->showDialog();
_vm->_dialogs->_pendingDialog = DIALOG_NONE;
}
diff --git a/engines/mads/phantom/globals_phantom.h b/engines/mads/phantom/globals_phantom.h
index 44d8c9e4bc..c23b53cdf5 100644
--- a/engines/mads/phantom/globals_phantom.h
+++ b/engines/mads/phantom/globals_phantom.h
@@ -33,23 +33,91 @@ namespace MADS {
namespace Phantom {
enum GlobalId {
+ // Global variables
+
kWalkerTiming = 0,
-// kWalkerTiming0 = 1,
+ kWalkerTiming2 = 1,
+ kStopWalkerDisabled = 2, // disable walker idle animations
+ kTempInterface = 3,
+ kWalkerConverse = 4, // conversation started with an NPC
+ kWalkerConverseState = 5,
+ kWalkerConverseNow = 6,
kCurrentYear = 10, // current year (1881 or 1993)
-
- //kTalkInanimateCount = 4,
-
- /* Section #1 variables */
-
- /* Section #2 variables */
-
- /* Section #3 Variables */
-
- /* Section #4 Variables */
-
- /* Section #5 Variables */
-
+ kMusicSelected = 11,
+ kPlayerScore = 12,
+ kPlayerScoreFlags = 13,
+ kDoneBrieConv203 = 14,
+ kLanternStatus = 15,
+
+ // Section #1 variables
+ kLeaveAngelMusicOn = 19,
+ kTrapDoorStatus = 20,
+ kChristineDoorStatus = 21,
+ kSandbagStatus = 22,
+ kChrisFStatus = 23,
+ kBrieTalkStatus = 24,
+ kJuliesDoor = 25,
+ kPrompterStandStatus = 26,
+ kChrisDStatus = 27,
+ kJulieNameIsKnown = 28,
+ kChrisKickedRaoulOut = 29,
+ kJacquesNameIsKnown = 30,
+ kJacquesStatus = 31,
+ kFlorentNameIsKnown = 32,
+ kCharlesNameIsKnown = 33,
+ kRoom103104Transition = 34,
+ kObservedPhan104 = 35,
+ kDeathLocation = 36,
+ kMakeBrieLeave203 = 37,
+ kHintThatDaaeIsHome1 = 38,
+ kHintThatDaaeIsHome2 = 39,
+
+ // Section #2 variables
+ kChristineToldEnvelope = 40,
+ kReadBook = 41,
+ kScannedBookcase = 42,
+ kRanConvIn205 = 43,
+ kDoorsIn205 = 44,
+ kPanelIn206 = 45,
+ kMadameNameIsKnown = 46,
+ kMadameGiryLocation = 47,
+ kLookedAtCase = 48,
+ kMadameGiryShowsUp = 49,
+ kDoneRichConv203 = 50,
+ kCameFromFade = 51,
+ kTicketPeoplePresent = 52,
+ kDegasNameIsKnown = 53,
+ kTempVar = 54,
+ kFlickedLever1 = 55,
+ kFlickedLever2 = 56,
+ kFlickedLever3 = 57,
+ kFlickedLever4 = 58,
+
+ // Section #3 Variables
+ kTopFloorLocked = 60,
+
+ // Section #4 Variables
+ kCatacombsRoom = 80,
+ // TODO
+ kDoorIn409IsOpen = 93,
+ kUnknown = 94, // TODO
+ kCobwebIsCut = 95,
+
+ // Section #5 Variables
+ kChristineIsInBoat = 100,
+ kChrisWillTakeSeat = 101,
+ kRightDoorIsOpen504 = 102,
+ kCoffinStatus = 103,
+ kChrisLeft505 = 104,
+ kKnockedOverHead = 105,
+ kFightStatus = 106,
+ kHeListened = 107,
+ kCanFindBookInLibrary = 108,
+ kRingIsOnFinger = 109,
+ kLookedAtSkullFace = 110,
+ kCableHookWasSeparate = 111,
+ kMakeRichLeave203 = 112
};
class PhantomGlobals : public Globals {
diff --git a/engines/mads/phantom/phantom_scenes.cpp b/engines/mads/phantom/phantom_scenes.cpp
index 57c2bb2c9b..f7f4d154df 100644
--- a/engines/mads/phantom/phantom_scenes.cpp
+++ b/engines/mads/phantom/phantom_scenes.cpp
@@ -43,7 +43,7 @@ SceneLogic *SceneFactory::createScene(MADSEngine *vm) {
switch (scene._nextSceneId) {
// Scene group #1 (theater, stage and dressing rooms)
case 101: // seats
- return new DummyScene(vm); // TODO
+ return new Scene101(vm);
case 102: // music stands
return new Scene102(vm);
case 103: // below stage
diff --git a/engines/mads/phantom/phantom_scenes.h b/engines/mads/phantom/phantom_scenes.h
index 55218f219a..c0a823ae06 100644
--- a/engines/mads/phantom/phantom_scenes.h
+++ b/engines/mads/phantom/phantom_scenes.h
@@ -35,7 +35,24 @@ namespace MADS {
namespace Phantom {
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_CLIMB_DOWN = 0x21,
+ VERB_CLIMB_INTO = 0x22,
+ VERB_CLIMB_THROUGH = 0x23,
+ VERB_EXIT_TO = 0x37,
+ VERB_JUMP_INTO = 0x53,
VERB_LOOK_AT = 0x60,
+ VERB_LOOK_THROUGH = 0x61,
VERB_TURN_OFF = 0x95,
VERB_TURN_ON = 0x96,
VERB_UNLOCK = 0x97,
@@ -43,22 +60,14 @@ enum Verb {
VERB_WALK_DOWN = 0x9A,
VERB_WALK_THROUGH = 0x9B,
VERB_WALK_UP = 0x9C,
+ VERB_CLIMB_UP = 0xA5,
+ VERB_WALK_ONTO = 0xA6,
+ VERB_WALK = 0xA7
};
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_ = 0xE,
NOUN_IN_ONE = 0xF,
NOUN_IN_TWO = 0x10,
@@ -78,9 +87,6 @@ enum Noun {
NOUN_CEILING = 0x1E,
NOUN_CHAIR = 0x1F,
NOUN_CIRCULAR_STAIRCASE = 0x20,
- NOUN_CLIMB_DOWN = 0x21,
- NOUN_CLIMB_INTO = 0x22,
- NOUN_CLIMB_THROUGH = 0x23,
NOUN_COLUMN_PROP = 0x24,
NOUN_CONDUCTORS_STAND = 0x25,
NOUN_CORRIDOR = 0x26,
@@ -100,7 +106,6 @@ enum Noun {
NOUN_EXIT = 0x34,
NOUN_EXIT_DOWN = 0x35,
NOUN_EXIT_SIGN = 0x36,
- NOUN_EXIT_TO = 0x37,
NOUN_EXIT_TO_BACKSTAGE = 0x38,
NOUN_EXIT_TO_CELLAR = 0x39,
NOUN_EXIT_TO_CORRIDOR = 0x3A,
@@ -128,7 +133,6 @@ enum Noun {
NOUN_HOUSE = 0x50,
NOUN_IN_ONE2 = 0x51,
NOUN_IN_TWO2 = 0x52,
- NOUN_JUMP_INTO = 0x53,
NOUN_JUNK = 0x54,
NOUN_KEY = 0x55,
NOUN_LAMP = 0x56,
@@ -141,7 +145,6 @@ enum Noun {
NOUN_LOCK = 0x5D,
NOUN_LOCKING_RAIL = 0x5E,
NOUN_LOCKRAIL = 0x5F,
- NOUN_LOOK_THROUGH = 0x61,
NOUN_MANNEQUINS = 0x62,
NOUN_MIRROR = 0x63,
NOUN_MUMMY_PROP = 0x64,
@@ -202,9 +205,6 @@ enum Noun {
NOUN_WEDDING_RING = 0xA2,
NOUN_YELLOW_FRAME = 0xA3,
NOUN_PROP = 0xA4,
- NOUN_CLIMB_UP = 0xA5,
- NOUN_WALK_ONTO = 0xA6,
- NOUN_WALK = 0xA7,
NOUN_LEFT_DOOR = 0xA8,
NOUN_RIGHT_DOOR = 0xA9,
NOUN_DOOR_TO_PIT = 0xAA,
diff --git a/engines/mads/phantom/phantom_scenes1.cpp b/engines/mads/phantom/phantom_scenes1.cpp
index b4035dc68b..2d991fd3bc 100644
--- a/engines/mads/phantom/phantom_scenes1.cpp
+++ b/engines/mads/phantom/phantom_scenes1.cpp
@@ -42,6 +42,92 @@ void Scene1xx::sceneEntrySound() {
/*------------------------------------------------------------------------*/
+Scene101::Scene101(MADSEngine *vm) : Scene1xx(vm) {
+
+}
+
+void Scene101::synchronize(Common::Serializer &s) {
+ Scene1xx::synchronize(s);
+
+}
+
+void Scene101::setup() {
+ //setPlayerSpritesPrefix();
+ setAAName();
+}
+
+void Scene101::enter() {
+ // TODO
+
+ if (_globals[kCurrentYear] == 1993) {
+ _globals._spriteIndexes[0] = _scene->_sprites.addSprites(formAnimName('z', -1));
+ // TODO
+ //_scene->_sequences.setDepth(_globals._sequenceIndexes[0], 14);
+ } else {
+ // TODO
+ }
+
+ // TODO
+}
+
+void Scene101::step() {
+ // TODO
+}
+
+void Scene101::preActions() {
+ if (_action.isAction(VERB_EXIT_TO, NOUN_ORCHESTRA_PIT)) {
+ // TODO: Handle Brie
+ _game._player._walkOffScreenSceneId = 102;
+ } 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)
+ _game._player._needToWalk = false;
+ }
+
+ // TODO
+}
+
+void Scene101::actions() {
+ // TODO: Brie conversation
+
+ // TODO: Look around
+
+ 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)) {
+ _vm->_dialogs->show(10113);
+ } else if (_action.isObject(NOUN_BACK_WALL)) {
+ _vm->_dialogs->show(10114);
+ } else if (_action.isObject(NOUN_SIDE_WALL)) {
+ _vm->_dialogs->show(10115);
+ } else if (_action.isObject(NOUN_SEATS)) {
+ // TODO: Finish this
+ _vm->_dialogs->show(10116);
+ } else if (_action.isObject(NOUN_GRAND_FOYER)) {
+ _vm->_dialogs->show(10117);
+ } else if (_action.isObject(NOUN_ORCHESTRA_PIT)) {
+ _vm->_dialogs->show(10118);
+ } 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;
+ }
+}
+
+/*------------------------------------------------------------------------*/
+
Scene102::Scene102(MADSEngine *vm) : Scene1xx(vm) {
_animRunningFl = false;
}
@@ -60,22 +146,34 @@ void Scene102::setup() {
void Scene102::enter() {
_animRunningFl = false;
- // TODO: Load sprite series
+ _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);
+ } else {
+ // TODO
+ }
if (_scene->_priorSceneId == 101) {
_game._player._playerPos = Common::Point(97, 79);
_game._player._facing = FACING_SOUTHEAST;
// TODO
+ _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) {
_game._player._playerPos = Common::Point(282, 145);
_game._player._facing = FACING_WEST;
- // TODO: Door closing animation
_animRunningFl = true;
+ // TODO: Door closing animation
} else if (_scene->_priorSceneId == -1) {
// TODO
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[2], 14);
}
sceneEntrySound();
@@ -109,6 +207,8 @@ void Scene102::actions() {
if (_animRunningFl) {
// TODO
} else {
+ _scene->_nextSceneId = 103; // FIXME: temporary HACK - remove!
+
switch (_game._trigger) {
case 70: // try again
case 0:
diff --git a/engines/mads/phantom/phantom_scenes1.h b/engines/mads/phantom/phantom_scenes1.h
index ef2cdb7aa0..0f5f56a4cf 100644
--- a/engines/mads/phantom/phantom_scenes1.h
+++ b/engines/mads/phantom/phantom_scenes1.h
@@ -53,6 +53,21 @@ public:
Scene1xx(MADSEngine *vm) : PhantomScene(vm) {}
};
+class Scene101 : public Scene1xx {
+private:
+ // TODO
+
+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:
bool _animRunningFl;
diff --git a/engines/mads/sound.cpp b/engines/mads/sound.cpp
index 7b9388eee3..4a35edb80f 100644
--- a/engines/mads/sound.cpp
+++ b/engines/mads/sound.cpp
@@ -21,6 +21,7 @@
*/
#include "audio/audiostream.h"
+#include "audio/fmopl.h"
#include "audio/decoders/raw.h"
#include "common/memstream.h"
#include "mads/sound.h"
@@ -39,7 +40,7 @@ SoundManager::SoundManager(MADSEngine *vm, Audio::Mixer *mixer) {
_masterVolume = 255;
_opl = OPL::Config::create();
- _opl->init(11025);
+ _opl->init();
// Validate sound files
switch (_vm->getGameID()) {
diff --git a/engines/mads/sound.h b/engines/mads/sound.h
index 16128f8284..9882f65e5a 100644
--- a/engines/mads/sound.h
+++ b/engines/mads/sound.h
@@ -37,7 +37,7 @@ class SoundManager {
private:
MADSEngine *_vm;
Audio::Mixer *_mixer;
- FM_OPL *_opl;
+ OPL::OPL *_opl;
Nebular::ASound *_driver;
bool _pollSoundEnabled;
bool _soundPollFlag;
diff --git a/engines/mohawk/console.cpp b/engines/mohawk/console.cpp
index d49f3e8637..9b5bae78be 100644
--- a/engines/mohawk/console.cpp
+++ b/engines/mohawk/console.cpp
@@ -248,9 +248,9 @@ bool MystConsole::Cmd_PlayMovie(int argc, const char **argv) {
return true;
}
- int8 stackNum = 0;
-
+ Common::String fileName;
if (argc == 3 || argc > 4) {
+ int8 stackNum = 0;
for (byte i = 1; i <= ARRAYSIZE(mystStackNames); i++)
if (!scumm_stricmp(argv[2], mystStackNames[i - 1])) {
stackNum = i;
@@ -261,16 +261,27 @@ bool MystConsole::Cmd_PlayMovie(int argc, const char **argv) {
debugPrintf("\'%s\' is not a stack name!\n", argv[2]);
return true;
}
+
+ fileName = _vm->wrapMovieFilename(argv[1], stackNum - 1);
+ } else {
+ fileName = argv[1];
}
- if (argc == 2)
- _vm->_video->playMovie(argv[1], 0, 0);
- else if (argc == 3)
- _vm->_video->playMovie(_vm->wrapMovieFilename(argv[1], stackNum - 1), 0, 0);
- else if (argc == 4)
- _vm->_video->playMovie(argv[1], atoi(argv[2]), atoi(argv[3]));
- else
- _vm->_video->playMovie(_vm->wrapMovieFilename(argv[1], stackNum - 1), atoi(argv[3]), atoi(argv[4]));
+ VideoHandle handle = _vm->_video->playMovie(fileName);
+ if (!handle) {
+ debugPrintf("Failed to open movie '%s'\n", fileName.c_str());
+ return true;
+ }
+
+ if (argc == 4) {
+ handle->setX(atoi(argv[2]));
+ handle->setY(atoi(argv[3]));
+ } else if (argc > 4) {
+ handle->setX(atoi(argv[3]));
+ handle->setY(atoi(argv[4]));
+ } else {
+ handle->center();
+ }
return false;
}
diff --git a/engines/mohawk/detection_tables.h b/engines/mohawk/detection_tables.h
index 7632cde294..6bb836b5b8 100644
--- a/engines/mohawk/detection_tables.h
+++ b/engines/mohawk/detection_tables.h
@@ -1379,6 +1379,22 @@ static const MohawkGameDescription gameDescriptions[] = {
"GRANDMA.EXE"
},
+ // Just Grandma and Me 1.0, Macintosh
+ {
+ {
+ "grandma",
+ "v1.0",
+ AD_ENTRY1("BookOutline", "9162483da06179e76f4a082412245efa"),
+ Common::EN_ANY,
+ Common::kPlatformMacintosh,
+ ADGF_NO_FLAGS,
+ GUIO1(GUIO_NOASPECT)
+ },
+ GType_LIVINGBOOKSV1,
+ GF_LB_10,
+ 0
+ },
+
// Just Grandma and Me 1.1 Mac
// From eisnerguy1 in bug#3610725
{
diff --git a/engines/mohawk/livingbooks.cpp b/engines/mohawk/livingbooks.cpp
index 998ef048f6..5af8fac901 100644
--- a/engines/mohawk/livingbooks.cpp
+++ b/engines/mohawk/livingbooks.cpp
@@ -363,6 +363,44 @@ void MohawkEngine_LivingBooks::destroyPage() {
_focus = NULL;
}
+// Replace any colons (originally a slash) with another character
+static Common::String replaceColons(const Common::String &in, char replace) {
+ Common::String out;
+
+ for (uint32 i = 0; i < in.size(); i++) {
+ if (in[i] == ':')
+ out += replace;
+ else
+ out += in[i];
+ }
+
+ return out;
+}
+
+// Helper function to assist in opening pages
+static bool tryOpenPage(Archive *archive, const Common::String &fileName) {
+ // Try the plain file name first
+ if (archive->openFile(fileName))
+ return true;
+
+ // No colons, then bail out
+ if (!fileName.contains(':'))
+ return false;
+
+ // Try replacing colons with underscores (in case the original was
+ // a Mac version and had slashes not as a separator).
+ if (archive->openFile(replaceColons(fileName, '_')))
+ return true;
+
+ // Try replacing colons with slashes (in case the original was a Mac
+ // version and had slashes as a separator).
+ if (archive->openFile(replaceColons(fileName, '/')))
+ return true;
+
+ // Failed to open the archive
+ return false;
+}
+
bool MohawkEngine_LivingBooks::loadPage(LBMode mode, uint page, uint subpage) {
destroyPage();
@@ -410,7 +448,7 @@ bool MohawkEngine_LivingBooks::loadPage(LBMode mode, uint page, uint subpage) {
}
Archive *pageArchive = createArchive();
- if (!filename.empty() && pageArchive->openFile(filename)) {
+ if (!filename.empty() && tryOpenPage(pageArchive, filename)) {
_page = new LBPage(this);
_page->open(pageArchive, 1000);
} else {
@@ -824,18 +862,18 @@ int MohawkEngine_LivingBooks::getIntFromConfig(const Common::String &section, co
Common::String MohawkEngine_LivingBooks::getFileNameFromConfig(const Common::String &section, const Common::String &key, Common::String &leftover) {
Common::String string = getStringFromConfig(section, key, leftover);
- Common::String x;
- uint32 i = 0;
if (string.hasPrefix("//")) {
// skip "//CD-ROM Title/" prefixes which we don't care about
- i = 3;
+ uint i = 3;
while (i < string.size() && string[i - 1] != '/')
i++;
+
+ // Already uses slashes, no need to convert further
+ return string.c_str() + i;
}
- x = string.c_str() + i;
- return (getPlatform() == Common::kPlatformMacintosh) ? convertMacFileName(x) : convertWinFileName(x);
+ return (getPlatform() == Common::kPlatformMacintosh) ? convertMacFileName(string) : convertWinFileName(string);
}
Common::String MohawkEngine_LivingBooks::removeQuotesFromString(const Common::String &string, Common::String &leftover) {
@@ -866,8 +904,10 @@ Common::String MohawkEngine_LivingBooks::convertMacFileName(const Common::String
for (uint32 i = 0; i < string.size(); i++) {
if (i == 0 && string[i] == ':') // First character should be ignored (another colon)
continue;
- if (string[i] == ':')
+ if (string[i] == ':') // Directory separator
filename += '/';
+ else if (string[i] == '/') // Literal slash
+ filename += ':'; // Replace by colon, as used by Mac OS X for slash
else
filename += string[i];
}
@@ -3772,7 +3812,7 @@ LBMovieItem::~LBMovieItem() {
void LBMovieItem::update() {
if (_playing) {
VideoHandle videoHandle = _vm->_video->findVideoHandle(_resourceId);
- if (videoHandle == NULL_VID_HANDLE || _vm->_video->endOfVideo(videoHandle))
+ if (!videoHandle || videoHandle->endOfVideo())
done(true);
}
@@ -3783,8 +3823,11 @@ bool LBMovieItem::togglePlaying(bool playing, bool restart) {
if (playing) {
if ((_loaded && _enabled && _globalEnabled) || _phase == kLBPhaseNone) {
debug("toggled video for phase %d", _phase);
- _vm->_video->playMovie(_resourceId, _rect.left, _rect.top);
+ VideoHandle handle = _vm->_video->playMovie(_resourceId);
+ if (!handle)
+ error("Failed to open tMOV %d", _resourceId);
+ handle->moveTo(_rect.left, _rect.top);
return true;
}
}
@@ -3808,9 +3851,9 @@ bool LBMiniGameItem::togglePlaying(bool playing, bool restart) {
// just skip to the most logical page. For optional minigames, this
// will return the player to the previous page. For mandatory minigames,
// this will send the player to the next page.
- // TODO: Document mini games from Arthur's Reading Race
- uint16 destPage;
+ uint16 destPage = 0;
+ bool returnToMenu = false;
// Figure out what minigame we have and bring us back to a page where
// the player can continue
@@ -3820,13 +3863,31 @@ bool LBMiniGameItem::togglePlaying(bool playing, bool restart) {
destPage = 5;
else if (_desc == "Fall") // Green Eggs and Ham: Fall minigame
destPage = 13;
+ else if (_desc == "MagicWrite3") // Arthur's Reading Race: "Let Me Write" minigame (Page 3)
+ destPage = 3;
+ else if (_desc == "MagicWrite4") // Arthur's Reading Race: "Let Me Write" minigame (Page 4)
+ destPage = 4;
+ else if (_desc == "MagicSpy5") // Arthur's Reading Race: "I Spy" minigame (Page 5)
+ destPage = 5;
+ else if (_desc == "MagicSpy6") // Arthur's Reading Race: "I Spy" minigame (Page 6)
+ destPage = 6;
+ else if (_desc == "MagicWrite7") // Arthur's Reading Race: "Let Me Write" minigame (Page 7)
+ destPage = 7;
+ else if (_desc == "MagicSpy8") // Arthur's Reading Race: "I Spy" minigame (Page 8)
+ destPage = 8;
+ else if (_desc == "MagicRace") // Arthur's Reading Race: Race minigame
+ returnToMenu = true;
else
error("Unknown minigame '%s'", _desc.c_str());
GUI::MessageDialog dialog(Common::String::format("The '%s' minigame is not supported yet.", _desc.c_str()));
dialog.runModal();
- _vm->addNotifyEvent(NotifyEvent(kLBNotifyChangePage, destPage));
+ // Go back to the menu if requested, otherwise go to the requested page
+ if (returnToMenu)
+ _vm->addNotifyEvent(NotifyEvent(kLBNotifyGoToControls, 1));
+ else
+ _vm->addNotifyEvent(NotifyEvent(kLBNotifyChangePage, destPage));
return false;
}
@@ -3863,7 +3924,7 @@ void LBProxyItem::load() {
debug(1, "LBProxyItem loading archive '%s' with id %d", filename.c_str(), baseId);
Archive *pageArchive = _vm->createArchive();
- if (!pageArchive->openFile(filename))
+ if (!tryOpenPage(pageArchive, filename))
error("failed to open archive '%s' (for proxy '%s')", filename.c_str(), _desc.c_str());
_page = new LBPage(_vm);
_page->open(pageArchive, baseId);
diff --git a/engines/mohawk/livingbooks_code.cpp b/engines/mohawk/livingbooks_code.cpp
index 6dcd8c3ce7..b5ea547414 100644
--- a/engines/mohawk/livingbooks_code.cpp
+++ b/engines/mohawk/livingbooks_code.cpp
@@ -842,8 +842,8 @@ CodeCommandInfo generalCommandInfo[NUM_GENERAL_COMMANDS] = {
{ "bottom", &LBCode::cmdBottom },
// 0x10
{ "right", &LBCode::cmdRight },
- { "xpos", 0 },
- { "ypos", 0 },
+ { "xpos", &LBCode::cmdXPos },
+ { "ypos", &LBCode::cmdYPos },
{ "playFrom", 0 },
{ "move", &LBCode::cmdMove },
{ 0, 0 },
@@ -852,13 +852,13 @@ CodeCommandInfo generalCommandInfo[NUM_GENERAL_COMMANDS] = {
{ "resetDragParams", 0 },
{ "enableRollover", &LBCode::cmdUnimplemented /* FIXME */ },
{ "setCursor", 0 },
- { "width", 0 },
- { "height", 0 },
+ { "width", &LBCode::cmdWidth },
+ { "height", &LBCode::cmdHeight },
{ "getFrameBounds", 0 }, // also "getFrameRect"
{ "traceRect", 0 },
{ "sqrt", 0 },
// 0x20
- { "deleteVar", 0 },
+ { "deleteVar", &LBCode::cmdDeleteVar },
{ "saveVars", 0 },
{ "scriptLink", 0 },
{ "setViewOrigin", &LBCode::cmdUnimplemented },
@@ -1131,6 +1131,38 @@ void LBCode::cmdRight(const Common::Array<LBValue> &params) {
_stack.push(rect.right);
}
+void LBCode::cmdXPos(const Common::Array<LBValue> &params) {
+ if (params.size() != 1)
+ error("too many parameters (%d) to xpos", params.size());
+
+ Common::Point point = params[0].toPoint();
+ _stack.push(point.x);
+}
+
+void LBCode::cmdYPos(const Common::Array<LBValue> &params) {
+ if (params.size() != 1)
+ error("too many parameters (%d) to ypos", params.size());
+
+ Common::Point point = params[0].toPoint();
+ _stack.push(point.y);
+}
+
+void LBCode::cmdWidth(const Common::Array<LBValue> &params) {
+ if (params.size() > 1)
+ error("too many parameters (%d) to width", params.size());
+
+ Common::Rect rect = getRectFromParams(params);
+ _stack.push(rect.width());
+}
+
+void LBCode::cmdHeight(const Common::Array<LBValue> &params) {
+ if (params.size() > 1)
+ error("too many parameters (%d) to height", params.size());
+
+ Common::Rect rect = getRectFromParams(params);
+ _stack.push(rect.height());
+}
+
void LBCode::cmdMove(const Common::Array<LBValue> &params) {
if (params.size() != 1 && params.size() != 2)
error("incorrect number of parameters (%d) to move", params.size());
@@ -1263,6 +1295,14 @@ void LBCode::cmdGetProperty(const Common::Array<LBValue> &params) {
_stack.push(target->_variables[name]);
}
+void LBCode::cmdDeleteVar(const Common::Array<LBValue> &params) {
+ if (params.size() != 1)
+ error("incorrect number of parameters (%d) to deleteVar", params.size());
+
+ const Common::String &string = params[0].toString();
+ _vm->_variables.erase(string);
+}
+
void LBCode::cmdExec(const Common::Array<LBValue> &params) {
if (params.size() != 1)
error("incorrect number of parameters (%d) to exec", params.size());
@@ -1706,6 +1746,10 @@ uint LBCode::parseCode(const Common::String &source) {
if (token != ' ' && token != '(' && wasFunction)
error("while parsing script '%s', encountered incomplete function call", source.c_str());
+ // Skip C++-style comments
+ if (token == '/' && lookahead == '/')
+ break;
+
// First, we check for simple operators.
for (uint i = 0; i < NUM_LB_OPERATORS; i++) {
if (token != operators[i].token)
@@ -1736,6 +1780,7 @@ uint LBCode::parseCode(const Common::String &source) {
switch (token) {
// whitespace
case ' ':
+ case '\t':
// ignore
break;
// literal string
diff --git a/engines/mohawk/livingbooks_code.h b/engines/mohawk/livingbooks_code.h
index 080377ce99..6f6297d592 100644
--- a/engines/mohawk/livingbooks_code.h
+++ b/engines/mohawk/livingbooks_code.h
@@ -263,6 +263,10 @@ public:
void cmdLeft(const Common::Array<LBValue> &params);
void cmdBottom(const Common::Array<LBValue> &params);
void cmdRight(const Common::Array<LBValue> &params);
+ void cmdXPos(const Common::Array<LBValue> &params);
+ void cmdYPos(const Common::Array<LBValue> &params);
+ void cmdWidth(const Common::Array<LBValue> &params);
+ void cmdHeight(const Common::Array<LBValue> &params);
void cmdMove(const Common::Array<LBValue> &params);
void cmdSetDragParams(const Common::Array<LBValue> &params);
void cmdNewList(const Common::Array<LBValue> &params);
@@ -273,6 +277,7 @@ public:
void cmdDeleteAt(const Common::Array<LBValue> &params);
void cmdSetProperty(const Common::Array<LBValue> &params);
void cmdGetProperty(const Common::Array<LBValue> &params);
+ void cmdDeleteVar(const Common::Array<LBValue> &params);
void cmdExec(const Common::Array<LBValue> &params);
void cmdReturn(const Common::Array<LBValue> &params);
void cmdSetPlayParams(const Common::Array<LBValue> &params);
diff --git a/engines/mohawk/myst_areas.cpp b/engines/mohawk/myst_areas.cpp
index 4a3001774a..7a9596d8e0 100644
--- a/engines/mohawk/myst_areas.cpp
+++ b/engines/mohawk/myst_areas.cpp
@@ -223,20 +223,26 @@ VideoHandle MystResourceType6::playMovie() {
VideoHandle handle = _vm->_video->findVideoHandle(_videoFile);
// If the video is not running, play it
- if (handle == NULL_VID_HANDLE || _vm->_video->endOfVideo(handle)) {
- handle = _vm->_video->playMovie(_videoFile, _left, _top, _loop);
+ if (!handle || handle->endOfVideo()) {
+ handle = _vm->_video->playMovie(_videoFile);
+ if (!handle)
+ error("Failed to open '%s'", _videoFile.c_str());
+
+ handle->moveTo(_left, _top);
+ handle->setLooping(_loop != 0);
+
if (_direction == -1) {
- _vm->_video->seekToTime(handle, _vm->_video->getDuration(handle));
- _vm->_video->setVideoRate(handle, -1);
+ handle->seek(handle->getDuration());
+ handle->setRate(-1);
}
} else {
// Resume the video
- _vm->_video->pauseMovie(handle, false);
+ handle->pause(false);
}
if (_playBlocking) {
_vm->_video->waitUntilMovieEnds(handle);
- handle = NULL_VID_HANDLE;
+ return VideoHandle();
}
return handle;
@@ -249,13 +255,13 @@ void MystResourceType6::handleCardChange() {
bool MystResourceType6::isPlaying() {
VideoHandle handle = _vm->_video->findVideoHandle(_videoFile);
- return handle != NULL_VID_HANDLE && !_vm->_video->endOfVideo(handle);
+ return handle && !handle->endOfVideo();
}
void MystResourceType6::pauseMovie(bool pause) {
VideoHandle handle = _vm->_video->findVideoHandle(_videoFile);
- if (handle != NULL_VID_HANDLE && !_vm->_video->endOfVideo(handle))
- _vm->_video->pauseMovie(handle, pause);
+ if (handle && !handle->endOfVideo())
+ handle->pause(pause);
}
MystResourceType7::MystResourceType7(MohawkEngine_Myst *vm, Common::SeekableReadStream *rlstStream, MystResource *parent) : MystResource(vm, rlstStream, parent) {
diff --git a/engines/mohawk/myst_stacks/channelwood.cpp b/engines/mohawk/myst_stacks/channelwood.cpp
index 2dd5745550..dfa15a9b6c 100644
--- a/engines/mohawk/myst_stacks/channelwood.cpp
+++ b/engines/mohawk/myst_stacks/channelwood.cpp
@@ -299,13 +299,17 @@ bool Channelwood::pipeChangeValve(bool open, uint16 mask) {
void Channelwood::o_bridgeToggle(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
debugC(kDebugScript, "Opcode %d: Bridge rise / skink video", op);
- VideoHandle bridge = _vm->_video->playMovie(_vm->wrapMovieFilename("bridge", kChannelwoodStack), 292, 203);
+ VideoHandle bridge = _vm->_video->playMovie(_vm->wrapMovieFilename("bridge", kChannelwoodStack));
+ if (!bridge)
+ error("Failed to open 'bridge' movie");
+
+ bridge->moveTo(292, 203);
// Toggle bridge state
if (_state.waterPumpBridgeState)
- _vm->_video->setVideoBounds(bridge, Audio::Timestamp(0, 3050, 600), Audio::Timestamp(0, 6100, 600));
+ bridge->setBounds(Audio::Timestamp(0, 3050, 600), Audio::Timestamp(0, 6100, 600));
else
- _vm->_video->setVideoBounds(bridge, Audio::Timestamp(0, 0, 600), Audio::Timestamp(0, 3050, 600));
+ bridge->setBounds(Audio::Timestamp(0, 0, 600), Audio::Timestamp(0, 3050, 600));
_vm->_video->waitUntilMovieEnds(bridge);
}
@@ -317,13 +321,17 @@ void Channelwood::o_pipeExtend(uint16 op, uint16 var, uint16 argc, uint16 *argv)
debugC(kDebugScript, "\tsoundId: %d", soundId);
_vm->_sound->replaceSoundMyst(soundId);
- VideoHandle pipe = _vm->_video->playMovie(_vm->wrapMovieFilename("pipebrid", kChannelwoodStack), 267, 170);
+ VideoHandle pipe = _vm->_video->playMovie(_vm->wrapMovieFilename("pipebrid", kChannelwoodStack));
+ if (!pipe)
+ error("Failed to open 'pipebrid' movie");
+
+ pipe->moveTo(267, 170);
// Toggle pipe state
if (_state.pipeState)
- _vm->_video->setVideoBounds(pipe, Audio::Timestamp(0, 3040, 600), Audio::Timestamp(0, 6080, 600));
+ pipe->setBounds(Audio::Timestamp(0, 3040, 600), Audio::Timestamp(0, 6080, 600));
else
- _vm->_video->setVideoBounds(pipe, Audio::Timestamp(0, 0, 600), Audio::Timestamp(0, 3040, 600));
+ pipe->setBounds(Audio::Timestamp(0, 0, 600), Audio::Timestamp(0, 3040, 600));
_vm->_video->waitUntilMovieEnds(pipe);
_vm->_sound->resumeBackgroundMyst();
@@ -605,23 +613,29 @@ void Channelwood::o_hologramMonitor(uint16 op, uint16 var, uint16 argc, uint16 *
_vm->_video->stopVideos();
+ VideoHandle handle;
+
switch (button) {
case 0:
- _vm->_video->playMovie(_vm->wrapMovieFilename("monalgh", kChannelwoodStack), 227, 70);
+ handle = _vm->_video->playMovie(_vm->wrapMovieFilename("monalgh", kChannelwoodStack));
break;
case 1:
- _vm->_video->playMovie(_vm->wrapMovieFilename("monamth", kChannelwoodStack), 227, 70);
+ handle = _vm->_video->playMovie(_vm->wrapMovieFilename("monamth", kChannelwoodStack));
break;
case 2:
- _vm->_video->playMovie(_vm->wrapMovieFilename("monasirs", kChannelwoodStack), 227, 70);
+ handle = _vm->_video->playMovie(_vm->wrapMovieFilename("monasirs", kChannelwoodStack));
break;
case 3:
- _vm->_video->playMovie(_vm->wrapMovieFilename("monsmsg", kChannelwoodStack), 227, 70);
+ handle = _vm->_video->playMovie(_vm->wrapMovieFilename("monsmsg", kChannelwoodStack));
break;
default:
warning("Opcode %d Control Variable Out of Range", op);
break;
}
+
+ // Move the video to the right location
+ if (handle)
+ handle->moveTo(227, 70);
}
}
diff --git a/engines/mohawk/myst_stacks/dni.cpp b/engines/mohawk/myst_stacks/dni.cpp
index 3eb3c40cbb..6ba0b63423 100644
--- a/engines/mohawk/myst_stacks/dni.cpp
+++ b/engines/mohawk/myst_stacks/dni.cpp
@@ -103,14 +103,14 @@ void Dni::o_handPage(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
VideoHandle atrus = _vm->_video->findVideoHandle(_video);
// Good ending and Atrus asked to give page
- if (_globals.ending == 1 && _vm->_video->getTime(atrus) > (uint)Audio::Timestamp(0, 6801, 600).msecs()) {
+ if (_globals.ending == 1 && atrus && atrus->getTime() > (uint)Audio::Timestamp(0, 6801, 600).msecs()) {
_globals.ending = 2;
_globals.heldPage = 0;
_vm->setMainCursor(kDefaultMystCursor);
// Play movie end (atrus leaving)
- _vm->_video->setVideoBounds(atrus, Audio::Timestamp(0, 14813, 600), _vm->_video->getDuration(atrus));
- _vm->_video->setVideoLooping(atrus, false);
+ atrus->setBounds(Audio::Timestamp(0, 14813, 600), atrus->getDuration());
+ atrus->setLooping(false);
_atrusLeft = true;
_waitForLoop = false;
@@ -121,8 +121,12 @@ void Dni::o_handPage(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
void Dni::atrusLeft_run() {
if (_vm->_system->getMillis() > _atrusLeftTime + 63333) {
_video = _vm->wrapMovieFilename("atrus2", kDniStack);
- VideoHandle atrus = _vm->_video->playMovie(_video, 215, 77);
- _vm->_video->setVideoBounds(atrus, Audio::Timestamp(0, 0, 600), Audio::Timestamp(0, 98000, 600));
+ VideoHandle atrus = _vm->_video->playMovie(_video);
+ if (!atrus)
+ error("Failed to open '%s'", _video.c_str());
+
+ atrus->moveTo(215, 77);
+ atrus->setBounds(Audio::Timestamp(0, 0, 600), Audio::Timestamp(0, 98000, 600));
_waitForLoop = true;
_loopStart = 73095;
@@ -139,9 +143,13 @@ void Dni::atrusLeft_run() {
void Dni::loopVideo_run() {
if (!_vm->_video->isVideoPlaying()) {
- VideoHandle atrus = _vm->_video->playMovie(_video, 215, 77);
- _vm->_video->setVideoBounds(atrus, Audio::Timestamp(0, _loopStart, 600), Audio::Timestamp(0, _loopEnd, 600));
- _vm->_video->setVideoLooping(atrus, true);
+ VideoHandle atrus = _vm->_video->playMovie(_video);
+ if (!atrus)
+ error("Failed to open '%s'", _video.c_str());
+
+ atrus->moveTo(215, 77);
+ atrus->setBounds(Audio::Timestamp(0, _loopStart, 600), Audio::Timestamp(0, _loopEnd, 600));
+ atrus->setLooping(true);
_waitForLoop = false;
}
@@ -155,14 +163,23 @@ void Dni::atrus_run() {
// Atrus asking for page
if (!_vm->_video->isVideoPlaying()) {
_video = _vm->wrapMovieFilename("atr1page", kDniStack);
- VideoHandle atrus = _vm->_video->playMovie(_video, 215, 77, true);
- _vm->_video->setVideoBounds(atrus, Audio::Timestamp(0, 7388, 600), Audio::Timestamp(0, 14700, 600));
+ VideoHandle atrus = _vm->_video->playMovie(_video);
+ if (!atrus)
+ error("Failed to open '%s'", _video.c_str());
+
+ atrus->moveTo(215, 77);
+ atrus->setLooping(true);
+ atrus->setBounds(Audio::Timestamp(0, 7388, 600), Audio::Timestamp(0, 14700, 600));
}
} else if (_globals.ending != 3 && _globals.ending != 4) {
if (_globals.heldPage == 13) {
_video = _vm->wrapMovieFilename("atr1page", kDniStack);
- VideoHandle atrus = _vm->_video->playMovie(_video, 215, 77);
- _vm->_video->setVideoBounds(atrus, Audio::Timestamp(0, 0, 600), Audio::Timestamp(0, 14700, 600));
+ VideoHandle atrus = _vm->_video->playMovie(_video);
+ if (!atrus)
+ error("Failed to open '%s'", _video.c_str());
+
+ atrus->moveTo(215, 77);
+ atrus->setBounds(Audio::Timestamp(0, 0, 600), Audio::Timestamp(0, 14700, 600));
_waitForLoop = true;
_loopStart = 7388;
@@ -173,8 +190,12 @@ void Dni::atrus_run() {
} else {
_video = _vm->wrapMovieFilename("atr1nopg", kDniStack);
- VideoHandle atrus = _vm->_video->playMovie(_video, 215, 77);
- _vm->_video->setVideoBounds(atrus, Audio::Timestamp(0, 0, 600), Audio::Timestamp(0, 46175, 600));
+ VideoHandle atrus = _vm->_video->playMovie(_video);
+ if (!atrus)
+ error("Failed to open '%s'", _video.c_str());
+
+ atrus->moveTo(215, 77);
+ atrus->setBounds(Audio::Timestamp(0, 0, 600), Audio::Timestamp(0, 46175, 600));
_waitForLoop = true;
_loopStart = 30656;
@@ -184,7 +205,12 @@ void Dni::atrus_run() {
_globals.ending = 3;
}
} else if (!_vm->_video->isVideoPlaying()) {
- _vm->_video->playMovie(_vm->wrapMovieFilename("atrwrite", kDniStack), 215, 77, true);
+ VideoHandle handle = _vm->_video->playMovie(_vm->wrapMovieFilename("atrwrite", kDniStack));
+ if (!handle)
+ error("Failed to open atrwrite movie");
+
+ handle->moveTo(215, 77);
+ handle->setLooping(true);
}
}
diff --git a/engines/mohawk/myst_stacks/intro.cpp b/engines/mohawk/myst_stacks/intro.cpp
index 2a33379198..dc66984398 100644
--- a/engines/mohawk/myst_stacks/intro.cpp
+++ b/engines/mohawk/myst_stacks/intro.cpp
@@ -98,10 +98,16 @@ void Intro::introMovies_run() {
// Play Intro Movies
// This is all quite messy...
+ VideoHandle handle;
+
switch (_introStep) {
case 0:
_introStep = 1;
- _vm->_video->playMovie(_vm->wrapMovieFilename("broder", kIntroStack));
+ handle = _vm->_video->playMovie(_vm->wrapMovieFilename("broder", kIntroStack));
+ if (!handle)
+ error("Failed to open broder movie");
+
+ handle->center();
break;
case 1:
if (!_vm->_video->isVideoPlaying())
@@ -109,7 +115,11 @@ void Intro::introMovies_run() {
break;
case 2:
_introStep = 3;
- _vm->_video->playMovie(_vm->wrapMovieFilename("cyanlogo", kIntroStack));
+ handle = _vm->_video->playMovie(_vm->wrapMovieFilename("cyanlogo", kIntroStack));
+ if (!handle)
+ error("Failed to open cyanlogo movie");
+
+ handle->center();
break;
case 3:
if (!_vm->_video->isVideoPlaying())
@@ -118,8 +128,13 @@ void Intro::introMovies_run() {
case 4:
_introStep = 5;
- if (!(_vm->getFeatures() & GF_DEMO)) // The demo doesn't have the intro video
- _vm->_video->playMovie(_vm->wrapMovieFilename("intro", kIntroStack));
+ if (!(_vm->getFeatures() & GF_DEMO)) { // The demo doesn't have the intro video
+ handle = _vm->_video->playMovie(_vm->wrapMovieFilename("intro", kIntroStack));
+ if (!handle)
+ error("Failed to open intro movie");
+
+ handle->center();
+ }
break;
case 5:
if (!_vm->_video->isVideoPlaying())
diff --git a/engines/mohawk/myst_stacks/mechanical.cpp b/engines/mohawk/myst_stacks/mechanical.cpp
index b5d1285435..ffcaa226c6 100644
--- a/engines/mohawk/myst_stacks/mechanical.cpp
+++ b/engines/mohawk/myst_stacks/mechanical.cpp
@@ -316,12 +316,16 @@ void Mechanical::o_snakeBoxTrigger(uint16 op, uint16 var, uint16 argc, uint16 *a
void Mechanical::o_fortressStaircaseMovie(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
debugC(kDebugScript, "Opcode %d: Play Stairs Movement Movie", op);
- VideoHandle staircase = _vm->_video->playMovie(_vm->wrapMovieFilename("hhstairs", kMechanicalStack), 174, 222);
+ VideoHandle staircase = _vm->_video->playMovie(_vm->wrapMovieFilename("hhstairs", kMechanicalStack));
+ if (!staircase)
+ error("Failed to open hhstairs movie");
+
+ staircase->moveTo(174, 222);
if (_state.staircaseState) {
- _vm->_video->setVideoBounds(staircase, Audio::Timestamp(0, 840, 600), Audio::Timestamp(0, 1680, 600));
+ staircase->setBounds(Audio::Timestamp(0, 840, 600), Audio::Timestamp(0, 1680, 600));
} else {
- _vm->_video->setVideoBounds(staircase, Audio::Timestamp(0, 0, 600), Audio::Timestamp(0, 840, 600));
+ staircase->setBounds(Audio::Timestamp(0, 0, 600), Audio::Timestamp(0, 840, 600));
}
_vm->_video->waitUntilMovieEnds(staircase);
@@ -571,8 +575,12 @@ void Mechanical::o_elevatorWindowMovie(uint16 op, uint16 var, uint16 argc, uint1
debugC(kDebugScript, "Opcode %d Movie Time Index %d to %d", op, startTime, endTime);
- VideoHandle window = _vm->_video->playMovie(_vm->wrapMovieFilename("ewindow", kMechanicalStack), 253, 0);
- _vm->_video->setVideoBounds(window, Audio::Timestamp(0, startTime, 600), Audio::Timestamp(0, endTime, 600));
+ VideoHandle window = _vm->_video->playMovie(_vm->wrapMovieFilename("ewindow", kMechanicalStack));
+ if (!window)
+ error("Failed to open ewindow movie");
+
+ window->moveTo(253, 0);
+ window->setBounds(Audio::Timestamp(0, startTime, 600), Audio::Timestamp(0, endTime, 600));
_vm->_video->waitUntilMovieEnds(window);
}
@@ -644,8 +652,12 @@ void Mechanical::o_elevatorTopMovie(uint16 op, uint16 var, uint16 argc, uint16 *
debugC(kDebugScript, "Opcode %d Movie Time Index %d to %d", op, startTime, endTime);
- VideoHandle window = _vm->_video->playMovie(_vm->wrapMovieFilename("hcelev", kMechanicalStack), 206, 38);
- _vm->_video->setVideoBounds(window, Audio::Timestamp(0, startTime, 600), Audio::Timestamp(0, endTime, 600));
+ VideoHandle window = _vm->_video->playMovie(_vm->wrapMovieFilename("hcelev", kMechanicalStack));
+ if (!window)
+ error("Failed to open hcelev movie");
+
+ window->moveTo(206, 38);
+ window->setBounds(Audio::Timestamp(0, startTime, 600), Audio::Timestamp(0, endTime, 600));
_vm->_video->waitUntilMovieEnds(window);
}
@@ -653,7 +665,7 @@ void Mechanical::o_fortressRotationSetPosition(uint16 op, uint16 var, uint16 arg
debugC(kDebugScript, "Opcode %d: Set fortress position", op);
VideoHandle gears = _fortressRotationGears->playMovie();
- uint32 moviePosition = Audio::Timestamp(_vm->_video->getTime(gears), 600).totalNumberOfFrames();
+ uint32 moviePosition = Audio::Timestamp(gears->getTime(), 600).totalNumberOfFrames();
// Myst ME short movie workaround, explained in o_fortressRotation_init
if (_fortressRotationShortMovieWorkaround) {
@@ -788,9 +800,8 @@ void Mechanical::o_elevatorRotation_init(uint16 op, uint16 var, uint16 argc, uin
void Mechanical::fortressRotation_run() {
VideoHandle gears = _fortressRotationGears->playMovie();
- double oldRate = _vm->_video->getVideoRate(gears).toDouble();
-
- uint32 moviePosition = Audio::Timestamp(_vm->_video->getTime(gears), 600).totalNumberOfFrames();
+ double oldRate = gears->getRate().toDouble();
+ uint32 moviePosition = Audio::Timestamp(gears->getTime(), 600).totalNumberOfFrames();
// Myst ME short movie workaround, explained in o_fortressRotation_init
if (_fortressRotationShortMovieWorkaround) {
@@ -837,19 +848,19 @@ void Mechanical::fortressRotation_run() {
newRate = CLIP<double>(newRate, -2.5, 2.5);
- _vm->_video->setVideoRate(gears, Common::Rational((int)(newRate * 1000.0), 1000));
+ gears->setRate(Common::Rational((int)(newRate * 1000.0), 1000));
_gearsWereRunning = true;
} else if (_gearsWereRunning) {
// The fortress has stopped. Set its new position
_fortressPosition = (moviePosition + 900) / 1800 % 4;
- _vm->_video->setVideoRate(gears, 0);
+ gears->setRate(0);
if (!_fortressRotationShortMovieWorkaround) {
- _vm->_video->seekToTime(gears, Audio::Timestamp(0, 1800 * _fortressPosition, 600));
+ gears->seek(Audio::Timestamp(0, 1800 * _fortressPosition, 600));
} else {
- _vm->_video->seekToTime(gears, Audio::Timestamp(0, 1800 * (_fortressPosition % 2), 600));
+ gears->seek(Audio::Timestamp(0, 1800 * (_fortressPosition % 2), 600));
}
_vm->_sound->playSoundBlocking(_fortressRotationSounds[_fortressPosition]);
@@ -864,9 +875,9 @@ void Mechanical::o_fortressRotation_init(uint16 op, uint16 var, uint16 argc, uin
_fortressRotationGears = static_cast<MystResourceType6 *>(_invokingResource);
VideoHandle gears = _fortressRotationGears->playMovie();
- _vm->_video->setVideoLooping(gears, true);
- _vm->_video->seekToTime(gears, Audio::Timestamp(0, 1800 * _fortressPosition, 600));
- _vm->_video->setVideoRate(gears, 0);
+ gears->setLooping(true);
+ gears->seek(Audio::Timestamp(0, 1800 * _fortressPosition, 600));
+ gears->setRate(0);
_fortressRotationSounds[0] = argv[0];
_fortressRotationSounds[1] = argv[1];
@@ -884,7 +895,7 @@ void Mechanical::o_fortressRotation_init(uint16 op, uint16 var, uint16 argc, uin
// ScummVM simulates a longer movie by counting the number of times the movie
// looped and adding that time to the current movie position.
// Hence allowing the fortress position to be properly computed.
- uint32 movieDuration = _vm->_video->getDuration(gears).convertToFramerate(600).totalNumberOfFrames();
+ uint32 movieDuration = gears->getDuration().convertToFramerate(600).totalNumberOfFrames();
if (movieDuration == 3680) {
_fortressRotationShortMovieWorkaround = true;
_fortressRotationShortMovieCount = 0;
@@ -924,8 +935,8 @@ void Mechanical::fortressSimulation_run() {
_fortressSimulationStartup->pauseMovie(true);
VideoHandle holo = _fortressSimulationHolo->playMovie();
- _vm->_video->setVideoLooping(holo, true);
- _vm->_video->setVideoRate(holo, 0);
+ holo->setLooping(true);
+ holo->setRate(0);
_vm->_cursor->showCursor();
@@ -933,9 +944,8 @@ void Mechanical::fortressSimulation_run() {
} else {
VideoHandle holo = _fortressSimulationHolo->playMovie();
- double oldRate = _vm->_video->getVideoRate(holo).toDouble();
-
- uint32 moviePosition = Audio::Timestamp(_vm->_video->getTime(holo), 600).totalNumberOfFrames();
+ double oldRate = holo->getRate().toDouble();
+ uint32 moviePosition = Audio::Timestamp(holo->getTime(), 600).totalNumberOfFrames();
int32 positionInQuarter = 900 - (moviePosition + 900) % 1800;
@@ -968,15 +978,15 @@ void Mechanical::fortressSimulation_run() {
newRate = CLIP<double>(newRate, -2.5, 2.5);
- _vm->_video->setVideoRate(holo, Common::Rational((int)(newRate * 1000.0), 1000));
+ holo->setRate(Common::Rational((int)(newRate * 1000.0), 1000));
_gearsWereRunning = true;
} else if (_gearsWereRunning) {
// The fortress has stopped. Set its new position
uint16 simulationPosition = (moviePosition + 900) / 1800 % 4;
- _vm->_video->setVideoRate(holo, 0);
- _vm->_video->seekToTime(holo, Audio::Timestamp(0, 1800 * simulationPosition, 600));
+ holo->setRate(0);
+ holo->seek(Audio::Timestamp(0, 1800 * simulationPosition, 600));
_vm->_sound->playSoundBlocking( _fortressRotationSounds[simulationPosition]);
_gearsWereRunning = false;
diff --git a/engines/mohawk/myst_stacks/myst.cpp b/engines/mohawk/myst_stacks/myst.cpp
index ca6e7c0ee5..98f0aa5349 100644
--- a/engines/mohawk/myst_stacks/myst.cpp
+++ b/engines/mohawk/myst_stacks/myst.cpp
@@ -51,8 +51,6 @@ Myst::Myst(MohawkEngine_Myst *vm) :
_dockVaultState = 0;
_cabinDoorOpened = 0;
_cabinMatchState = 2;
- _cabinGaugeMovie = NULL_VID_HANDLE;
- _cabinFireMovie = NULL_VID_HANDLE;
_matchBurning = false;
_tree = 0;
_treeAlcove = 0;
@@ -1135,10 +1133,13 @@ void Myst::o_clockWheelsExecute(uint16 op, uint16 var, uint16 argc, uint16 *argv
_vm->_system->delayMillis(500);
// Gears rise up
- VideoHandle gears = _vm->_video->playMovie(_vm->wrapMovieFilename("gears", kMystStack), 305, 33);
- _vm->_video->setVideoBounds(gears, Audio::Timestamp(0, 0, 600), Audio::Timestamp(0, 650, 600));
- _vm->_video->waitUntilMovieEnds(gears);
+ VideoHandle gears = _vm->_video->playMovie(_vm->wrapMovieFilename("gears", kMystStack));
+ if (!gears)
+ error("Failed to open gears movie");
+ gears->moveTo(305, 33);
+ gears->setBounds(Audio::Timestamp(0, 0, 600), Audio::Timestamp(0, 650, 600));
+ _vm->_video->waitUntilMovieEnds(gears);
_state.clockTowerBridgeOpen = 1;
_vm->redrawArea(12);
@@ -1147,8 +1148,12 @@ void Myst::o_clockWheelsExecute(uint16 op, uint16 var, uint16 argc, uint16 *argv
_vm->_system->delayMillis(500);
// Gears sink down
- VideoHandle gears = _vm->_video->playMovie(_vm->wrapMovieFilename("gears", kMystStack), 305, 33);
- _vm->_video->setVideoBounds(gears, Audio::Timestamp(0, 700, 600), Audio::Timestamp(0, 1300, 600));
+ VideoHandle gears = _vm->_video->playMovie(_vm->wrapMovieFilename("gears", kMystStack));
+ if (!gears)
+ error("Failed to open gears movie");
+
+ gears->moveTo(305, 33);
+ gears->setBounds(Audio::Timestamp(0, 700, 600), Audio::Timestamp(0, 1300, 600));
_vm->_video->waitUntilMovieEnds(gears);
_state.clockTowerBridgeOpen = 0;
@@ -1191,15 +1196,23 @@ void Myst::o_imagerPlayButton(uint16 op, uint16 var, uint16 argc, uint16 *argv)
if (_state.imagerActive) {
// Mountains disappearing
Common::String file = _vm->wrapMovieFilename("vltmntn", kMystStack);
- VideoHandle mountain = _vm->_video->playMovie(file, 159, 96, false);
- _vm->_video->setVideoBounds(mountain, Audio::Timestamp(0, 11180, 600), Audio::Timestamp(0, 16800, 600));
+ VideoHandle mountain = _vm->_video->playMovie(file);
+ if (!mountain)
+ error("Failed to open '%s'", file.c_str());
+
+ mountain->moveTo(159, 96);
+ mountain->setBounds(Audio::Timestamp(0, 11180, 600), Audio::Timestamp(0, 16800, 600));
_state.imagerActive = 0;
} else {
// Mountains appearing
Common::String file = _vm->wrapMovieFilename("vltmntn", kMystStack);
- VideoHandle mountain = _vm->_video->playMovie(file, 159, 96, false);
- _vm->_video->setVideoBounds(mountain, Audio::Timestamp(0, 0, 600), Audio::Timestamp(0, 11180, 600));
+ VideoHandle mountain = _vm->_video->playMovie(file);
+ if (!mountain)
+ error("Failed to open '%s'", file.c_str());
+
+ mountain->moveTo(159, 96);
+ mountain->setBounds(Audio::Timestamp(0, 0, 600), Audio::Timestamp(0, 11180, 600));
_state.imagerActive = 1;
}
@@ -1212,20 +1225,20 @@ void Myst::o_imagerPlayButton(uint16 op, uint16 var, uint16 argc, uint16 *argv)
// Water disappearing
VideoHandle water = _imagerMovie->playMovie();
- _vm->_video->setVideoBounds(water, Audio::Timestamp(0, 4204, 600), Audio::Timestamp(0, 6040, 600));
- _vm->_video->setVideoLooping(water, false);
+ water->setBounds(Audio::Timestamp(0, 4204, 600), Audio::Timestamp(0, 6040, 600));
+ water->setLooping(false);
_state.imagerActive = 0;
} else {
// Water appearing
VideoHandle water = _imagerMovie->playMovie();
- _vm->_video->setVideoBounds(water, Audio::Timestamp(0, 0, 600), Audio::Timestamp(0, 1814, 600));
+ water->setBounds(Audio::Timestamp(0, 0, 600), Audio::Timestamp(0, 1814, 600));
_vm->_video->waitUntilMovieEnds(water);
// Water looping
water = _imagerMovie->playMovie();
- _vm->_video->setVideoBounds(water, Audio::Timestamp(0, 1814, 600), Audio::Timestamp(0, 4204, 600));
- _vm->_video->setVideoLooping(water, true);
+ water->setBounds(Audio::Timestamp(0, 1814, 600), Audio::Timestamp(0, 4204, 600));
+ water->setLooping(true);
_state.imagerActive = 1;
}
@@ -1902,11 +1915,19 @@ Common::Rational Myst::boilerComputeGaugeRate(uint16 pressure, uint32 delay) {
}
void Myst::boilerResetGauge(const Common::Rational &rate) {
- if (_vm->_video->endOfVideo(_cabinGaugeMovie)) {
+ if (!_cabinGaugeMovie || _cabinGaugeMovie->endOfVideo()) {
if (_vm->getCurCard() == 4098) {
- _cabinGaugeMovie = _vm->_video->playMovie(_vm->wrapMovieFilename("cabingau", kMystStack), 243, 96);
+ _cabinGaugeMovie = _vm->_video->playMovie(_vm->wrapMovieFilename("cabingau", kMystStack));
+ if (!_cabinGaugeMovie)
+ error("Failed to open cabingau movie");
+
+ _cabinGaugeMovie->moveTo(243, 96);
} else {
- _cabinGaugeMovie = _vm->_video->playMovie(_vm->wrapMovieFilename("cabcgfar", kMystStack), 254, 136);
+ _cabinGaugeMovie = _vm->_video->playMovie(_vm->wrapMovieFilename("cabcgfar", kMystStack));
+ if (!_cabinGaugeMovie)
+ error("Failed to open cabingau movie");
+
+ _cabinGaugeMovie->moveTo(254, 136);
}
}
@@ -1914,10 +1935,10 @@ void Myst::boilerResetGauge(const Common::Rational &rate) {
if (rate > 0)
goTo = Audio::Timestamp(0, 0, 600);
else
- goTo = _vm->_video->getDuration(_cabinGaugeMovie);
+ goTo = _cabinGaugeMovie->getDuration();
- _vm->_video->seekToTime(_cabinGaugeMovie, goTo);
- _vm->_video->setVideoRate(_cabinGaugeMovie, rate);
+ _cabinGaugeMovie->seek(goTo);
+ _cabinGaugeMovie->setRate(rate);
}
void Myst::o_boilerIncreasePressureStop(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
@@ -1931,10 +1952,10 @@ void Myst::o_boilerIncreasePressureStop(uint16 op, uint16 var, uint16 argc, uint
if (_state.cabinValvePosition > 0)
_vm->_sound->replaceBackgroundMyst(8098, 49152);
- if (!_vm->_video->endOfVideo(_cabinGaugeMovie)) {
+ if (_cabinGaugeMovie && !_cabinGaugeMovie->endOfVideo()) {
uint16 delay = treeNextMoveDelay(_state.cabinValvePosition);
Common::Rational rate = boilerComputeGaugeRate(_state.cabinValvePosition, delay);
- _vm->_video->setVideoRate(_cabinGaugeMovie, rate);
+ _cabinGaugeMovie->setRate(rate);
}
} else if (_state.cabinValvePosition > 0)
@@ -2006,10 +2027,10 @@ void Myst::o_boilerDecreasePressureStop(uint16 op, uint16 var, uint16 argc, uint
if (_state.cabinValvePosition > 0)
_vm->_sound->replaceBackgroundMyst(8098, 49152);
- if (!_vm->_video->endOfVideo(_cabinGaugeMovie)) {
+ if (_cabinGaugeMovie && !_cabinGaugeMovie->endOfVideo()) {
uint16 delay = treeNextMoveDelay(_state.cabinValvePosition);
Common::Rational rate = boilerComputeGaugeRate(_state.cabinValvePosition, delay);
- _vm->_video->setVideoRate(_cabinGaugeMovie, rate);
+ _cabinGaugeMovie->setRate(rate);
}
} else {
@@ -2117,7 +2138,7 @@ void Myst::tree_run() {
// Check if alcove is accessible
treeSetAlcoveAccessible();
- if (_cabinGaugeMovie != NULL_VID_HANDLE) {
+ if (_cabinGaugeMovie) {
Common::Rational rate = boilerComputeGaugeRate(pressure, delay);
boilerResetGauge(rate);
}
@@ -2246,13 +2267,22 @@ void Myst::rocketCheckSolution() {
// Book appearing
Common::String movieFile = _vm->wrapMovieFilename("selenbok", kMystStack);
- _rocketLinkBook = _vm->_video->playMovie(movieFile, 224, 41);
- _vm->_video->setVideoBounds(_rocketLinkBook, Audio::Timestamp(0, 0, 600), Audio::Timestamp(0, 660, 600));
+ _rocketLinkBook = _vm->_video->playMovie(movieFile);
+ if (!_rocketLinkBook)
+ error("Failed to open '%s'", movieFile.c_str());
+
+ _rocketLinkBook->moveTo(224, 41);
+ _rocketLinkBook->setBounds(Audio::Timestamp(0, 0, 600), Audio::Timestamp(0, 660, 600));
_vm->_video->waitUntilMovieEnds(_rocketLinkBook);
// Book looping closed
- _rocketLinkBook = _vm->_video->playMovie(movieFile, 224, 41, true);
- _vm->_video->setVideoBounds(_rocketLinkBook, Audio::Timestamp(0, 660, 600), Audio::Timestamp(0, 3500, 600));
+ _rocketLinkBook = _vm->_video->playMovie(movieFile);
+ if (!_rocketLinkBook)
+ error("Failed to open '%s'", movieFile.c_str());
+
+ _rocketLinkBook->moveTo(224, 41);
+ _rocketLinkBook->setLooping(true);
+ _rocketLinkBook->setBounds(Audio::Timestamp(0, 660, 600), Audio::Timestamp(0, 3500, 600));
_tempVar = 1;
}
@@ -2367,7 +2397,7 @@ void Myst::o_rocketOpenBook(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
debugC(kDebugScript, "Opcode %d: Rocket open link book", op);
// Flyby movie
- _vm->_video->setVideoBounds(_rocketLinkBook, Audio::Timestamp(0, 3500, 600), Audio::Timestamp(0, 13100, 600));
+ _rocketLinkBook->setBounds(Audio::Timestamp(0, 3500, 600), Audio::Timestamp(0, 13100, 600));
// Set linkable
_tempVar = 2;
@@ -2889,8 +2919,12 @@ void Myst::clockGearForwardOneStep(uint16 gear) {
// Set video bounds
uint16 gearPosition = _clockGearsPositions[gear] - 1;
- _clockGearsVideos[gear] = _vm->_video->playMovie(_vm->wrapMovieFilename(videos[gear], kMystStack), x[gear], y[gear]);
- _vm->_video->setVideoBounds(_clockGearsVideos[gear],
+ _clockGearsVideos[gear] = _vm->_video->playMovie(_vm->wrapMovieFilename(videos[gear], kMystStack));
+ if (!_clockGearsVideos[gear])
+ error("Failed to open %s movie", videos[gear]);
+
+ _clockGearsVideos[gear]->moveTo(x[gear], y[gear]);
+ _clockGearsVideos[gear]->setBounds(
Audio::Timestamp(0, startTime[gearPosition], 600),
Audio::Timestamp(0, endTime[gearPosition], 600));
}
@@ -2902,8 +2936,12 @@ void Myst::clockWeightDownOneStep() {
// Set video bounds
if (updateVideo) {
- _clockWeightVideo = _vm->_video->playMovie(_vm->wrapMovieFilename("cl1wlfch", kMystStack) , 124, 0);
- _vm->_video->setVideoBounds(_clockWeightVideo,
+ _clockWeightVideo = _vm->_video->playMovie(_vm->wrapMovieFilename("cl1wlfch", kMystStack));
+ if (!_clockWeightVideo)
+ error("Failed to open cl1wlfch movie");
+
+ _clockWeightVideo->moveTo(124, 0);
+ _clockWeightVideo->setBounds(
Audio::Timestamp(0, _clockWeightPosition, 600),
Audio::Timestamp(0, _clockWeightPosition + 246, 600));
}
@@ -2931,7 +2969,7 @@ void Myst::o_clockLeverEndMove(uint16 op, uint16 var, uint16 argc, uint16 *argv)
// Let movies stop playing
for (uint i = 0; i < ARRAYSIZE(videos); i++) {
VideoHandle handle = _vm->_video->findVideoHandle(_vm->wrapMovieFilename(videos[i], kMystStack));
- if (handle != NULL_VID_HANDLE)
+ if (handle)
_vm->_video->delayUntilMovieEnds(handle);
}
@@ -2956,8 +2994,12 @@ void Myst::clockGearsCheckSolution() {
// Make weight go down
_vm->_sound->replaceSoundMyst(9113);
- _clockWeightVideo = _vm->_video->playMovie(_vm->wrapMovieFilename("cl1wlfch", kMystStack) , 124, 0);
- _vm->_video->setVideoBounds(_clockWeightVideo,
+ _clockWeightVideo = _vm->_video->playMovie(_vm->wrapMovieFilename("cl1wlfch", kMystStack));
+ if (!_clockWeightVideo)
+ error("Failed to open cl1wlfch movie");
+
+ _clockWeightVideo->moveTo(124, 0);
+ _clockWeightVideo->setBounds(
Audio::Timestamp(0, _clockWeightPosition, 600),
Audio::Timestamp(0, 2214, 600));
_vm->_video->waitUntilMovieEnds(_clockWeightVideo);
@@ -2968,7 +3010,7 @@ void Myst::clockGearsCheckSolution() {
_vm->_sound->replaceSoundMyst(7113);
// Gear opening video
- _vm->_video->playMovieBlocking(_vm->wrapMovieFilename("cl1wggat", kMystStack) , 195, 225);
+ _vm->_video->playMovieBlocking(_vm->wrapMovieFilename("cl1wggat", kMystStack), 195, 225);
_state.gearsOpen = 1;
_vm->redrawArea(40);
@@ -3011,7 +3053,7 @@ void Myst::clockReset() {
// Let movies stop playing
for (uint i = 0; i < ARRAYSIZE(videos); i++) {
VideoHandle handle = _vm->_video->findVideoHandle(_vm->wrapMovieFilename(videos[i], kMystStack));
- if (handle != NULL_VID_HANDLE)
+ if (handle)
_vm->_video->delayUntilMovieEnds(handle);
}
@@ -3024,9 +3066,13 @@ void Myst::clockReset() {
_vm->_sound->replaceSoundMyst(7113);
// Gear closing movie
- VideoHandle handle = _vm->_video->playMovie(_vm->wrapMovieFilename("cl1wggat", kMystStack) , 195, 225);
- _vm->_video->seekToTime(handle, _vm->_video->getDuration(handle));
- _vm->_video->setVideoRate(handle, -1);
+ VideoHandle handle = _vm->_video->playMovie(_vm->wrapMovieFilename("cl1wggat", kMystStack));
+ if (!handle)
+ error("Failed to open cl1wggat movie");
+
+ handle->moveTo(195, 225);
+ handle->seek(handle->getDuration());
+ handle->setRate(-1);
_vm->_video->waitUntilMovieEnds(handle);
// Redraw gear
@@ -3038,11 +3084,15 @@ void Myst::clockReset() {
}
void Myst::clockResetWeight() {
- _clockWeightVideo = _vm->_video->playMovie(_vm->wrapMovieFilename("cl1wlfch", kMystStack) , 124, 0);
+ _clockWeightVideo = _vm->_video->playMovie(_vm->wrapMovieFilename("cl1wlfch", kMystStack));
+ if (!_clockWeightVideo)
+ error("Failed to open cl1wlfch movie");
+
+ _clockWeightVideo->moveTo(124, 0);
// Play the movie backwards, weight going up
- _vm->_video->seekToTime(_clockWeightVideo, Audio::Timestamp(0, _clockWeightPosition, 600));
- _vm->_video->setVideoRate(_clockWeightVideo, -1);
+ _clockWeightVideo->seek(Audio::Timestamp(0, _clockWeightPosition, 600));
+ _clockWeightVideo->setRate(-1);
// Reset position
_clockWeightPosition = 0;
@@ -3057,8 +3107,12 @@ void Myst::clockResetGear(uint16 gear) {
// Set video bounds, gears going to 3
uint16 gearPosition = _clockGearsPositions[gear] - 1;
if (gearPosition != 2) {
- _clockGearsVideos[gear] = _vm->_video->playMovie(_vm->wrapMovieFilename(videos[gear], kMystStack), x[gear], y[gear]);
- _vm->_video->setVideoBounds(_clockGearsVideos[gear],
+ _clockGearsVideos[gear] = _vm->_video->playMovie(_vm->wrapMovieFilename(videos[gear], kMystStack));
+ if (!_clockGearsVideos[gear])
+ error("Failed to open gears movie");
+
+ _clockGearsVideos[gear]->moveTo(x[gear], y[gear]);
+ _clockGearsVideos[gear]->setBounds(
Audio::Timestamp(0, time[gearPosition], 600),
Audio::Timestamp(0, time[2], 600));
}
@@ -3289,8 +3343,8 @@ void Myst::imager_run() {
if (_state.imagerActive && _state.imagerSelection == 67) {
VideoHandle water = _imagerMovie->playMovie();
- _vm->_video->setVideoBounds(water, Audio::Timestamp(0, 1814, 600), Audio::Timestamp(0, 4204, 600));
- _vm->_video->setVideoLooping(water, true);
+ water->setBounds(Audio::Timestamp(0, 1814, 600), Audio::Timestamp(0, 4204, 600));
+ water->setLooping(true);
}
}
@@ -3402,8 +3456,11 @@ void Myst::gullsFly1_run() {
else
x = _vm->_rnd->getRandomNumber(160) + 260;
- _vm->_video->playMovie(_vm->wrapMovieFilename(gulls[video], kMystStack), x, 0);
+ VideoHandle handle = _vm->_video->playMovie(_vm->wrapMovieFilename(gulls[video], kMystStack));
+ if (!handle)
+ error("Failed to open gulls movie");
+ handle->moveTo(x, 0);
_gullsNextTime = time + _vm->_rnd->getRandomNumber(16667) + 13334;
}
}
@@ -3548,8 +3605,11 @@ void Myst::gullsFly2_run() {
if (time > _gullsNextTime) {
uint16 video = _vm->_rnd->getRandomNumber(3);
if (video != 3) {
- _vm->_video->playMovie(_vm->wrapMovieFilename(gulls[video], kMystStack), 424, 0);
-
+ VideoHandle handle = _vm->_video->playMovie(_vm->wrapMovieFilename(gulls[video], kMystStack));
+ if (!handle)
+ error("Failed to open gulls movie");
+
+ handle->moveTo(424, 0);
_gullsNextTime = time + _vm->_rnd->getRandomNumber(16667) + 13334;
}
}
@@ -3580,31 +3640,41 @@ void Myst::o_boilerMovies_init(uint16 op, uint16 var, uint16 argc, uint16 *argv)
void Myst::boilerFireInit() {
if (_vm->getCurCard() == 4098) {
- _cabinFireMovie = _vm->_video->playMovie(_vm->wrapMovieFilename("cabfire", kMystStack), 240, 279, true);
- _vm->_video->pauseMovie(_cabinFireMovie, true);
+ _cabinFireMovie = _vm->_video->playMovie(_vm->wrapMovieFilename("cabfire", kMystStack));
+ if (!_cabinFireMovie)
+ error("Failed to open cabfire movie");
+
+ _cabinFireMovie->moveTo(240, 279);
+ _cabinFireMovie->setLooping(true);
+ _cabinFireMovie->pause(true);
_vm->redrawArea(305);
boilerFireUpdate(true);
} else {
if (_state.cabinPilotLightLit == 1 && _state.cabinValvePosition >= 1) {
- _cabinFireMovie = _vm->_video->playMovie(_vm->wrapMovieFilename("cabfirfr", kMystStack), 254, 244, true);
+ _cabinFireMovie = _vm->_video->playMovie(_vm->wrapMovieFilename("cabfirfr", kMystStack));
+ if (!_cabinFireMovie)
+ error("Failed to open cabfirfr movie");
+
+ _cabinFireMovie->moveTo(254, 244);
+ _cabinFireMovie->setLooping(true);
}
}
}
void Myst::boilerFireUpdate(bool init) {
- uint position = _vm->_video->getTime(_cabinFireMovie);
+ uint position = _cabinFireMovie->getTime();
if (_state.cabinPilotLightLit == 1) {
if (_state.cabinValvePosition == 0) {
if (position > (uint)Audio::Timestamp(0, 200, 600).msecs() || init) {
- _vm->_video->setVideoBounds(_cabinFireMovie, Audio::Timestamp(0, 0, 600), Audio::Timestamp(0, 100, 600));
- _vm->_video->pauseMovie(_cabinFireMovie, false);
+ _cabinFireMovie->setBounds(Audio::Timestamp(0, 0, 600), Audio::Timestamp(0, 100, 600));
+ _cabinFireMovie->pause(false);
}
} else {
if (position < (uint)Audio::Timestamp(0, 200, 600).msecs() || init) {
- _vm->_video->setVideoBounds(_cabinFireMovie, Audio::Timestamp(0, 201, 600), Audio::Timestamp(0, 1900, 600));
- _vm->_video->pauseMovie(_cabinFireMovie, false);
+ _cabinFireMovie->setBounds(Audio::Timestamp(0, 201, 600), Audio::Timestamp(0, 1900, 600));
+ _cabinFireMovie->pause(false);
}
}
}
@@ -3612,15 +3682,23 @@ void Myst::boilerFireUpdate(bool init) {
void Myst::boilerGaugeInit() {
if (_vm->getCurCard() == 4098) {
- _cabinGaugeMovie = _vm->_video->playMovie(_vm->wrapMovieFilename("cabingau", kMystStack), 243, 96);
+ _cabinGaugeMovie = _vm->_video->playMovie(_vm->wrapMovieFilename("cabingau", kMystStack));
+ if (!_cabinFireMovie)
+ error("Failed to open cabingau movie");
+
+ _cabinFireMovie->moveTo(243, 96);
} else {
- _cabinGaugeMovie = _vm->_video->playMovie(_vm->wrapMovieFilename("cabcgfar", kMystStack), 254, 136);
+ _cabinGaugeMovie = _vm->_video->playMovie(_vm->wrapMovieFilename("cabcgfar", kMystStack));
+ if (!_cabinFireMovie)
+ error("Failed to open cabcgfar movie");
+
+ _cabinFireMovie->moveTo(254, 136);
}
Audio::Timestamp frame;
if (_state.cabinPilotLightLit == 1 && _state.cabinValvePosition > 12)
- frame = _vm->_video->getDuration(_cabinGaugeMovie);
+ frame = _cabinGaugeMovie->getDuration();
else
frame = Audio::Timestamp(0, 0, 600);
@@ -3680,18 +3758,27 @@ void Myst::greenBook_run() {
_vm->_sound->stopSound();
_vm->_sound->pauseBackgroundMyst();
+ VideoHandle book = _vm->_video->playMovie(file);
+ if (!book)
+ error("Failed to open '%s'", file.c_str());
+
+ book->moveTo(314, 76);
+
if (_globals.ending != 4) {
_tempVar = 2;
- _vm->_video->playMovie(file, 314, 76);
} else {
- VideoHandle book = _vm->_video->playMovie(file, 314, 76, true);
- _vm->_video->setVideoBounds(book, Audio::Timestamp(0, loopStart, 600), Audio::Timestamp(0, loopEnd, 600));
+ book->setBounds(Audio::Timestamp(0, loopStart, 600), Audio::Timestamp(0, loopEnd, 600));
+ book->setLooping(true);
_tempVar = 0;
}
} else if (_tempVar == 2 && !_vm->_video->isVideoPlaying()) {
- VideoHandle book = _vm->_video->playMovie(file, 314, 76);
- _vm->_video->setVideoBounds(book, Audio::Timestamp(0, loopStart, 600), Audio::Timestamp(0, loopEnd, 600));
- _vm->_video->setVideoLooping(book, true);
+ VideoHandle book = _vm->_video->playMovie(file);
+ if (!book)
+ error("Failed to open '%s'", file.c_str());
+
+ book->moveTo(314, 76);
+ book->setBounds(Audio::Timestamp(0, loopStart, 600), Audio::Timestamp(0, loopEnd, 600));
+ book->setLooping(true);
_tempVar = 0;
}
}
@@ -3714,8 +3801,11 @@ void Myst::gullsFly3_run() {
if (video != 3) {
uint16 x = _vm->_rnd->getRandomNumber(280) + 135;
- _vm->_video->playMovie(_vm->wrapMovieFilename(gulls[video], kMystStack), x, 0);
+ VideoHandle handle = _vm->_video->playMovie(_vm->wrapMovieFilename(gulls[video], kMystStack));
+ if (!handle)
+ error("Failed to open gulls movie");
+ handle->moveTo(x, 0);
_gullsNextTime = time + _vm->_rnd->getRandomNumber(16667) + 13334;
}
}
@@ -3750,8 +3840,8 @@ void Myst::o_treeEntry_exit(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
void Myst::o_boiler_exit(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
debugC(kDebugScript, "Opcode %d: Exit boiler card", op);
- _cabinGaugeMovie = NULL_VID_HANDLE;
- _cabinFireMovie = NULL_VID_HANDLE;
+ _cabinGaugeMovie = VideoHandle();
+ _cabinFireMovie = VideoHandle();
}
void Myst::o_generatorControlRoom_exit(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
diff --git a/engines/mohawk/myst_stacks/stoneship.cpp b/engines/mohawk/myst_stacks/stoneship.cpp
index d8dbeef641..1113ceeac9 100644
--- a/engines/mohawk/myst_stacks/stoneship.cpp
+++ b/engines/mohawk/myst_stacks/stoneship.cpp
@@ -425,8 +425,12 @@ void Stoneship::o_cabinBookMovie(uint16 op, uint16 var, uint16 argc, uint16 *arg
uint16 startTime = argv[0];
uint16 endTime = argv[1];
- VideoHandle book = _vm->_video->playMovie(_vm->wrapMovieFilename("bkroom", kStoneshipStack), 159, 99);
- _vm->_video->setVideoBounds(book, Audio::Timestamp(0, startTime, 600), Audio::Timestamp(0, endTime, 600));
+ VideoHandle book = _vm->_video->playMovie(_vm->wrapMovieFilename("bkroom", kStoneshipStack));
+ if (!book)
+ error("Failed to open bkroom movie");
+
+ book->moveTo(159, 99);
+ book->setBounds(Audio::Timestamp(0, startTime, 600), Audio::Timestamp(0, endTime, 600));
_vm->_video->waitUntilMovieEnds(book);
}
@@ -597,9 +601,9 @@ void Stoneship::o_hologramPlayback(uint16 op, uint16 var, uint16 argc, uint16 *a
if (_hologramTurnedOn) {
if (_hologramDisplayPos)
endPoint = _hologramDisplayPos;
- _vm->_video->setVideoBounds(displayMovie, Audio::Timestamp(0, startPoint, 600), Audio::Timestamp(0, endPoint, 600));
+ displayMovie->setBounds(Audio::Timestamp(0, startPoint, 600), Audio::Timestamp(0, endPoint, 600));
} else {
- _vm->_video->setVideoBounds(displayMovie, Audio::Timestamp(0, startPoint, 600), Audio::Timestamp(0, endPoint, 600));
+ displayMovie->setBounds(Audio::Timestamp(0, startPoint, 600), Audio::Timestamp(0, endPoint, 600));
}
_vm->_video->delayUntilMovieEnds(displayMovie);
@@ -673,29 +677,45 @@ void Stoneship::o_chestValveVideos(uint16 op, uint16 var, uint16 argc, uint16 *a
if (_state.chestValveState) {
// Valve closing
- VideoHandle valve = _vm->_video->playMovie(movie, 97, 267);
- _vm->_video->setVideoBounds(valve, Audio::Timestamp(0, 0, 600), Audio::Timestamp(0, 350, 600));
+ VideoHandle valve = _vm->_video->playMovie(movie);
+ if (!valve)
+ error("Failed to open '%s'", movie.c_str());
+
+ valve->moveTo(97, 267);
+ valve->setBounds(Audio::Timestamp(0, 0, 600), Audio::Timestamp(0, 350, 600));
_vm->_video->waitUntilMovieEnds(valve);
} else if (_state.chestWaterState) {
// Valve opening, spilling water
- VideoHandle valve = _vm->_video->playMovie(movie, 97, 267);
- _vm->_video->setVideoBounds(valve, Audio::Timestamp(0, 350, 600), Audio::Timestamp(0, 650, 600));
+ VideoHandle valve = _vm->_video->playMovie(movie);
+ if (!valve)
+ error("Failed to open '%s'", movie.c_str());
+
+ valve->moveTo(97, 267);
+ valve->setBounds(Audio::Timestamp(0, 350, 600), Audio::Timestamp(0, 650, 600));
_vm->_video->waitUntilMovieEnds(valve);
_vm->_sound->playSound(3132);
for (uint i = 0; i < 25; i++) {
- valve = _vm->_video->playMovie(movie, 97, 267);
- _vm->_video->setVideoBounds(valve, Audio::Timestamp(0, 650, 600), Audio::Timestamp(0, 750, 600));
+ valve = _vm->_video->playMovie(movie);
+ if (!valve)
+ error("Failed to open '%s'", movie.c_str());
+
+ valve->moveTo(97, 267);
+ valve->setBounds(Audio::Timestamp(0, 650, 600), Audio::Timestamp(0, 750, 600));
_vm->_video->waitUntilMovieEnds(valve);
}
_vm->_sound->resumeBackgroundMyst();
} else {
// Valve opening
- VideoHandle valve = _vm->_video->playMovie(movie, 97, 267);
- _vm->_video->seekToTime(valve, Audio::Timestamp(0, 350, 600));
- _vm->_video->setVideoRate(valve, -1);
+ VideoHandle valve = _vm->_video->playMovie(movie);
+ if (!valve)
+ error("Failed to open '%s'", movie.c_str());
+
+ valve->moveTo(97, 267);
+ valve->seek(Audio::Timestamp(0, 350, 600));
+ valve->setRate(-1);
_vm->_video->waitUntilMovieEnds(valve);
}
}
@@ -716,14 +736,22 @@ void Stoneship::o_trapLockOpen(uint16 op, uint16 var, uint16 argc, uint16 *argv)
Common::String movie = _vm->wrapMovieFilename("openloc", kStoneshipStack);
- VideoHandle lock = _vm->_video->playMovie(movie, 187, 71);
- _vm->_video->setVideoBounds(lock, Audio::Timestamp(0, 0, 600), Audio::Timestamp(0, 750, 600));
+ VideoHandle lock = _vm->_video->playMovie(movie);
+ if (!lock)
+ error("Failed to open '%s'", movie.c_str());
+
+ lock->moveTo(187, 71);
+ lock->setBounds(Audio::Timestamp(0, 0, 600), Audio::Timestamp(0, 750, 600));
_vm->_video->waitUntilMovieEnds(lock);
_vm->_sound->playSound(2143);
- lock = _vm->_video->playMovie(movie, 187, 71);
- _vm->_video->setVideoBounds(lock, Audio::Timestamp(0, 750, 600), Audio::Timestamp(0, 10000, 600));
+ lock = _vm->_video->playMovie(movie);
+ if (!lock)
+ error("Failed to open '%s'", movie.c_str());
+
+ lock->moveTo(187, 71);
+ lock->setBounds(Audio::Timestamp(0, 750, 600), Audio::Timestamp(0, 10000, 600));
_vm->_video->waitUntilMovieEnds(lock);
if (_state.pumpState != 4)
diff --git a/engines/mohawk/riven.cpp b/engines/mohawk/riven.cpp
index a7fe12b9e1..898f68c581 100644
--- a/engines/mohawk/riven.cpp
+++ b/engines/mohawk/riven.cpp
@@ -828,7 +828,7 @@ static void sunnersTopStairsTimer(MohawkEngine_Riven *vm) {
VideoHandle oldHandle = vm->_video->findVideoHandleRiven(1);
uint32 timerTime = 500;
- if (oldHandle == NULL_VID_HANDLE || vm->_video->endOfVideo(oldHandle)) {
+ if (!oldHandle || oldHandle->endOfVideo()) {
uint32 &sunnerTime = vm->_vars["jsunnertime"];
if (sunnerTime == 0) {
@@ -836,7 +836,7 @@ static void sunnersTopStairsTimer(MohawkEngine_Riven *vm) {
} else if (sunnerTime < vm->getTotalPlayTime()) {
VideoHandle handle = vm->_video->playMovieRiven(vm->_rnd->getRandomNumberRng(1, 3));
- timerTime = vm->_video->getDuration(handle).msecs() + vm->_rnd->getRandomNumberRng(2, 15) * 1000;
+ timerTime = handle->getDuration().msecs() + vm->_rnd->getRandomNumberRng(2, 15) * 1000;
}
sunnerTime = timerTime + vm->getTotalPlayTime();
@@ -858,7 +858,7 @@ static void sunnersMidStairsTimer(MohawkEngine_Riven *vm) {
VideoHandle oldHandle = vm->_video->findVideoHandleRiven(1);
uint32 timerTime = 500;
- if (oldHandle == NULL_VID_HANDLE || vm->_video->endOfVideo(oldHandle)) {
+ if (!oldHandle || oldHandle->endOfVideo()) {
uint32 &sunnerTime = vm->_vars["jsunnertime"];
if (sunnerTime == 0) {
@@ -874,7 +874,7 @@ static void sunnersMidStairsTimer(MohawkEngine_Riven *vm) {
VideoHandle handle = vm->_video->playMovieRiven(movie);
- timerTime = vm->_video->getDuration(handle).msecs() + vm->_rnd->getRandomNumberRng(1, 10) * 1000;
+ timerTime = handle->getDuration().msecs() + vm->_rnd->getRandomNumberRng(1, 10) * 1000;
}
sunnerTime = timerTime + vm->getTotalPlayTime();
@@ -896,7 +896,7 @@ static void sunnersLowerStairsTimer(MohawkEngine_Riven *vm) {
VideoHandle oldHandle = vm->_video->findVideoHandleRiven(1);
uint32 timerTime = 500;
- if (oldHandle == NULL_VID_HANDLE || vm->_video->endOfVideo(oldHandle)) {
+ if (!oldHandle || oldHandle->endOfVideo()) {
uint32 &sunnerTime = vm->_vars["jsunnertime"];
if (sunnerTime == 0) {
@@ -904,7 +904,7 @@ static void sunnersLowerStairsTimer(MohawkEngine_Riven *vm) {
} else if (sunnerTime < vm->getTotalPlayTime()) {
VideoHandle handle = vm->_video->playMovieRiven(vm->_rnd->getRandomNumberRng(3, 5));
- timerTime = vm->_video->getDuration(handle).msecs() + vm->_rnd->getRandomNumberRng(1, 30) * 1000;
+ timerTime = handle->getDuration().msecs() + vm->_rnd->getRandomNumberRng(1, 30) * 1000;
}
sunnerTime = timerTime + vm->getTotalPlayTime();
@@ -926,7 +926,7 @@ static void sunnersBeachTimer(MohawkEngine_Riven *vm) {
VideoHandle oldHandle = vm->_video->findVideoHandleRiven(3);
uint32 timerTime = 500;
- if (oldHandle == NULL_VID_HANDLE || vm->_video->endOfVideo(oldHandle)) {
+ if (!oldHandle || oldHandle->endOfVideo()) {
uint32 &sunnerTime = vm->_vars["jsunnertime"];
if (sunnerTime == 0) {
@@ -938,7 +938,7 @@ static void sunnersBeachTimer(MohawkEngine_Riven *vm) {
vm->_video->activateMLST(mlstID, vm->getCurCard());
VideoHandle handle = vm->_video->playMovieRiven(mlstID);
- timerTime = vm->_video->getDuration(handle).msecs() + vm->_rnd->getRandomNumberRng(1, 30) * 1000;
+ timerTime = handle->getDuration().msecs() + vm->_rnd->getRandomNumberRng(1, 30) * 1000;
}
sunnerTime = timerTime + vm->getTotalPlayTime();
@@ -969,7 +969,7 @@ void MohawkEngine_Riven::installCardTimer() {
}
void MohawkEngine_Riven::doVideoTimer(VideoHandle handle, bool force) {
- assert(handle != NULL_VID_HANDLE);
+ assert(handle);
uint16 id = _scriptMan->getStoredMovieOpcodeID();
@@ -977,7 +977,7 @@ void MohawkEngine_Riven::doVideoTimer(VideoHandle handle, bool force) {
return;
// Run the opcode if we can at this point
- if (force || _video->getTime(handle) >= _scriptMan->getStoredMovieOpcodeTime())
+ if (force || handle->getTime() >= _scriptMan->getStoredMovieOpcodeTime())
_scriptMan->runStoredMovieOpcode();
}
@@ -1003,7 +1003,7 @@ void MohawkEngine_Riven::checkSunnerAlertClick() {
// If the alert video is no longer playing, we have nothing left to do
VideoHandle handle = _video->findVideoHandleRiven(1);
- if (handle == NULL_VID_HANDLE || _video->endOfVideo(handle))
+ if (!handle || handle->endOfVideo())
return;
sunners = 1;
diff --git a/engines/mohawk/riven_external.cpp b/engines/mohawk/riven_external.cpp
index cda0683028..00075039fe 100644
--- a/engines/mohawk/riven_external.cpp
+++ b/engines/mohawk/riven_external.cpp
@@ -229,7 +229,7 @@ void RivenExternal::runCredits(uint16 video, uint32 delay) {
VideoHandle videoHandle = _vm->_video->findVideoHandleRiven(video);
while (!_vm->shouldQuit() && _vm->_gfx->getCurCreditsImage() <= 320) {
- if (_vm->_video->getCurFrame(videoHandle) >= (int32)_vm->_video->getFrameCount(videoHandle) - 1) {
+ if (videoHandle->getCurFrame() >= (int32)videoHandle->getFrameCount() - 1) {
if (nextCreditsFrameStart == 0) {
// Set us up to start after delay ms
nextCreditsFrameStart = _vm->_system->getMillis() + delay;
@@ -265,10 +265,10 @@ void RivenExternal::runDomeCheck() {
// Check if we clicked while the golden frame was showing
VideoHandle video = _vm->_video->findVideoHandleRiven(1);
- assert(video != NULL_VID_HANDLE);
+ assert(video);
- int32 curFrame = _vm->_video->getCurFrame(video);
- int32 frameCount = _vm->_video->getFrameCount(video);
+ int32 curFrame = video->getCurFrame();
+ int32 frameCount = video->getFrameCount();
// The final frame of the video is the 'golden' frame (double meaning: the
// frame that is the magic one is the one with the golden symbol) but we
@@ -857,8 +857,12 @@ void RivenExternal::xbupdateboiler(uint16 argc, uint16 *argv) {
_vm->_video->playMovieRiven(7);
}
} else {
- _vm->_video->disableMovieRiven(7);
- _vm->_video->disableMovieRiven(8);
+ VideoHandle handle = _vm->_video->findVideoHandleRiven(7);
+ if (handle)
+ handle->setEnabled(false);
+ handle = _vm->_video->findVideoHandleRiven(8);
+ if (handle)
+ handle->setEnabled(false);
}
}
@@ -1149,8 +1153,8 @@ void RivenExternal::lowerPins() {
// Play the video of the pins going down
VideoHandle handle = _vm->_video->playMovieRiven(upMovie);
- assert(handle != NULL_VID_HANDLE);
- _vm->_video->setVideoBounds(handle, Audio::Timestamp(0, startTime, 600), Audio::Timestamp(0, startTime + 550, 600));
+ assert(handle);
+ handle->setBounds(Audio::Timestamp(0, startTime, 600), Audio::Timestamp(0, startTime + 550, 600));
_vm->_video->waitUntilMovieEnds(handle);
upMovie = 0;
@@ -1181,8 +1185,8 @@ void RivenExternal::xgrotatepins(uint16 argc, uint16 *argv) {
// Play the video of the pins rotating
VideoHandle handle = _vm->_video->playMovieRiven(_vm->_vars["gupmoov"]);
- assert(handle != NULL_VID_HANDLE);
- _vm->_video->setVideoBounds(handle, Audio::Timestamp(0, startTime, 600), Audio::Timestamp(0, startTime + 1215, 600));
+ assert(handle);
+ handle->setBounds(Audio::Timestamp(0, startTime, 600), Audio::Timestamp(0, startTime + 1215, 600));
_vm->_video->waitUntilMovieEnds(handle);
}
@@ -1265,9 +1269,9 @@ void RivenExternal::xgpincontrols(uint16 argc, uint16 *argv) {
// Actually play the movie
VideoHandle handle = _vm->_video->playMovieRiven(pinMovieCodes[imagePos - 1]);
- assert(handle != NULL_VID_HANDLE);
+ assert(handle);
uint32 startTime = 9630 - pinPos * 600;
- _vm->_video->setVideoBounds(handle, Audio::Timestamp(0, startTime, 600), Audio::Timestamp(0, startTime + 550, 600));
+ handle->setBounds(Audio::Timestamp(0, startTime, 600), Audio::Timestamp(0, startTime + 550, 600));
_vm->_video->waitUntilMovieEnds(handle);
// Update the relevant variables
@@ -1343,8 +1347,8 @@ void RivenExternal::xgrviewer(uint16 argc, uint16 *argv) {
// Now play the movie
VideoHandle handle = _vm->_video->playMovieRiven(1);
- assert(handle != NULL_VID_HANDLE);
- _vm->_video->setVideoBounds(handle, Audio::Timestamp(0, s_viewerTimeIntervals[curPos], 600), Audio::Timestamp(0, s_viewerTimeIntervals[newPos], 600));
+ assert(handle);
+ handle->setBounds(Audio::Timestamp(0, s_viewerTimeIntervals[curPos], 600), Audio::Timestamp(0, s_viewerTimeIntervals[newPos], 600));
_vm->_video->waitUntilMovieEnds(handle);
// Set the new position and let the card's scripts take over again
@@ -1412,8 +1416,8 @@ void RivenExternal::xglviewer(uint16 argc, uint16 *argv) {
// Now play the movie
VideoHandle handle = _vm->_video->playMovieRiven(1);
- assert(handle != NULL_VID_HANDLE);
- _vm->_video->setVideoBounds(handle, Audio::Timestamp(0, s_viewerTimeIntervals[curPos], 600), Audio::Timestamp(0, s_viewerTimeIntervals[newPos], 600));
+ assert(handle);
+ handle->setBounds(Audio::Timestamp(0, s_viewerTimeIntervals[curPos], 600), Audio::Timestamp(0, s_viewerTimeIntervals[newPos], 600));
_vm->_video->waitUntilMovieEnds(handle);
// Set the new position to the variable
@@ -1467,7 +1471,7 @@ static void catherineViewerIdleTimer(MohawkEngine_Riven *vm) {
VideoHandle videoHandle = vm->_video->playMovieRiven(30);
// Reset the timer
- vm->installTimer(&catherineViewerIdleTimer, vm->_video->getDuration(videoHandle).msecs() + vm->_rnd->getRandomNumber(60) * 1000);
+ vm->installTimer(&catherineViewerIdleTimer, videoHandle->getDuration().msecs() + vm->_rnd->getRandomNumber(60) * 1000);
}
void RivenExternal::xglview_prisonon(uint16 argc, uint16 *argv) {
@@ -1507,7 +1511,7 @@ void RivenExternal::xglview_prisonon(uint16 argc, uint16 *argv) {
_vm->_video->activateMLST(cathMovie, _vm->getCurCard());
VideoHandle videoHandle = _vm->_video->playMovieRiven(30);
- timeUntilNextMovie = _vm->_video->getDuration(videoHandle).msecs() + _vm->_rnd->getRandomNumber(60) * 1000;
+ timeUntilNextMovie = videoHandle->getDuration().msecs() + _vm->_rnd->getRandomNumber(60) * 1000;
} else {
// Otherwise, just redraw the imager
timeUntilNextMovie = _vm->_rnd->getRandomNumberRng(10, 20) * 1000;
@@ -1986,7 +1990,7 @@ void RivenExternal::xschool280_playwhark(uint16 argc, uint16 *argv) {
Audio::Timestamp startTime = Audio::Timestamp(0, (11560 / 19) * (*posVar), 600);
*posVar += number; // Adjust to the end
Audio::Timestamp endTime = Audio::Timestamp(0, (11560 / 19) * (*posVar), 600);
- _vm->_video->setVideoBounds(handle, startTime, endTime);
+ handle->setBounds(startTime, endTime);
_vm->_video->waitUntilMovieEnds(handle);
if (*posVar > 19) {
@@ -2059,7 +2063,7 @@ void RivenExternal::xbookclick(uint16 argc, uint16 *argv) {
debug(0, "\tHotspot = %d -> %d", argv[3], hotspotMap[argv[3] - 1]);
// Just let the video play while we wait until Gehn opens the trap book for us
- while (_vm->_video->getTime(video) < startTime && !_vm->shouldQuit()) {
+ while (video->getTime() < startTime && !_vm->shouldQuit()) {
if (_vm->_video->updateMovies())
_vm->_system->updateScreen();
@@ -2084,7 +2088,7 @@ void RivenExternal::xbookclick(uint16 argc, uint16 *argv) {
// OK, Gehn has opened the trap book and has asked us to go in. Let's watch
// and see what the player will do...
- while (_vm->_video->getTime(video) < endTime && !_vm->shouldQuit()) {
+ while (video->getTime() < endTime && !_vm->shouldQuit()) {
bool updateScreen = _vm->_video->updateMovies();
Common::Event event;
@@ -2335,7 +2339,7 @@ static void rebelPrisonWindowTimer(MohawkEngine_Riven *vm) {
VideoHandle handle = vm->_video->playMovieRiven(movie);
// Ensure the next video starts after this one ends
- uint32 timeUntilNextVideo = vm->_video->getDuration(handle).msecs() + vm->_rnd->getRandomNumberRng(38, 58) * 1000;
+ uint32 timeUntilNextVideo = handle->getDuration().msecs() + vm->_rnd->getRandomNumberRng(38, 58) * 1000;
// Save the time in case we leave the card and return
vm->_vars["rvillagetime"] = timeUntilNextVideo + vm->getTotalPlayTime();
@@ -2434,7 +2438,7 @@ void RivenExternal::xtexterior300_telescopedown(uint16 argc, uint16 *argv) {
static const uint32 timeIntervals[] = { 4320, 3440, 2560, 1760, 880, 0 };
uint16 movieCode = telescopeCover ? 1 : 2;
VideoHandle handle = _vm->_video->playMovieRiven(movieCode);
- _vm->_video->setVideoBounds(handle, Audio::Timestamp(0, timeIntervals[telescopePos], 600), Audio::Timestamp(0, timeIntervals[telescopePos - 1], 600));
+ handle->setBounds(Audio::Timestamp(0, timeIntervals[telescopePos], 600), Audio::Timestamp(0, timeIntervals[telescopePos - 1], 600));
_vm->_sound->playSound(14); // Play the moving sound
_vm->_video->waitUntilMovieEnds(handle);
@@ -2467,7 +2471,7 @@ void RivenExternal::xtexterior300_telescopeup(uint16 argc, uint16 *argv) {
static const uint32 timeIntervals[] = { 0, 800, 1680, 2560, 3440, 4320 };
uint16 movieCode = _vm->_vars["ttelecover"] ? 4 : 5;
VideoHandle handle = _vm->_video->playMovieRiven(movieCode);
- _vm->_video->setVideoBounds(handle, Audio::Timestamp(0, timeIntervals[telescopePos - 1], 600), Audio::Timestamp(0, timeIntervals[telescopePos], 600));
+ handle->setBounds(Audio::Timestamp(0, timeIntervals[telescopePos - 1], 600), Audio::Timestamp(0, timeIntervals[telescopePos], 600));
_vm->_sound->playSound(14); // Play the moving sound
_vm->_video->waitUntilMovieEnds(handle);
@@ -2569,26 +2573,47 @@ void RivenExternal::xt7500_checkmarbles(uint16 argc, uint16 *argv) {
void RivenExternal::xt7600_setupmarbles(uint16 argc, uint16 *argv) {
// Draw the small marbles when we're a step away from the waffle
- uint16 baseBitmapId = _vm->findResourceID(ID_TBMP, "*tsmallred");
+
+ // Convert from marble X coordinate to screen X coordinate
+ static const uint16 xPosOffsets[] = {
+ 246, 245, 244, 243, 243, 241, 240, 240, 239, 238, 237, 237, 236, 235, 234, 233, 232, 231, 230, 229, 228, 227, 226, 226, 225
+ };
+
+ // Convert from marble Y coordinate to screen Y coordinate
+ static const uint16 yPosOffsets[] = {
+ 261, 263, 265, 267, 268, 270, 272, 274, 276, 278, 281, 284, 285, 288, 290, 293, 295, 298, 300, 303, 306, 309, 311, 314, 316
+ };
+
+ // Handle spacing for y coordinates due to the angle
+ static const double yAdjusts[] = {
+ 4.56, 4.68, 4.76, 4.84, 4.84, 4.96, 5.04, 5.04, 5.12, 5.2, 5.28, 5.28, 5.36, 5.44, 5.4, 5.6, 5.72, 5.8, 5.88, 5.96, 6.04, 6.12, 6.2, 6.2, 6.28
+ };
+
+ // Waffle state of 0 is up, 1 down
bool waffleDown = _vm->_vars["twaffle"] != 0;
// Note that each of the small marble images is exactly 4x2
+ // The original seems to scale the marble images from extras.mhk, but
+ // we're using the pre-scaled images in the stack.
+ uint16 baseBitmapId = _vm->findResourceID(ID_TBMP, "*tsmallred");
for (uint16 i = 0; i < kMarbleCount; i++) {
- uint32 &var = _vm->_vars[s_marbleNames[i]];
+ uint32 var = _vm->_vars[s_marbleNames[i]];
if (var == 0) {
// The marble is still in its initial place
// (Note that this is still drawn even if the waffle is down)
- int marbleX = 376 + i * 2;
- int marbleY = 253 + i * 4;
- _vm->_gfx->copyImageToScreen(baseBitmapId + i, marbleX, marbleY, marbleX + kSmallMarbleWidth, marbleY + kSmallMarbleHeight);
+ static const uint16 defaultX[] = { 375, 377, 379, 381, 383, 385 };
+ static const uint16 defaultY[] = { 253, 257, 261, 265, 268, 273 };
+ _vm->_gfx->copyImageToScreen(baseBitmapId + i, defaultX[i], defaultY[i], defaultX[i] + kSmallMarbleWidth, defaultY[i] + kSmallMarbleHeight);
} else if (waffleDown) {
// The marble is on the grid and the waffle is down
// (Nothing to draw here)
} else {
// The marble is on the grid and the waffle is up
- // TODO: Draw them onto the grid
+ int marbleX = (int)floor(getMarbleX(var) * yAdjusts[getMarbleY(var)] + xPosOffsets[getMarbleY(var)] + 0.5);
+ int marbleY = yPosOffsets[getMarbleY(var)];
+ _vm->_gfx->copyImageToScreen(baseBitmapId + i, marbleX, marbleY, marbleX + kSmallMarbleWidth, marbleY + kSmallMarbleHeight);
}
}
}
diff --git a/engines/mohawk/riven_scripts.cpp b/engines/mohawk/riven_scripts.cpp
index 29ee5cd50b..caa235ec8b 100644
--- a/engines/mohawk/riven_scripts.cpp
+++ b/engines/mohawk/riven_scripts.cpp
@@ -493,7 +493,9 @@ void RivenScript::changeStack(uint16 op, uint16 argc, uint16 *argv) {
// Command 28: disable a movie
void RivenScript::disableMovie(uint16 op, uint16 argc, uint16 *argv) {
- _vm->_video->disableMovieRiven(argv[0]);
+ VideoHandle handle = _vm->_video->findVideoHandleRiven(argv[0]);
+ if (handle)
+ handle->setEnabled(false);
}
// Command 29: disable all movies
@@ -503,7 +505,9 @@ void RivenScript::disableAllMovies(uint16 op, uint16 argc, uint16 *argv) {
// Command 31: enable a movie
void RivenScript::enableMovie(uint16 op, uint16 argc, uint16 *argv) {
- _vm->_video->enableMovieRiven(argv[0]);
+ VideoHandle handle = _vm->_video->findVideoHandleRiven(argv[0]);
+ if (handle)
+ handle->setEnabled(true);
}
// Command 32: play foreground movie - blocking (movie_id)
diff --git a/engines/mohawk/video.cpp b/engines/mohawk/video.cpp
index 3f27e4a1a4..ff4a69cd28 100644
--- a/engines/mohawk/video.cpp
+++ b/engines/mohawk/video.cpp
@@ -24,6 +24,7 @@
#include "mohawk/resource.h"
#include "mohawk/video.h"
+#include "common/algorithm.h"
#include "common/debug.h"
#include "common/events.h"
#include "common/textconsole.h"
@@ -37,19 +38,110 @@
namespace Mohawk {
-void VideoEntry::clear() {
- video = 0;
- x = 0;
- y = 0;
- loop = false;
- enabled = false;
- start = Audio::Timestamp(0, 1);
- filename.clear();
- id = -1;
+VideoEntry::VideoEntry() : _video(0), _id(-1), _x(0), _y(0), _loop(false), _enabled(true) {
}
-bool VideoEntry::endOfVideo() {
- return !video || video->endOfVideo();
+VideoEntry::VideoEntry(Video::VideoDecoder *video, const Common::String &fileName) : _video(video), _fileName(fileName), _id(-1), _x(0), _y(0), _loop(false), _enabled(true) {
+}
+
+VideoEntry::VideoEntry(Video::VideoDecoder *video, int id) : _video(video), _id(id), _x(0), _y(0), _loop(false), _enabled(true) {
+}
+
+VideoEntry::~VideoEntry() {
+ close();
+}
+
+void VideoEntry::close() {
+ delete _video;
+ _video = 0;
+}
+
+bool VideoEntry::endOfVideo() const {
+ return !isOpen() || _video->endOfVideo();
+}
+
+int VideoEntry::getCurFrame() const {
+ assert(_video);
+ return _video->getCurFrame();
+}
+
+uint32 VideoEntry::getFrameCount() const {
+ assert(_video);
+ return _video->getFrameCount();
+}
+
+uint32 VideoEntry::getTime() const {
+ assert(_video);
+ return _video->getTime();
+}
+
+Audio::Timestamp VideoEntry::getDuration() const {
+ assert(_video);
+ return _video->getDuration();
+}
+
+Common::Rational VideoEntry::getRate() const {
+ assert(_video);
+ return _video->getRate();
+}
+
+void VideoEntry::center() {
+ assert(_video);
+ _x = (g_system->getWidth() - _video->getWidth()) / 2;
+ _y = (g_system->getHeight() - _video->getHeight()) / 2;
+}
+
+void VideoEntry::setBounds(const Audio::Timestamp &startTime, const Audio::Timestamp &endTime) {
+ assert(_video);
+ _start = startTime;
+ _video->setEndTime(endTime);
+ _video->seek(startTime);
+}
+
+void VideoEntry::seek(const Audio::Timestamp &time) {
+ assert(_video);
+ _video->seek(time);
+}
+
+void VideoEntry::setRate(const Common::Rational &rate) {
+ assert(_video);
+ _video->setRate(rate);
+}
+
+void VideoEntry::pause(bool isPaused) {
+ assert(_video);
+ _video->pauseVideo(isPaused);
+}
+
+void VideoEntry::start() {
+ assert(_video);
+ _video->start();
+}
+
+void VideoEntry::stop() {
+ assert(_video);
+ _video->stop();
+}
+
+bool VideoEntry::isPlaying() const {
+ assert(_video);
+ return _video->isPlaying();
+}
+
+int VideoEntry::getVolume() const {
+ assert(_video);
+ return _video->getVolume();
+}
+
+void VideoEntry::setVolume(int volume) {
+ assert(_video);
+ _video->setVolume(CLIP(volume, 0, 255));
+}
+
+VideoHandle::VideoHandle(VideoEntryPtr ptr) : _ptr(ptr) {
+}
+
+VideoHandle::VideoHandle(const VideoHandle &handle) : _ptr(handle._ptr) {
}
VideoManager::VideoManager(MohawkEngine* vm) : _vm(vm) {
@@ -62,41 +154,42 @@ VideoManager::~VideoManager() {
}
void VideoManager::pauseVideos() {
- for (uint16 i = 0; i < _videoStreams.size(); i++)
- if (_videoStreams[i].video)
- _videoStreams[i]->pauseVideo(true);
+ for (VideoList::iterator it = _videos.begin(); it != _videos.end(); it++)
+ (*it)->pause(true);
}
void VideoManager::resumeVideos() {
- for (uint16 i = 0; i < _videoStreams.size(); i++)
- if (_videoStreams[i].video)
- _videoStreams[i]->pauseVideo(false);
+ for (VideoList::iterator it = _videos.begin(); it != _videos.end(); it++)
+ (*it)->pause(false);
}
void VideoManager::stopVideos() {
- for (uint16 i = 0; i < _videoStreams.size(); i++)
- delete _videoStreams[i].video;
+ for (VideoList::iterator it = _videos.begin(); it != _videos.end(); it++)
+ (*it)->close();
- _videoStreams.clear();
+ _videos.clear();
}
-void VideoManager::playMovieBlocking(const Common::String &filename, uint16 x, uint16 y, bool clearScreen) {
- VideoHandle videoHandle = createVideoHandle(filename, x, y, false);
- if (videoHandle == NULL_VID_HANDLE)
+void VideoManager::playMovieBlocking(const Common::String &fileName, uint16 x, uint16 y, bool clearScreen) {
+ VideoEntryPtr ptr = open(fileName);
+ if (!ptr)
return;
+ ptr->moveTo(x, y);
+
// Clear screen if requested
if (clearScreen) {
_vm->_system->fillScreen(_vm->_system->getScreenFormat().RGBToColor(0, 0, 0));
_vm->_system->updateScreen();
}
- waitUntilMovieEnds(videoHandle);
+ ptr->start();
+ waitUntilMovieEnds(ptr);
}
-void VideoManager::playMovieBlockingCentered(const Common::String &filename, bool clearScreen) {
- VideoHandle videoHandle = createVideoHandle(filename, 0, 0, false);
- if (videoHandle == NULL_VID_HANDLE)
+void VideoManager::playMovieBlockingCentered(const Common::String &fileName, bool clearScreen) {
+ VideoEntryPtr ptr = open(fileName);
+ if (!ptr)
return;
// Clear screen if requested
@@ -105,19 +198,22 @@ void VideoManager::playMovieBlockingCentered(const Common::String &filename, boo
_vm->_system->updateScreen();
}
- _videoStreams[videoHandle].x = (_vm->_system->getWidth() - _videoStreams[videoHandle]->getWidth()) / 2;
- _videoStreams[videoHandle].y = (_vm->_system->getHeight() - _videoStreams[videoHandle]->getHeight()) / 2;
-
- waitUntilMovieEnds(videoHandle);
+ ptr->center();
+ ptr->start();
+ waitUntilMovieEnds(ptr);
}
void VideoManager::waitUntilMovieEnds(VideoHandle videoHandle) {
- if (videoHandle == NULL_VID_HANDLE)
+ if (!videoHandle)
return;
+ // Sanity check
+ if (videoHandle._ptr->isLooping())
+ error("Called waitUntilMovieEnds() on a looping video");
+
bool continuePlaying = true;
- while (!_videoStreams[videoHandle].endOfVideo() && !_vm->shouldQuit() && continuePlaying) {
+ while (!videoHandle->endOfVideo() && !_vm->shouldQuit() && continuePlaying) {
if (updateMovies())
_vm->_system->updateScreen();
@@ -149,12 +245,22 @@ void VideoManager::waitUntilMovieEnds(VideoHandle videoHandle) {
_vm->_system->delayMillis(10);
}
- delete _videoStreams[videoHandle].video;
- _videoStreams[videoHandle].clear();
+ // Ensure it's removed
+ removeEntry(videoHandle._ptr);
}
void VideoManager::delayUntilMovieEnds(VideoHandle videoHandle) {
- while (!_videoStreams[videoHandle].endOfVideo() && !_vm->shouldQuit()) {
+ // FIXME: Why is this separate from waitUntilMovieEnds?
+ // It seems to only cut out the event loop (which is bad).
+
+ if (!videoHandle)
+ return;
+
+ // Sanity check
+ if (videoHandle._ptr->isLooping())
+ error("Called delayUntilMovieEnds() on a looping video");
+
+ while (!videoHandle->endOfVideo() && !_vm->shouldQuit()) {
if (updateMovies())
_vm->_system->updateScreen();
@@ -162,73 +268,59 @@ void VideoManager::delayUntilMovieEnds(VideoHandle videoHandle) {
_vm->_system->delayMillis(10);
}
- delete _videoStreams[videoHandle].video;
- _videoStreams[videoHandle].clear();
+ // Ensure it's removed
+ removeEntry(videoHandle._ptr);
}
-VideoHandle VideoManager::playMovie(const Common::String &filename, int16 x, int16 y, bool loop) {
- VideoHandle videoHandle = createVideoHandle(filename, x, y, loop);
- if (videoHandle == NULL_VID_HANDLE)
- return NULL_VID_HANDLE;
-
- // Center x if requested
- if (x < 0)
- _videoStreams[videoHandle].x = (_vm->_system->getWidth() - _videoStreams[videoHandle]->getWidth()) / 2;
-
- // Center y if requested
- if (y < 0)
- _videoStreams[videoHandle].y = (_vm->_system->getHeight() - _videoStreams[videoHandle]->getHeight()) / 2;
+VideoHandle VideoManager::playMovie(const Common::String &fileName) {
+ VideoEntryPtr ptr = open(fileName);
+ if (!ptr)
+ return VideoHandle();
- return videoHandle;
+ ptr->start();
+ return ptr;
}
-VideoHandle VideoManager::playMovie(uint16 id, int16 x, int16 y, bool loop) {
- VideoHandle videoHandle = createVideoHandle(id, x, y, loop);
- if (videoHandle == NULL_VID_HANDLE)
- return NULL_VID_HANDLE;
+VideoHandle VideoManager::playMovie(uint16 id) {
+ VideoEntryPtr ptr = open(id);
+ if (!ptr)
+ return VideoHandle();
- // Center x if requested
- if (x < 0)
- _videoStreams[videoHandle].x = (_vm->_system->getWidth() - _videoStreams[videoHandle]->getWidth()) / 2;
-
- // Center y if requested
- if (y < 0)
- _videoStreams[videoHandle].y = (_vm->_system->getHeight() - _videoStreams[videoHandle]->getHeight()) / 2;
-
- return videoHandle;
+ ptr->start();
+ return ptr;
}
bool VideoManager::updateMovies() {
bool updateScreen = false;
- for (uint32 i = 0; i < _videoStreams.size() && !_vm->shouldQuit(); i++) {
- // Skip deleted videos
- if (!_videoStreams[i].video)
- continue;
-
- // Remove any videos that are over
- if (_videoStreams[i].endOfVideo()) {
- if (_videoStreams[i].loop) {
- _videoStreams[i]->seek(_videoStreams[i].start);
+ for (VideoList::iterator it = _videos.begin(); it != _videos.end(); ) {
+ // Check of the video has reached the end
+ if ((*it)->endOfVideo()) {
+ if ((*it)->isLooping()) {
+ // Seek back if looping
+ (*it)->seek((*it)->getStart());
} else {
- // Check the video time one last time before deleting it
- _vm->doVideoTimer(i, true);
- delete _videoStreams[i].video;
- _videoStreams[i].clear();
+ // Done; close and continue on
+ (*it)->close();
+ it = _videos.erase(it);
continue;
}
}
- // Nothing more to do if we're paused
- if (_videoStreams[i]->isPaused())
+ Video::VideoDecoder *video = (*it)->_video;
+
+ // Ignore paused videos
+ if (video->isPaused()) {
+ it++;
continue;
+ }
// Check if we need to draw a frame
- if (_videoStreams[i]->needsUpdate()) {
- const Graphics::Surface *frame = _videoStreams[i]->decodeNextFrame();
+ if (video->needsUpdate()) {
+ const Graphics::Surface *frame = video->decodeNextFrame();
Graphics::Surface *convertedFrame = 0;
- if (frame && _videoStreams[i].enabled) {
+ if (frame && (*it)->isEnabled()) {
Graphics::PixelFormat pixelFormat = _vm->_system->getScreenFormat();
if (frame->format != pixelFormat) {
@@ -236,25 +328,25 @@ bool VideoManager::updateMovies() {
// support in the codec. Set _enableDither if shows up.
if (pixelFormat.bytesPerPixel == 1) {
warning("Cannot convert high color video frame to 8bpp");
- delete _videoStreams[i].video;
- _videoStreams[i].clear();
+ (*it)->close();
+ it = _videos.erase(it);
continue;
}
// Convert to the current screen format
- convertedFrame = frame->convertTo(pixelFormat, _videoStreams[i]->getPalette());
+ convertedFrame = frame->convertTo(pixelFormat, video->getPalette());
frame = convertedFrame;
- } else if (pixelFormat.bytesPerPixel == 1 && _videoStreams[i]->hasDirtyPalette()) {
+ } 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(_videoStreams[i]->getPalette(), 0, 256);
+ _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>(_videoStreams[i]->getWidth(), _vm->_system->getWidth() - _videoStreams[i].x);
- uint16 height = MIN<int32>(_videoStreams[i]->getHeight(), _vm->_system->getHeight() - _videoStreams[i].y);
- _vm->_system->copyRectToScreen(frame->getPixels(), frame->pitch, _videoStreams[i].x, _videoStreams[i].y, width, height);
+ 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
updateScreen = true;
@@ -268,7 +360,10 @@ bool VideoManager::updateMovies() {
}
// Check the video time
- _vm->doVideoTimer(i, false);
+ _vm->doVideoTimer(*it, false);
+
+ // Remember to increase the iterator
+ it++;
}
// Return true if we need to update the screen
@@ -323,251 +418,165 @@ void VideoManager::clearMLST() {
}
VideoHandle VideoManager::playMovieRiven(uint16 id) {
- for (uint16 i = 0; i < _mlstRecords.size(); i++)
+ for (uint16 i = 0; i < _mlstRecords.size(); i++) {
if (_mlstRecords[i].code == id) {
debug(1, "Play tMOV %d (non-blocking) at (%d, %d) %s, Volume = %d", _mlstRecords[i].movieID, _mlstRecords[i].left, _mlstRecords[i].top, _mlstRecords[i].loop != 0 ? "looping" : "non-looping", _mlstRecords[i].volume);
- return createVideoHandle(_mlstRecords[i].movieID, _mlstRecords[i].left, _mlstRecords[i].top, _mlstRecords[i].loop != 0, _mlstRecords[i].volume);
+
+ VideoEntryPtr ptr = open(_mlstRecords[i].movieID);
+ if (ptr) {
+ ptr->moveTo(_mlstRecords[i].left, _mlstRecords[i].top);
+ ptr->setLooping(_mlstRecords[i].loop != 0);
+ ptr->setVolume(_mlstRecords[i].volume);
+ ptr->start();
+ }
+
+ return ptr;
}
+ }
- return NULL_VID_HANDLE;
+ return VideoHandle();
}
void VideoManager::playMovieBlockingRiven(uint16 id) {
- for (uint16 i = 0; i < _mlstRecords.size(); i++)
+ for (uint16 i = 0; i < _mlstRecords.size(); i++) {
if (_mlstRecords[i].code == id) {
debug(1, "Play tMOV %d (blocking) at (%d, %d), Volume = %d", _mlstRecords[i].movieID, _mlstRecords[i].left, _mlstRecords[i].top, _mlstRecords[i].volume);
- VideoHandle videoHandle = createVideoHandle(_mlstRecords[i].movieID, _mlstRecords[i].left, _mlstRecords[i].top, false);
- waitUntilMovieEnds(videoHandle);
+ VideoEntryPtr ptr = open(_mlstRecords[i].movieID);
+ ptr->moveTo(_mlstRecords[i].left, _mlstRecords[i].top);
+ ptr->setVolume(_mlstRecords[i].volume);
+ ptr->start();
+ waitUntilMovieEnds(ptr);
return;
}
+ }
}
void VideoManager::stopMovieRiven(uint16 id) {
debug(2, "Stopping movie %d", id);
- for (uint16 i = 0; i < _mlstRecords.size(); i++)
- if (_mlstRecords[i].code == id)
- for (uint16 j = 0; j < _videoStreams.size(); j++)
- if (_mlstRecords[i].movieID == _videoStreams[j].id) {
- delete _videoStreams[j].video;
- _videoStreams[j].clear();
- return;
- }
-}
-
-void VideoManager::enableMovieRiven(uint16 id) {
- debug(2, "Enabling movie %d", id);
- for (uint16 i = 0; i < _mlstRecords.size(); i++)
- if (_mlstRecords[i].code == id)
- for (uint16 j = 0; j < _videoStreams.size(); j++)
- if (_mlstRecords[i].movieID == _videoStreams[j].id) {
- _videoStreams[j].enabled = true;
- return;
- }
-}
-
-void VideoManager::disableMovieRiven(uint16 id) {
- debug(2, "Disabling movie %d", id);
- for (uint16 i = 0; i < _mlstRecords.size(); i++)
- if (_mlstRecords[i].code == id)
- for (uint16 j = 0; j < _videoStreams.size(); j++)
- if (_mlstRecords[i].movieID == _videoStreams[j].id) {
- _videoStreams[j].enabled = false;
- return;
- }
+ VideoHandle handle = findVideoHandleRiven(id);
+ if (handle)
+ removeEntry(handle._ptr);
}
void VideoManager::disableAllMovies() {
debug(2, "Disabling all movies");
- for (uint16 i = 0; i < _videoStreams.size(); i++)
- _videoStreams[i].enabled = false;
+ for (VideoList::iterator it = _videos.begin(); it != _videos.end(); it++)
+ (*it)->setEnabled(false);
}
-VideoHandle VideoManager::createVideoHandle(uint16 id, uint16 x, uint16 y, bool loop, uint16 volume) {
- // First, check to see if that video is already playing
- for (uint32 i = 0; i < _videoStreams.size(); i++)
- if (_videoStreams[i].id == id)
- return i;
+VideoEntryPtr VideoManager::open(uint16 id) {
+ // If this video is already playing, return that handle
+ VideoHandle oldHandle = findVideoHandle(id);
+ if (oldHandle._ptr)
+ return oldHandle._ptr;
// Otherwise, create a new entry
- Video::QuickTimeDecoder *decoder = new Video::QuickTimeDecoder();
- decoder->setChunkBeginOffset(_vm->getResourceOffset(ID_TMOV, id));
- decoder->loadStream(_vm->getResource(ID_TMOV, id));
- decoder->setVolume((volume >= 256) ? 255 : volume);
-
- VideoEntry entry;
- entry.clear();
- entry.video = decoder;
- entry.x = x;
- entry.y = y;
- entry.id = id;
- entry.loop = loop;
- entry.enabled = true;
+ Video::QuickTimeDecoder *video = new Video::QuickTimeDecoder();
+ video->setChunkBeginOffset(_vm->getResourceOffset(ID_TMOV, id));
+ video->loadStream(_vm->getResource(ID_TMOV, id));
+
+ // Create the entry
+ VideoEntryPtr entry(new VideoEntry(video, id));
// Enable dither if necessary
checkEnableDither(entry);
- entry->start();
+ // Add it to the video list
+ _videos.push_back(entry);
- // Search for any deleted videos so we can take a formerly used slot
- for (uint32 i = 0; i < _videoStreams.size(); i++)
- if (!_videoStreams[i].video) {
- _videoStreams[i] = entry;
- return i;
- }
-
- // Otherwise, just add it to the list
- _videoStreams.push_back(entry);
- return _videoStreams.size() - 1;
+ return entry;
}
-VideoHandle VideoManager::createVideoHandle(const Common::String &filename, uint16 x, uint16 y, bool loop, byte volume) {
- // First, check to see if that video is already playing
- for (uint32 i = 0; i < _videoStreams.size(); i++)
- if (_videoStreams[i].filename == filename)
- return i;
+VideoEntryPtr VideoManager::open(const Common::String &fileName) {
+ // If this video is already playing, return that entry
+ VideoHandle oldHandle = findVideoHandle(fileName);
+ if (oldHandle._ptr)
+ return oldHandle._ptr;
// Otherwise, create a new entry
- VideoEntry entry;
- entry.clear();
- entry.video = new Video::QuickTimeDecoder();
- entry.x = x;
- entry.y = y;
- entry.filename = filename;
- entry.loop = loop;
- entry.enabled = true;
-
- Common::File *file = new Common::File();
- if (!file->open(filename)) {
- delete file;
- return NULL_VID_HANDLE;
+ Common::SeekableReadStream *stream = SearchMan.createReadStreamForMember(fileName);
+ if (!stream)
+ return VideoEntryPtr();
+
+ Video::VideoDecoder *video = new Video::QuickTimeDecoder();
+ if (!video->loadStream(stream)) {
+ // FIXME: Better error handling
+ delete video;
+ return VideoEntryPtr();
}
- entry->loadStream(file);
+ // Create the entry
+ VideoEntryPtr entry(new VideoEntry(video, fileName));
// Enable dither if necessary
checkEnableDither(entry);
- entry->setVolume(volume);
- entry->start();
-
- // Search for any deleted videos so we can take a formerly used slot
- for (uint32 i = 0; i < _videoStreams.size(); i++)
- if (!_videoStreams[i].video) {
- _videoStreams[i] = entry;
- return i;
- }
+ // Add it to the video list
+ _videos.push_back(entry);
- // Otherwise, just add it to the list
- _videoStreams.push_back(entry);
- return _videoStreams.size() - 1;
+ return entry;
}
VideoHandle VideoManager::findVideoHandleRiven(uint16 id) {
for (uint16 i = 0; i < _mlstRecords.size(); i++)
if (_mlstRecords[i].code == id)
- for (uint32 j = 0; j < _videoStreams.size(); j++)
- if (_videoStreams[j].video && _mlstRecords[i].movieID == _videoStreams[j].id)
- return j;
+ for (VideoList::iterator it = _videos.begin(); it != _videos.end(); it++)
+ if ((*it)->getID() == _mlstRecords[i].movieID)
+ return *it;
- return NULL_VID_HANDLE;
+ return VideoHandle();
}
VideoHandle VideoManager::findVideoHandle(uint16 id) {
- if (!id)
- return NULL_VID_HANDLE;
+ if (id == 0)
+ return VideoHandle();
- for (uint32 i = 0; i < _videoStreams.size(); i++)
- if (_videoStreams[i].video && _videoStreams[i].id == id)
- return i;
+ for (VideoList::iterator it = _videos.begin(); it != _videos.end(); it++)
+ if ((*it)->getID() == id)
+ return *it;
- return NULL_VID_HANDLE;
+ return VideoHandle();
}
-VideoHandle VideoManager::findVideoHandle(const Common::String &filename) {
- if (filename.empty())
- return NULL_VID_HANDLE;
+VideoHandle VideoManager::findVideoHandle(const Common::String &fileName) {
+ if (fileName.empty())
+ return VideoHandle();
- for (uint32 i = 0; i < _videoStreams.size(); i++)
- if (_videoStreams[i].video && _videoStreams[i].filename.equalsIgnoreCase(filename))
- return i;
-
- return NULL_VID_HANDLE;
-}
-
-int VideoManager::getCurFrame(VideoHandle handle) {
- assert(handle != NULL_VID_HANDLE);
- return _videoStreams[handle]->getCurFrame();
-}
-
-uint32 VideoManager::getFrameCount(VideoHandle handle) {
- assert(handle != NULL_VID_HANDLE);
- return _videoStreams[handle]->getFrameCount();
-}
+ for (VideoList::iterator it = _videos.begin(); it != _videos.end(); it++)
+ if ((*it)->getFileName().equalsIgnoreCase(fileName))
+ return *it;
-uint32 VideoManager::getTime(VideoHandle handle) {
- assert(handle != NULL_VID_HANDLE);
- return _videoStreams[handle]->getTime();
-}
-
-Audio::Timestamp VideoManager::getDuration(VideoHandle handle) {
- assert(handle != NULL_VID_HANDLE);
- return _videoStreams[handle]->getDuration();
-}
-
-bool VideoManager::endOfVideo(VideoHandle handle) {
- assert(handle != NULL_VID_HANDLE);
- return _videoStreams[handle].endOfVideo();
+ return VideoHandle();
}
bool VideoManager::isVideoPlaying() {
- for (uint32 i = 0; i < _videoStreams.size(); i++)
- if (!_videoStreams[i].endOfVideo())
+ for (VideoList::iterator it = _videos.begin(); it != _videos.end(); it++)
+ if (!(*it)->endOfVideo())
return true;
return false;
}
-void VideoManager::setVideoBounds(VideoHandle handle, Audio::Timestamp start, Audio::Timestamp end) {
- assert(handle != NULL_VID_HANDLE);
- _videoStreams[handle].start = start;
- _videoStreams[handle]->setEndTime(end);
- _videoStreams[handle]->seek(start);
-}
-
-void VideoManager::drawVideoFrame(VideoHandle handle, Audio::Timestamp time) {
- assert(handle != NULL_VID_HANDLE);
- _videoStreams[handle]->seek(time);
+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();
- delete _videoStreams[handle].video;
- _videoStreams[handle].clear();
-}
-
-void VideoManager::seekToTime(VideoHandle handle, Audio::Timestamp time) {
- assert(handle != NULL_VID_HANDLE);
- _videoStreams[handle]->seek(time);
-}
-
-void VideoManager::setVideoLooping(VideoHandle handle, bool loop) {
- assert(handle != NULL_VID_HANDLE);
- _videoStreams[handle].loop = loop;
-}
-
-Common::Rational VideoManager::getVideoRate(VideoHandle handle) const {
- assert(handle != NULL_VID_HANDLE);
- return _videoStreams[handle]->getRate();
+ handle->close();
}
-void VideoManager::setVideoRate(VideoHandle handle, const Common::Rational &rate) {
- assert(handle != NULL_VID_HANDLE);
- _videoStreams[handle]->setRate(rate);
+VideoManager::VideoList::iterator VideoManager::findEntry(VideoEntryPtr ptr) {
+ return Common::find(_videos.begin(), _videos.end(), ptr);
}
-void VideoManager::pauseMovie(VideoHandle handle, bool pause) {
- assert(handle != NULL_VID_HANDLE);
- _videoStreams[handle]->pauseVideo(pause);
+void VideoManager::removeEntry(VideoEntryPtr ptr) {
+ VideoManager::VideoList::iterator it = findEntry(ptr);
+ if (it != _videos.end())
+ _videos.erase(it);
}
-void VideoManager::checkEnableDither(VideoEntry &entry) {
+void VideoManager::checkEnableDither(VideoEntryPtr &entry) {
// If we're not dithering, bail out
if (!_enableDither)
return;
@@ -575,13 +584,13 @@ void VideoManager::checkEnableDither(VideoEntry &entry) {
// Set the palette
byte palette[256 * 3];
g_system->getPaletteManager()->grabPalette(palette, 0, 256);
- entry->setDitheringPalette(palette);
+ entry->_video->setDitheringPalette(palette);
- if (entry->getPixelFormat().bytesPerPixel != 1) {
- if (entry.filename.empty())
- error("Failed to set dither for video %d", entry.id);
+ if (entry->_video->getPixelFormat().bytesPerPixel != 1) {
+ if (entry->getFileName().empty())
+ error("Failed to set dither for video tMOV %d", entry->getID());
else
- error("Failed to set dither for video %s", entry.filename.c_str());
+ error("Failed to set dither for video %s", entry->getFileName().c_str());
}
}
diff --git a/engines/mohawk/video.h b/engines/mohawk/video.h
index deb09afe6b..106a32f8e2 100644
--- a/engines/mohawk/video.h
+++ b/engines/mohawk/video.h
@@ -23,9 +23,17 @@
#ifndef MOHAWK_VIDEO_H
#define MOHAWK_VIDEO_H
+#include "audio/timestamp.h"
#include "common/array.h"
+#include "common/list.h"
+#include "common/noncopyable.h"
+#include "common/ptr.h"
+#include "common/rational.h"
#include "graphics/pixelformat.h"
-#include "video/video_decoder.h"
+
+namespace Video {
+class VideoDecoder;
+}
namespace Mohawk {
@@ -43,29 +51,254 @@ struct MLSTRecord {
uint16 u1;
};
-struct VideoEntry {
+/**
+ * A video monitored by the VideoManager
+ */
+class VideoEntry : private Common::NonCopyable {
+ // The private members should be able to be manipulated by VideoManager
+ friend class VideoManager;
+
+private:
+ // Hide the destructor/constructor
+ // Only VideoManager should be allowed
+ VideoEntry();
+ VideoEntry(Video::VideoDecoder *video, const Common::String &fileName);
+ VideoEntry(Video::VideoDecoder *video, int id);
+
+public:
+ ~VideoEntry();
+
+ /**
+ * Convenience implicit cast to bool
+ */
+ operator bool() const { return isOpen(); }
+
+ /**
+ * Is the video open?
+ */
+ bool isOpen() const { return _video != 0; }
+
+ /**
+ * Close the video
+ */
+ void close();
+
+ /**
+ * Has the video reached its end?
+ */
+ bool endOfVideo() const;
+
+ /**
+ * Get the X position of where the video is displayed
+ */
+ uint16 getX() const { return _x; }
+
+ /**
+ * Get the Y position of where the video is displayed
+ */
+ uint16 getY() const { return _y; }
+
+ /**
+ * Is the video looping?
+ */
+ bool isLooping() const { return _loop; }
+
+ /**
+ * Is the video enabled? (Drawing to the screen)
+ */
+ bool isEnabled() const { return _enabled; }
+
+ /**
+ * Get the start time of the video bounds
+ */
+ const Audio::Timestamp &getStart() const { return _start; }
+
+ /**
+ * Get the file name of the video, or empty if by ID
+ */
+ const Common::String &getFileName() const { return _fileName; }
+
+ /**
+ * Get the ID of the video, or -1 if by file name
+ */
+ int getID() const { return _id; }
+
+ /**
+ * Get the current frame of the video
+ */
+ int getCurFrame() const;
+
+ /**
+ * Get the frame count of the video
+ */
+ uint32 getFrameCount() const;
+
+ /**
+ * Get the current time position of the video
+ */
+ uint32 getTime() const;
+
+ /**
+ * Get the duration of the video
+ */
+ Audio::Timestamp getDuration() const;
+
+ /**
+ * Get the current playback rate of the videos
+ */
+ Common::Rational getRate() const;
+
+ /**
+ * Move the x position of the video
+ */
+ void setX(uint16 x) { _x = x; }
+
+ /**
+ * Move the y position of the video
+ */
+ void setY(uint16 y) { _y = y; }
+
+ /**
+ * Move the video to the specified coordinates
+ */
+ void moveTo(uint16 x, uint16 y) { setX(x); setY(y); }
+
+ /**
+ * Center the video on the screen
+ */
+ void center();
+
+ /**
+ * Set the start time when using video bounds
+ */
+ void setStart(const Audio::Timestamp &time) { _start = time; }
+
+ /**
+ * Set the video to loop (true) or not (false)
+ */
+ void setLooping(bool loop) { _loop = loop; }
+
+ /**
+ * Set the video's enabled status
+ */
+ void setEnabled(bool enabled) { _enabled = enabled; }
+
+ /**
+ * Set the bounds of the video
+ *
+ * This automatically seeks to the start time
+ */
+ void setBounds(const Audio::Timestamp &startTime, const Audio::Timestamp &endTime);
+
+ /**
+ * Seek to the given time
+ */
+ void seek(const Audio::Timestamp &time);
+
+ /**
+ * Set the playback rate
+ */
+ void setRate(const Common::Rational &rate);
+
+ /**
+ * Pause the video
+ */
+ void pause(bool isPaused);
+
+ /**
+ * Start playing the video
+ */
+ void start();
+
+ /**
+ * Stop playing the video
+ */
+ void stop();
+
+ /**
+ * Is the video playing?
+ */
+ bool isPlaying() const;
+
+ /**
+ * Get the volume of the video
+ */
+ int getVolume() const;
+
+ /**
+ * Set the volume of the video
+ */
+ void setVolume(int volume);
+
+private:
+ // Non-changing variables
+ Video::VideoDecoder *_video;
+ Common::String _fileName; // External video files
+ int _id; // Internal Mohawk files
+
// Playback variables
- Video::VideoDecoder *video;
- uint16 x;
- uint16 y;
- bool loop;
- bool enabled;
- Audio::Timestamp start;
-
- // Identification
- Common::String filename; // External video files
- int id; // Internal Mohawk files
-
- // Helper functions
- Video::VideoDecoder *operator->() const { assert(video); return video; } // TODO: Remove this eventually
- void clear();
- bool endOfVideo();
+ uint16 _x;
+ uint16 _y;
+ bool _loop;
+ bool _enabled;
+ Audio::Timestamp _start;
};
-typedef int32 VideoHandle;
+typedef Common::SharedPtr<VideoEntry> VideoEntryPtr;
-enum {
- NULL_VID_HANDLE = -1
+/**
+ * A handle for manipulating a video
+ */
+class VideoHandle {
+ // The private members should be able to be manipulated by VideoManager
+ friend class VideoManager;
+
+public:
+ /**
+ * Default constructor
+ */
+ VideoHandle() {}
+
+ /**
+ * Copy constructor
+ */
+ VideoHandle(const VideoHandle &handle);
+
+ /**
+ * Is this handle pointing to a valid video entry?
+ */
+ bool isValid() const { return _ptr && _ptr->isOpen(); }
+
+ /**
+ * Convenience implicit cast to bool
+ */
+ operator bool() const { return isValid(); }
+
+ /**
+ * Simple equality operator
+ */
+ bool operator==(const VideoHandle &other) const { return _ptr.get() == other._ptr.get(); }
+
+ /**
+ * Simple inequality operator
+ */
+ bool operator!=(const VideoHandle &other) const { return !(*this == other); }
+
+ /**
+ * Convenience operator-> override to give direct access to the VideoEntry
+ */
+ VideoEntryPtr operator->() const { return _ptr; }
+
+private:
+ /**
+ * Constructor for internal VideoManager use
+ */
+ VideoHandle(VideoEntryPtr ptr);
+
+ /**
+ * The video entry this is associated with
+ */
+ VideoEntryPtr _ptr;
};
class VideoManager {
@@ -76,8 +309,8 @@ public:
// Generic movie functions
void playMovieBlocking(const Common::String &filename, uint16 x = 0, uint16 y = 0, bool clearScreen = false);
void playMovieBlockingCentered(const Common::String &filename, bool clearScreen = true);
- VideoHandle playMovie(const Common::String &filename, int16 x = -1, int16 y = -1, bool loop = false);
- VideoHandle playMovie(uint16 id, int16 x = -1, int16 y = -1, bool loop = false);
+ VideoHandle playMovie(const Common::String &filename);
+ VideoHandle playMovie(uint16 id);
bool updateMovies();
void pauseVideos();
void resumeVideos();
@@ -87,31 +320,18 @@ public:
// Riven-related functions
void activateMLST(uint16 mlstId, uint16 card);
void clearMLST();
- void enableMovieRiven(uint16 id);
- void disableMovieRiven(uint16 id);
void disableAllMovies();
VideoHandle playMovieRiven(uint16 id);
- void stopMovieRiven(uint16 id);
void playMovieBlockingRiven(uint16 id);
VideoHandle findVideoHandleRiven(uint16 id);
+ void stopMovieRiven(uint16 id);
// Handle functions
VideoHandle findVideoHandle(uint16 id);
- VideoHandle findVideoHandle(const Common::String &filename);
- int getCurFrame(VideoHandle handle);
- uint32 getFrameCount(VideoHandle handle);
- uint32 getTime(VideoHandle handle);
- Audio::Timestamp getDuration(VideoHandle videoHandle);
- bool endOfVideo(VideoHandle handle);
- void setVideoBounds(VideoHandle handle, Audio::Timestamp start, Audio::Timestamp end);
- void drawVideoFrame(VideoHandle handle, Audio::Timestamp time);
- void seekToTime(VideoHandle handle, Audio::Timestamp time);
- void setVideoLooping(VideoHandle handle, bool loop);
- Common::Rational getVideoRate(VideoHandle handle) const;
- void setVideoRate(VideoHandle handle, const Common::Rational &rate);
- void waitUntilMovieEnds(VideoHandle videoHandle);
- void delayUntilMovieEnds(VideoHandle videoHandle);
- void pauseMovie(VideoHandle videoHandle, bool pause);
+ VideoHandle findVideoHandle(const Common::String &fileName);
+ void waitUntilMovieEnds(VideoHandle handle);
+ void delayUntilMovieEnds(VideoHandle handle);
+ void drawVideoFrame(VideoHandle handle, const Audio::Timestamp &time);
private:
MohawkEngine *_vm;
@@ -120,14 +340,19 @@ private:
Common::Array<MLSTRecord> _mlstRecords;
// Keep tabs on any videos playing
- Common::Array<VideoEntry> _videoStreams;
+ typedef Common::List<VideoEntryPtr> VideoList;
+ VideoList _videos;
- VideoHandle createVideoHandle(uint16 id, uint16 x, uint16 y, bool loop, uint16 volume = 0xff);
- VideoHandle createVideoHandle(const Common::String &filename, uint16 x, uint16 y, bool loop, byte volume = 0xff);
+ // Utility functions for managing entries
+ VideoEntryPtr open(uint16 id);
+ VideoEntryPtr open(const Common::String &fileName);
+
+ VideoList::iterator findEntry(VideoEntryPtr ptr);
+ void removeEntry(VideoEntryPtr ptr);
// Dithering control
bool _enableDither;
- void checkEnableDither(VideoEntry &entry);
+ void checkEnableDither(VideoEntryPtr &entry);
};
} // End of namespace Mohawk
diff --git a/engines/mortevielle/detection_tables.h b/engines/mortevielle/detection_tables.h
index d244d15365..26611d4271 100644
--- a/engines/mortevielle/detection_tables.h
+++ b/engines/mortevielle/detection_tables.h
@@ -110,6 +110,23 @@ static const MortevielleGameDescription MortevielleGameDescriptions[] = {
}, Common::DE_DEU, kUseEngineDataFile
},
+ // French, provided by ultrapingu in bug ref #6575
+ {
+ {
+ "mortevielle",
+ "",
+ {
+ {"menu.mor", 0, "3fef0a3f8fca99fdcb6dbca8cbcef46f", 160},
+ {"dxx.mor", 0, "949e68e829ecd5ad29e36a00347a9e7e", 207744},
+ AD_LISTEND
+ },
+ Common::FR_FRA,
+ Common::kPlatformDOS,
+ ADGF_NO_FLAGS,
+ GUIO0()
+ }, Common::FR_FRA, kUseOriginalData
+ },
+
{ AD_TABLE_END_MARKER , Common::EN_ANY, kUseEngineDataFile}
};
diff --git a/engines/mortevielle/menu.cpp b/engines/mortevielle/menu.cpp
index c0b81b252a..b788ce9a71 100644
--- a/engines/mortevielle/menu.cpp
+++ b/engines/mortevielle/menu.cpp
@@ -682,8 +682,13 @@ void Menu::initMenu() {
if (!menuLoaded) {
// Load menu from game data using the original language
if (_vm->getOriginalLanguage() == Common::FR_FRA) {
- if (!f.open("menufr.mor"))
- error("Missing file - menufr.mor");
+ if (f.exists("menufr.mor")) {
+ if (!f.open("menufr.mor"))
+ error("Missing file - menufr.mor");
+ } else {
+ if (!f.open("menu.mor"))
+ error("Missing file - menu.mor");
+ }
} else { // Common::DE_DEU
if (!f.open("menual.mor"))
error("Missing file - menual.mor");
diff --git a/engines/parallaction/adlib.cpp b/engines/parallaction/adlib.cpp
index 7c1dd1681f..568ad190aa 100644
--- a/engines/parallaction/adlib.cpp
+++ b/engines/parallaction/adlib.cpp
@@ -25,7 +25,7 @@
#include "audio/fmopl.h"
#include "audio/mpu401.h"
-#include "audio/softsynth/emumidi.h"
+#include "audio/mididrv.h"
namespace Parallaction {
@@ -270,11 +270,13 @@ struct MelodicVoice {
int8 _octave;
};
-class AdLibDriver : public MidiDriver_Emulated {
+class AdLibDriver : public MidiDriver {
public:
- AdLibDriver(Audio::Mixer *mixer) : MidiDriver_Emulated(mixer) {
+ AdLibDriver(Audio::Mixer *mixer) {
for (uint i = 0; i < 16; ++i)
_channels[i].init(this, i);
+
+ _isOpen = false;
}
int open();
@@ -282,11 +284,13 @@ public:
void send(uint32 b);
MidiChannel *allocateChannel();
MidiChannel *getPercussionChannel() { return &_channels[9]; }
+ bool isOpen() const { return _isOpen; }
+ uint32 getBaseTempo() { return 1000000 / OPL::OPL::kDefaultCallbackFrequency; }
- bool isStereo() const { return false; }
- int getRate() const { return _mixer->getOutputRate(); }
-
- void generateSamples(int16 *buf, int len);
+ virtual void setTimerCallback(void *timerParam, Common::TimerManager::TimerProc timerProc) {
+ _adlibTimerProc = timerProc;
+ _adlibTimerParam = timerParam;
+ }
protected:
OPL::OPL *_opl;
@@ -320,6 +324,13 @@ protected:
void muteMelodicVoice(uint8 voice);
void initVoices();
+
+private:
+ void onTimer();
+
+ Common::TimerManager::TimerProc _adlibTimerProc;
+ void *_adlibTimerParam;
+ bool _isOpen;
};
MidiDriver *createAdLibDriver() {
@@ -348,10 +359,10 @@ int AdLibDriver::open() {
if (_isOpen)
return MERR_ALREADY_OPEN;
- MidiDriver_Emulated::open();
+ _isOpen = true;
_opl = OPL::Config::create();
- _opl->init(getRate());
+ _opl->init();
_opl->writeReg(0x1, 0x20); // set bit 5 (enable all waveforms)
// Reset the OPL registers.
@@ -364,7 +375,7 @@ int AdLibDriver::open() {
initVoices();
- _mixer->playStream(Audio::Mixer::kMusicSoundType, &_mixerSoundHandle, this, -1, Audio::Mixer::kMaxChannelVolume, 0, DisposeAfterUse::NO, true);
+ _opl->start(new Common::Functor0Mem<void, AdLibDriver>(this, &AdLibDriver::onTimer));
return 0;
}
@@ -373,7 +384,6 @@ void AdLibDriver::close() {
return;
_isOpen = false;
- _mixer->stopHandle(_mixerSoundHandle);
delete _opl;
}
@@ -777,9 +787,9 @@ MidiChannel *AdLibDriver::allocateChannel() {
return NULL;
}
-void AdLibDriver::generateSamples(int16 *buf, int len) {
- memset(buf, 0, sizeof(int16) * len);
- _opl->readBuffer(buf, len);
+void AdLibDriver::onTimer() {
+ if (_adlibTimerProc)
+ (*_adlibTimerProc)(_adlibTimerParam);
}
void AdLibDriver::initVoices() {
diff --git a/engines/pegasus/sound.cpp b/engines/pegasus/sound.cpp
index 5b437b81d4..ddcb2be010 100644
--- a/engines/pegasus/sound.cpp
+++ b/engines/pegasus/sound.cpp
@@ -59,7 +59,15 @@ void Sound::initFromAIFFFile(const Common::String &fileName) {
return;
}
- _stream = Audio::makeAIFFStream(file, DisposeAfterUse::YES);
+ Audio::RewindableAudioStream *stream = Audio::makeAIFFStream(file, DisposeAfterUse::YES);
+
+ _stream = dynamic_cast<Audio::SeekableAudioStream *>(stream);
+
+ if (!_stream) {
+ delete stream;
+ warning("AIFF stream '%s' is not seekable", fileName.c_str());
+ return;
+ }
}
void Sound::initFromQuickTime(const Common::String &fileName) {
diff --git a/engines/queen/midiadlib.cpp b/engines/queen/midiadlib.cpp
index 25175c21d7..f5bc0f4d58 100644
--- a/engines/queen/midiadlib.cpp
+++ b/engines/queen/midiadlib.cpp
@@ -23,118 +23,29 @@
#include "common/endian.h"
#include "common/textconsole.h"
-#include "audio/fmopl.h"
-#include "audio/softsynth/emumidi.h"
+#include "engines/queen/midiadlib.h"
namespace Queen {
-class AdLibMidiDriver : public MidiDriver_Emulated {
-public:
-
- AdLibMidiDriver(Audio::Mixer *mixer) : MidiDriver_Emulated(mixer) { _adlibWaveformSelect = 0; }
- ~AdLibMidiDriver() {}
-
- // MidiDriver
- int open();
- void close();
- void send(uint32 b);
- void metaEvent(byte type, byte *data, uint16 length);
- MidiChannel *allocateChannel() { return 0; }
- MidiChannel *getPercussionChannel() { return 0; }
-
- // AudioStream
- bool isStereo() const { return false; }
- int getRate() const { return _mixer->getOutputRate(); }
-
- // MidiDriver_Emulated
- void generateSamples(int16 *buf, int len);
-
-private:
-
- void handleMidiEvent0x90_NoteOn(int channel, int param1, int param2);
- void handleSequencerSpecificMetaEvent1(int channel, const uint8 *data);
- void handleSequencerSpecificMetaEvent2(uint8 value);
- void handleSequencerSpecificMetaEvent3(uint8 value);
-
- void adlibWrite(uint8 port, uint8 value);
- void adlibSetupCard();
- void adlibSetupChannels(int fl);
- void adlibResetAmpVibratoRhythm(int am, int vib, int kso);
- void adlibResetChannels();
- void adlibSetAmpVibratoRhythm();
- void adlibSetCSMKeyboardSplit();
- void adlibSetNoteMul(int mul);
- void adlibSetWaveformSelect(int fl);
- void adlibSetPitchBend(int channel, int range);
- void adlibPlayNote(int channel);
- uint8 adlibPlayNoteHelper(int channel, int note1, int note2, int oct);
- void adlibTurnNoteOff(int channel);
- void adlibTurnNoteOn(int channel, int note);
- void adlibSetupChannelFromSequence(int channel, const uint8 *src, int fl);
- void adlibSetupChannel(int channel, const uint16 *src, int fl);
- void adlibSetNoteVolume(int channel, int volume);
- void adlibSetupChannelHelper(int channel);
- void adlibSetChannel0x40(int channel);
- void adlibSetChannel0xC0(int channel);
- void adlibSetChannel0x60(int channel);
- void adlibSetChannel0x80(int channel);
- void adlibSetChannel0x20(int channel);
- void adlibSetChannel0xE0(int channel);
-
- FM_OPL *_opl;
- int _midiNumberOfChannels;
- int _adlibNoteMul;
- int _adlibWaveformSelect;
- int _adlibAMDepthEq48;
- int _adlibVibratoDepthEq14;
- int _adlibRhythmEnabled;
- int _adlibKeyboardSplitOn;
- int _adlibVibratoRhythm;
- uint8 _midiChannelsFreqTable[9];
- uint8 _adlibChannelsLevelKeyScalingTable[11];
- uint8 _adlibSetupChannelSequence1[14 * 18];
- uint16 _adlibSetupChannelSequence2[14];
- int16 _midiChannelsNote2Table[9];
- uint8 _midiChannelsNote1Table[9];
- uint8 _midiChannelsOctTable[9];
- uint16 _adlibChannelsVolume[11];
- uint16 _adlibMetaSequenceData[28];
-
- static const uint8 _adlibChannelsMappingTable1[];
- static const uint8 _adlibChannelsNoFeedback[];
- static const uint8 _adlibChannelsMappingTable2[];
- static const uint8 _adlibChannelsMappingTable3[];
- static const uint8 _adlibChannelsKeyScalingTable1[];
- static const uint8 _adlibChannelsKeyScalingTable2[];
- static const uint8 _adlibChannelsVolumeTable[];
- static const uint8 _adlibInitSequenceData1[];
- static const uint8 _adlibInitSequenceData2[];
- static const uint8 _adlibInitSequenceData3[];
- static const uint8 _adlibInitSequenceData4[];
- static const uint8 _adlibInitSequenceData5[];
- static const uint8 _adlibInitSequenceData6[];
- static const uint8 _adlibInitSequenceData7[];
- static const uint8 _adlibInitSequenceData8[];
- static const int16 _midiChannelsNoteTable[];
- static const int16 _midiNoteFreqTable[];
-};
-
int AdLibMidiDriver::open() {
- MidiDriver_Emulated::open();
- _opl = makeAdLibOPL(getRate());
+ _isOpen = true;
+ _opl = OPL::Config::create();
+ if (!_opl || !_opl->init())
+ error("Failed to create OPL");
+
adlibSetupCard();
for (int i = 0; i < 11; ++i) {
_adlibChannelsVolume[i] = 0;
adlibSetNoteVolume(i, 0);
adlibTurnNoteOff(i);
}
- _mixer->playStream(Audio::Mixer::kMusicSoundType, &_mixerSoundHandle, this, -1, Audio::Mixer::kMaxChannelVolume, 0, DisposeAfterUse::NO, true);
+
+ _opl->start(new Common::Functor0Mem<void, AdLibMidiDriver>(this, &AdLibMidiDriver::onTimer));
return 0;
}
void AdLibMidiDriver::close() {
- _mixer->stopHandle(_mixerSoundHandle);
- OPLDestroy(_opl);
+ delete _opl;
}
void AdLibMidiDriver::send(uint32 b) {
@@ -164,6 +75,11 @@ void AdLibMidiDriver::send(uint32 b) {
}
}
+void AdLibMidiDriver::setVolume(uint32 volume) {
+ for (int i = 0; i < _midiNumberOfChannels; ++i)
+ adlibSetChannelVolume(i, volume * 64 / 256 + 64);
+}
+
void AdLibMidiDriver::metaEvent(byte type, byte *data, uint16 length) {
int event = 0;
if (length > 4 && READ_BE_UINT32(data) == 0x3F00) {
@@ -192,9 +108,14 @@ void AdLibMidiDriver::metaEvent(byte type, byte *data, uint16 length) {
warning("Unhandled meta event %d len %d", event, length);
}
-void AdLibMidiDriver::generateSamples(int16 *data, int len) {
- memset(data, 0, sizeof(int16) * len);
- YM3812UpdateOne(_opl, data, len);
+void AdLibMidiDriver::setTimerCallback(void *timerParam, Common::TimerManager::TimerProc timerProc) {
+ _adlibTimerProc = timerProc;
+ _adlibTimerParam = timerParam;
+}
+
+void AdLibMidiDriver::onTimer() {
+ if (_adlibTimerProc)
+ (*_adlibTimerProc)(_adlibTimerParam);
}
void AdLibMidiDriver::handleSequencerSpecificMetaEvent1(int channel, const uint8 *data) {
@@ -238,7 +159,7 @@ void AdLibMidiDriver::handleMidiEvent0x90_NoteOn(int channel, int param1, int pa
}
void AdLibMidiDriver::adlibWrite(uint8 port, uint8 value) {
- OPLWriteReg(_opl, port, value);
+ _opl->writeReg(port, value);
}
void AdLibMidiDriver::adlibSetupCard() {
@@ -253,6 +174,7 @@ void AdLibMidiDriver::adlibSetupCard() {
_midiChannelsFreqTable[i] = 0;
}
memset(_adlibChannelsLevelKeyScalingTable, 127, 11);
+ memset(_adlibChannelsVolumeTable, 128, 11);
adlibSetupChannels(0);
adlibResetAmpVibratoRhythm(0, 0, 0);
adlibSetNoteMul(1);
@@ -448,6 +370,11 @@ void AdLibMidiDriver::adlibSetNoteVolume(int channel, int volume) {
}
}
+void AdLibMidiDriver::adlibSetChannelVolume(int channel, uint8 volume) {
+ if (channel < (_adlibRhythmEnabled ? 11 : 9))
+ _adlibChannelsVolumeTable[channel] = volume;
+}
+
void AdLibMidiDriver::adlibSetupChannelHelper(int channel) {
adlibSetAmpVibratoRhythm();
adlibSetCSMKeyboardSplit();
@@ -558,10 +485,6 @@ const uint8 AdLibMidiDriver::_adlibChannelsKeyScalingTable2[] = {
0, 3, 1, 4, 2, 5, 6, 9, 7, 10, 8, 11, 12, 15, 16, 255, 14, 255, 17, 255, 13, 255
};
-const uint8 AdLibMidiDriver::_adlibChannelsVolumeTable[] = {
- 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128
-};
-
const uint8 AdLibMidiDriver::_adlibInitSequenceData1[] = {
1, 1, 3, 15, 5, 0, 1, 3, 15, 0, 0, 0, 1, 0
};
@@ -617,8 +540,4 @@ const int16 AdLibMidiDriver::_midiNoteFreqTable[] = {
-363, -361, -359, -356, -354, -351, -349, -347, -344, -342, -339, -337
};
-MidiDriver *C_Player_CreateAdLibMidiDriver(Audio::Mixer *mixer) {
- return new AdLibMidiDriver(mixer);
-}
-
} // End of namespace Queen
diff --git a/engines/queen/midiadlib.h b/engines/queen/midiadlib.h
new file mode 100644
index 0000000000..8692e51840
--- /dev/null
+++ b/engines/queen/midiadlib.h
@@ -0,0 +1,128 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public 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/fmopl.h"
+#include "audio/mididrv.h"
+
+namespace Queen {
+
+class AdLibMidiDriver : public MidiDriver {
+public:
+
+ AdLibMidiDriver() {
+ _adlibWaveformSelect = 0;
+ _isOpen = false;
+ }
+
+ ~AdLibMidiDriver() {}
+
+ // MidiDriver
+ int open();
+ void close();
+ void send(uint32 b);
+ void metaEvent(byte type, byte *data, uint16 length);
+ MidiChannel *allocateChannel() { return 0; }
+ MidiChannel *getPercussionChannel() { return 0; }
+ void setTimerCallback(void *timerParam, Common::TimerManager::TimerProc timerProc);
+ bool isOpen() const { return _isOpen; }
+ uint32 getBaseTempo() { return 1000000 / OPL::OPL::kDefaultCallbackFrequency; }
+
+ void setVolume(uint32 volume);
+
+private:
+
+ void handleMidiEvent0x90_NoteOn(int channel, int param1, int param2);
+ void handleSequencerSpecificMetaEvent1(int channel, const uint8 *data);
+ void handleSequencerSpecificMetaEvent2(uint8 value);
+ void handleSequencerSpecificMetaEvent3(uint8 value);
+
+ void adlibWrite(uint8 port, uint8 value);
+ void adlibSetupCard();
+ void adlibSetupChannels(int fl);
+ void adlibResetAmpVibratoRhythm(int am, int vib, int kso);
+ void adlibResetChannels();
+ void adlibSetAmpVibratoRhythm();
+ void adlibSetCSMKeyboardSplit();
+ void adlibSetNoteMul(int mul);
+ void adlibSetWaveformSelect(int fl);
+ void adlibSetPitchBend(int channel, int range);
+ void adlibPlayNote(int channel);
+ uint8 adlibPlayNoteHelper(int channel, int note1, int note2, int oct);
+ void adlibTurnNoteOff(int channel);
+ void adlibTurnNoteOn(int channel, int note);
+ void adlibSetupChannelFromSequence(int channel, const uint8 *src, int fl);
+ void adlibSetupChannel(int channel, const uint16 *src, int fl);
+ void adlibSetNoteVolume(int channel, int volume);
+ void adlibSetChannelVolume(int channel, uint8 volume);
+ void adlibSetupChannelHelper(int channel);
+ void adlibSetChannel0x40(int channel);
+ void adlibSetChannel0xC0(int channel);
+ void adlibSetChannel0x60(int channel);
+ void adlibSetChannel0x80(int channel);
+ void adlibSetChannel0x20(int channel);
+ void adlibSetChannel0xE0(int channel);
+
+ void onTimer();
+
+ OPL::OPL *_opl;
+ int _midiNumberOfChannels;
+ int _adlibNoteMul;
+ int _adlibWaveformSelect;
+ int _adlibAMDepthEq48;
+ int _adlibVibratoDepthEq14;
+ int _adlibRhythmEnabled;
+ int _adlibKeyboardSplitOn;
+ int _adlibVibratoRhythm;
+ uint8 _midiChannelsFreqTable[9];
+ uint8 _adlibChannelsLevelKeyScalingTable[11];
+ uint8 _adlibSetupChannelSequence1[14 * 18];
+ uint16 _adlibSetupChannelSequence2[14];
+ int16 _midiChannelsNote2Table[9];
+ uint8 _midiChannelsNote1Table[9];
+ uint8 _midiChannelsOctTable[9];
+ uint16 _adlibChannelsVolume[11];
+ uint16 _adlibMetaSequenceData[28];
+ uint8 _adlibChannelsVolumeTable[11];
+
+ bool _isOpen;
+ Common::TimerManager::TimerProc _adlibTimerProc;
+ void *_adlibTimerParam;
+
+ static const uint8 _adlibChannelsMappingTable1[];
+ static const uint8 _adlibChannelsNoFeedback[];
+ static const uint8 _adlibChannelsMappingTable2[];
+ static const uint8 _adlibChannelsMappingTable3[];
+ static const uint8 _adlibChannelsKeyScalingTable1[];
+ static const uint8 _adlibChannelsKeyScalingTable2[];
+ static const uint8 _adlibInitSequenceData1[];
+ static const uint8 _adlibInitSequenceData2[];
+ static const uint8 _adlibInitSequenceData3[];
+ static const uint8 _adlibInitSequenceData4[];
+ static const uint8 _adlibInitSequenceData5[];
+ static const uint8 _adlibInitSequenceData6[];
+ static const uint8 _adlibInitSequenceData7[];
+ static const uint8 _adlibInitSequenceData8[];
+ static const int16 _midiChannelsNoteTable[];
+ static const int16 _midiNoteFreqTable[];
+};
+
+} // End of namespace Queen
diff --git a/engines/queen/music.cpp b/engines/queen/music.cpp
index 93d6527622..9f74aab915 100644
--- a/engines/queen/music.cpp
+++ b/engines/queen/music.cpp
@@ -23,6 +23,7 @@
#include "common/config-manager.h"
#include "common/events.h"
+#include "queen/midiadlib.h"
#include "queen/music.h"
#include "queen/queen.h"
#include "queen/resource.h"
@@ -33,8 +34,6 @@
namespace Queen {
-extern MidiDriver *C_Player_CreateAdLibMidiDriver(Audio::Mixer *);
-
MidiMusic::MidiMusic(QueenEngine *vm)
: _isPlaying(false), _isLooping(false),
_randomLoop(false), _masterVolume(192),
@@ -69,7 +68,7 @@ MidiMusic::MidiMusic(QueenEngine *vm)
// if (READ_LE_UINT16(_musicData + 2) != infoOffset) {
// defaultAdLibVolume = _musicData[infoOffset];
// }
- _driver = C_Player_CreateAdLibMidiDriver(vm->_mixer);
+ _driver = new AdLibMidiDriver();
} else {
_driver = MidiDriver::createMidi(dev);
if (_nativeMT32) {
@@ -117,6 +116,9 @@ void MidiMusic::setVolume(int volume) {
if (_channelsTable[i])
_channelsTable[i]->volume(_channelsVolume[i] * _masterVolume / 255);
}
+
+ if (_adlib)
+ static_cast<AdLibMidiDriver*>(_driver)->setVolume(volume);
}
void MidiMusic::playSong(uint16 songNum) {
diff --git a/engines/saga/detection_tables.h b/engines/saga/detection_tables.h
index 2f72e7a13c..98009326ae 100644
--- a/engines/saga/detection_tables.h
+++ b/engines/saga/detection_tables.h
@@ -192,9 +192,9 @@ static const SAGAGameDescription gameDescriptions[] = {
ADGF_DEMO,
GUIO1(GUIO_NOSPEECH)
},
- GID_ITE, // Game id
- GF_OLD_ITE_DOS, // features
- ITE_DEFAULT_SCENE, // Starting scene number
+ GID_ITE,
+ GF_ITE_DOS_DEMO,
+ ITE_DEFAULT_SCENE,
&ITEDemo_Resources,
ARRAYSIZE(ITEDEMO_GameFonts),
ITEDEMO_GameFonts,
@@ -393,6 +393,33 @@ static const SAGAGameDescription gameDescriptions[] = {
NULL,
},
+ // Inherit the earth - German Wyrmkeep combined Windows/Mac/Linux CD
+
+ // Supplied by user nicode in bug #6428.
+ // Contains voices.rsc instead of "Inherit the Earth Voices".
+ {
+ {
+ "ite",
+ "Multi-OS CD Version",
+ {
+ {"ite.rsc", GAME_RESOURCEFILE, "420e09cfdbb4db12baefd4bc81d8e154", 8925349},
+ {"scripts.rsc", GAME_SCRIPTFILE, "a891405405edefc69c9d6c420c868b84", -1},
+ { NULL, 0, NULL, 0}
+ },
+ Common::DE_DEU,
+ Common::kPlatformUnknown,
+ ADGF_CD,
+ GUIO0()
+ },
+ GID_ITE,
+ 0,
+ ITE_DEFAULT_SCENE,
+ &ITE_Resources,
+ ARRAYSIZE(ITE_GameFonts),
+ ITE_GameFonts,
+ NULL,
+ },
+
// Inherit the earth - Italian Wyrmkeep combined Windows/Mac/Linux CD (fan translation)
// version is different from the other Wyrmkeep re-releases in that it does
diff --git a/engines/saga/introproc_ihnm.cpp b/engines/saga/introproc_ihnm.cpp
index fc28d2372f..dc3f55e8c1 100644
--- a/engines/saga/introproc_ihnm.cpp
+++ b/engines/saga/introproc_ihnm.cpp
@@ -68,7 +68,7 @@ int Scene::IHNMStartProc() {
// Play the title music
_vm->_music->play(1, MUSIC_NORMAL);
// Play title screen
- playTitle(2, 17);
+ playTitle(2, _vm->_music->isAdlib() ? 20 : 27);
}
}
} else {
@@ -150,7 +150,7 @@ bool Scene::checkKey() {
break;
case Common::EVENT_KEYDOWN:
// Don't react to modifier keys alone. The original did
- // non, and the user may want to change scaler without
+ // not, and the user may want to change scaler without
// terminating the intro.
if (event.kbd.ascii)
res = true;
diff --git a/engines/saga/introproc_ite.cpp b/engines/saga/introproc_ite.cpp
index 0b129dbcc0..3c10cbe1dd 100644
--- a/engines/saga/introproc_ite.cpp
+++ b/engines/saga/introproc_ite.cpp
@@ -59,6 +59,11 @@ namespace Saga {
#define RID_ITE_FAIREPATH_SCENE 1564
#define RID_ITE_FAIRETENT_SCENE 1567
+// Intro scenes - DOS demo
+#define RID_ITE_INTRO_ANIM_SCENE_DOS_DEMO 298
+#define RID_ITE_CAVE_SCENE_DOS_DEMO 302
+#define RID_ITE_VALLEY_SCENE_DOS_DEMO 310
+
// ITE intro music
#define MUSIC_INTRO 9
#define MUSIC_TITLE_THEME 10
@@ -75,22 +80,24 @@ LoadSceneParams ITE_IntroList[] = {
{RID_ITE_FAIRETENT_SCENE, kLoadByResourceId, Scene::SC_ITEIntroFaireTentProc, false, kTransitionNoFade, 0, NO_CHAPTER_CHANGE}
};
-int Scene::ITEStartProc() {
- size_t scenesCount;
- size_t i;
+LoadSceneParams ITE_DOS_Demo_IntroList[] = {
+ {RID_ITE_INTRO_ANIM_SCENE_DOS_DEMO, kLoadByResourceId, Scene::SC_ITEIntroAnimProc, false, kTransitionNoFade, 0, NO_CHAPTER_CHANGE},
+ {RID_ITE_CAVE_SCENE_DOS_DEMO, kLoadByResourceId, Scene::SC_ITEIntroCaveDemoProc, false, kTransitionFade, 0, NO_CHAPTER_CHANGE},
+ {RID_ITE_VALLEY_SCENE_DOS_DEMO, kLoadByResourceId, Scene::SC_ITEIntroValleyProc, false, kTransitionFade, 0, NO_CHAPTER_CHANGE},
+};
+int Scene::ITEStartProc() {
LoadSceneParams firstScene;
LoadSceneParams tempScene;
+ bool dosDemo = (_vm->getFeatures() & GF_ITE_DOS_DEMO);
+ int scenesCount = (!dosDemo) ? ARRAYSIZE(ITE_IntroList) : ARRAYSIZE(ITE_DOS_Demo_IntroList);
- scenesCount = ARRAYSIZE(ITE_IntroList);
-
- for (i = 0; i < scenesCount; i++) {
- tempScene = ITE_IntroList[i];
+ for (int i = 0; i < scenesCount; i++) {
+ tempScene = (!dosDemo) ? ITE_IntroList[i] : ITE_DOS_Demo_IntroList[i];
tempScene.sceneDescriptor = _vm->_resource->convertResourceId(tempScene.sceneDescriptor);
_vm->_scene->queueScene(tempScene);
}
-
firstScene.loadFlag = kLoadBySceneNumber;
firstScene.sceneDescriptor = _vm->getStartSceneNumber();
firstScene.sceneSkipTarget = true;
@@ -437,6 +444,53 @@ int Scene::ITEIntroCaveCommonProc(int param, int caveScene) {
return 0;
}
+int Scene::ITEIntroCaveDemoProc(int param) {
+ Event event;
+ EventColumns *eventColumns = NULL;
+
+ switch (param) {
+ case SCENE_BEGIN:
+ // Begin palette cycling animation for candles
+ event.type = kEvTOneshot;
+ event.code = kPalAnimEvent;
+ event.op = kEventCycleStart;
+ event.time = 0;
+ eventColumns = _vm->_events->chain(eventColumns, event);
+
+ // Queue narrator dialogue list
+ for (int i = 0; i < 11; i++) {
+ // Play voice
+ event.type = kEvTOneshot;
+ event.code = kVoiceEvent;
+ event.op = kEventPlay;
+ event.param = i;
+ event.time = _vm->_sndRes->getVoiceLength(i);
+ _vm->_events->chain(eventColumns, event);
+ }
+
+ // End scene after last dialogue over
+ event.type = kEvTOneshot;
+ event.code = kSceneEvent;
+ event.op = kEventEnd;
+ event.time = INTRO_VOICE_PAD;
+ _vm->_events->chain(eventColumns, event);
+
+ break;
+ case SCENE_END:
+ break;
+
+ default:
+ warning("Illegal scene procedure parameter");
+ break;
+ }
+
+ return 0;
+}
+
+int Scene::SC_ITEIntroCaveDemoProc(int param, void *refCon) {
+ return ((Scene *)refCon)->ITEIntroCaveDemoProc(param);
+}
+
// Handles first introductory cave painting scene
int Scene::SC_ITEIntroCave1Proc(int param, void *refCon) {
return ((Scene *)refCon)->ITEIntroCaveCommonProc(param, 1);
diff --git a/engines/saga/music.cpp b/engines/saga/music.cpp
index d20882ca26..663f5991d0 100644
--- a/engines/saga/music.cpp
+++ b/engines/saga/music.cpp
@@ -31,6 +31,7 @@
#include "audio/mididrv.h"
#include "audio/midiparser.h"
#include "audio/midiparser_qt.h"
+#include "audio/miles.h"
#include "audio/decoders/raw.h"
#include "common/config-manager.h"
#include "common/file.h"
@@ -42,24 +43,51 @@ namespace Saga {
#define MUSIC_SUNSPOT 26
MusicDriver::MusicDriver() : _isGM(false) {
-
- MidiPlayer::createDriver();
-
MidiDriver::DeviceHandle dev = MidiDriver::detectDevice(MDT_MIDI | MDT_ADLIB | MDT_PREFER_GM);
_driverType = MidiDriver::getMusicType(dev);
+ switch (_driverType) {
+ case MT_ADLIB:
+ if (Common::File::exists("INSTR.AD") && Common::File::exists("INSTR.OPL")) {
+ _milesAudioMode = true;
+ _driver = Audio::MidiDriver_Miles_AdLib_create("INSTR.AD", "INSTR.OPL");
+ } else if (Common::File::exists("SAMPLE.AD") && Common::File::exists("SAMPLE.OPL")) {
+ _milesAudioMode = true;
+ _driver = Audio::MidiDriver_Miles_AdLib_create("SAMPLE.AD", "SAMPLE.OPL");
+ } else {
+ _milesAudioMode = false;
+ MidiPlayer::createDriver();
+ }
+ break;
+ case MT_MT32:
+ _milesAudioMode = true;
+ _driver = Audio::MidiDriver_Miles_MT32_create("");
+ break;
+ default:
+ _milesAudioMode = false;
+ MidiPlayer::createDriver();
+ break;
+ }
+
int retValue = _driver->open();
if (retValue == 0) {
- if (_nativeMT32)
- _driver->sendMT32Reset();
- else
- _driver->sendGMReset();
+ if (_driverType != MT_ADLIB) {
+ if (_driverType == MT_MT32 || _nativeMT32)
+ _driver->sendMT32Reset();
+ else
+ _driver->sendGMReset();
+ }
_driver->setTimerCallback(this, &timerCallback);
}
}
void MusicDriver::send(uint32 b) {
+ if (_milesAudioMode) {
+ _driver->send(b);
+ return;
+ }
+
if ((b & 0xF0) == 0xC0 && !_isGM && !_nativeMT32) {
// Remap MT32 instruments to General Midi
b = (b & 0xFFFF00FF) | MidiDriver::_mt32ToGm[(b >> 8) & 0xFF] << 8;
@@ -249,7 +277,11 @@ void Music::play(uint32 resourceId, MusicFlags flags) {
debug(2, "Music::play %d, %d", resourceId, flags);
- if (isPlaying() && _trackNumber == resourceId) {
+ if (isPlaying() && _trackNumber == resourceId)
+ return;
+
+ if (_vm->getFeatures() & GF_ITE_DOS_DEMO) {
+ warning("TODO: Music::play %d, %d for ITE DOS demo", resourceId, flags);
return;
}
diff --git a/engines/saga/music.h b/engines/saga/music.h
index 2106fb6fa6..2e7cc4c5ec 100644
--- a/engines/saga/music.h
+++ b/engines/saga/music.h
@@ -61,6 +61,7 @@ public:
protected:
MusicType _driverType;
bool _isGM;
+ bool _milesAudioMode;
};
class Music {
@@ -79,6 +80,8 @@ public:
void setVolume(int volume, int time = 1);
int getVolume() { return _currentVolume; }
+ bool isAdlib() const { return _player->isAdlib(); }
+
Common::Array<int32> _songTable;
private:
diff --git a/engines/saga/saga.cpp b/engines/saga/saga.cpp
index 3d38b3ea52..b94bb66bb4 100644
--- a/engines/saga/saga.cpp
+++ b/engines/saga/saga.cpp
@@ -117,6 +117,9 @@ SagaEngine::SagaEngine(OSystem *syst, const SAGAGameDescription *gameDesc)
SearchMan.addSubDirectoryMatching(gameDataDir, "music");
SearchMan.addSubDirectoryMatching(gameDataDir, "sound");
+ // Location of Miles audio files (sample.ad and sample.opl) in IHNM
+ SearchMan.addSubDirectoryMatching(gameDataDir, "drivers");
+
// The Multi-OS version puts the voices file in the root directory of
// the CD. The rest of the data files are in game/itedata
SearchMan.addSubDirectoryMatching(gameDataDir, "game/itedata");
@@ -634,6 +637,9 @@ void SagaEngine::syncSoundSettings() {
}
void SagaEngine::pauseEngineIntern(bool pause) {
+ if (!_render || !_music)
+ return;
+
bool engineIsPaused = (_render->getFlags() & RF_RENDERPAUSE);
if (engineIsPaused == pause)
return;
diff --git a/engines/saga/saga.h b/engines/saga/saga.h
index 6077e55094..9c7b2f5295 100644
--- a/engines/saga/saga.h
+++ b/engines/saga/saga.h
@@ -137,9 +137,7 @@ enum GameFileTypes {
enum GameFeatures {
GF_ITE_FLOPPY = 1 << 0,
-#if 0
- GF_OLD_ITE_DOS = 1 << 1, // Currently unused
-#endif
+ GF_ITE_DOS_DEMO = 1 << 1,
GF_EXTRA_ITE_CREDITS = 1 << 2,
GF_8BIT_UNSIGNED_PCM = 1 << 3
};
diff --git a/engines/saga/scene.cpp b/engines/saga/scene.cpp
index 4fa15d09e5..efd4c371b1 100644
--- a/engines/saga/scene.cpp
+++ b/engines/saga/scene.cpp
@@ -866,15 +866,13 @@ void Scene::loadSceneDescriptor(uint32 resourceId) {
_sceneDescription.reset();
- if (resourceId == 0) {
+ if (resourceId == 0)
return;
- }
_vm->_resource->loadResource(_sceneContext, resourceId, sceneDescriptorData);
+ ByteArrayReadStreamEndian readS(sceneDescriptorData, _sceneContext->isBigEndian());
- if (sceneDescriptorData.size() == 16) {
- ByteArrayReadStreamEndian readS(sceneDescriptorData, _sceneContext->isBigEndian());
-
+ if (sceneDescriptorData.size() == 14 || sceneDescriptorData.size() == 16) {
_sceneDescription.flags = readS.readSint16();
_sceneDescription.resourceListResourceId = readS.readSint16();
_sceneDescription.endSlope = readS.readSint16();
@@ -882,7 +880,10 @@ void Scene::loadSceneDescriptor(uint32 resourceId) {
_sceneDescription.scriptModuleNumber = readS.readUint16();
_sceneDescription.sceneScriptEntrypointNumber = readS.readUint16();
_sceneDescription.startScriptEntrypointNumber = readS.readUint16();
- _sceneDescription.musicResourceId = readS.readSint16();
+ if (sceneDescriptorData.size() == 16)
+ _sceneDescription.musicResourceId = readS.readSint16();
+ } else {
+ warning("Scene::loadSceneDescriptor: Unknown scene descriptor data size (%d)", sceneDescriptorData.size());
}
}
diff --git a/engines/saga/scene.h b/engines/saga/scene.h
index 410713c5d5..1a710cfe9c 100644
--- a/engines/saga/scene.h
+++ b/engines/saga/scene.h
@@ -400,12 +400,14 @@ class Scene {
static int SC_ITEIntroTreeHouseProc(int param, void *refCon);
static int SC_ITEIntroFairePathProc(int param, void *refCon);
static int SC_ITEIntroFaireTentProc(int param, void *refCon);
+ static int SC_ITEIntroCaveDemoProc(int param, void *refCon);
private:
EventColumns *queueIntroDialogue(EventColumns *eventColumns, int n_dialogues, const IntroDialogue dialogue[]);
EventColumns *queueCredits(int delta_time, int duration, int n_credits, const IntroCredit credits[]);
int ITEIntroAnimProc(int param);
int ITEIntroCaveCommonProc(int param, int caveScene);
+ int ITEIntroCaveDemoProc(int param);
int ITEIntroValleyProc(int param);
int ITEIntroTreeHouseProc(int param);
int ITEIntroFairePathProc(int param);
diff --git a/engines/saga/script.cpp b/engines/saga/script.cpp
index 94b26c8da3..3cc6586432 100644
--- a/engines/saga/script.cpp
+++ b/engines/saga/script.cpp
@@ -977,19 +977,15 @@ void Script::opSpeak(SCRIPTOP_PARAMS) {
// now data contains last string index
-#if 0
- if (_vm->getFeatures() & GF_OLD_ITE_DOS) { // special ITE dos
+ if (_vm->getFeatures() & GF_ITE_DOS_DEMO) {
if ((_vm->_scene->currentSceneNumber() == ITE_DEFAULT_SCENE) &&
(iparam1 >= 288) && (iparam1 <= (RID_SCENE1_VOICE_END - RID_SCENE1_VOICE_START + 288))) {
sampleResourceId = RID_SCENE1_VOICE_START + iparam1 - 288;
}
} else {
-#endif
if (thread->_voiceLUT->size() > uint16(first))
sampleResourceId = (*thread->_voiceLUT)[uint16(first)];
-#if 0
}
-#endif
if (sampleResourceId < 0 || sampleResourceId > 4000)
sampleResourceId = -1;
diff --git a/engines/saga/sndres.cpp b/engines/saga/sndres.cpp
index 39578e96f0..b8d03c9c08 100644
--- a/engines/saga/sndres.cpp
+++ b/engines/saga/sndres.cpp
@@ -327,9 +327,18 @@ bool SndRes::load(ResourceContext *context, uint32 resourceId, SoundBuffer &buff
result = true;
} break;
case kSoundAIFF: {
- Audio::SeekableAudioStream *audStream = Audio::makeAIFFStream(READ_STREAM(soundResourceLength), DisposeAfterUse::YES);
- buffer.stream = audStream;
- buffer.streamLength = audStream->getLength();
+ Audio::RewindableAudioStream *audStream = Audio::makeAIFFStream(READ_STREAM(soundResourceLength), DisposeAfterUse::YES);
+ Audio::SeekableAudioStream *seekStream = dynamic_cast<Audio::SeekableAudioStream *>(audStream);
+
+ if (!seekStream) {
+ warning("AIFF file is not seekable");
+ delete audStream;
+ result = false;
+ break;
+ }
+
+ buffer.stream = seekStream;
+ buffer.streamLength = seekStream->getLength();
result = true;
} break;
case kSoundVOC: {
diff --git a/engines/sci/detection.cpp b/engines/sci/detection.cpp
index 9a41127f6d..bac9b3467a 100644
--- a/engines/sci/detection.cpp
+++ b/engines/sci/detection.cpp
@@ -371,8 +371,8 @@ static const ADExtraGuiOptionsMap optionsList[] = {
{
GAMEOPTION_EGA_UNDITHER,
{
- _s("EGA undithering"),
- _s("Enable undithering in EGA games"),
+ _s("Skip EGA dithering pass (full color backgrounds)"),
+ _s("Skip dithering pass in EGA games, graphics are shown with full colors"),
"disable_dithering",
false
}
diff --git a/engines/sci/detection_tables.h b/engines/sci/detection_tables.h
index 7cadcfc27e..55305c4b42 100644
--- a/engines/sci/detection_tables.h
+++ b/engines/sci/detection_tables.h
@@ -2445,6 +2445,16 @@ static const struct ADGameDescription SciGameDescriptions[] = {
AD_LISTEND},
Common::EN_ANY, Common::kPlatformDOS, ADGF_UNSTABLE, GUIO5(GUIO_NOSPEECH, GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+ // Lighthouse - Japanese DOS (from m_kiewitz)
+ // Executable scanning reports "3.000.000", VERSION file reports "1.0C"
+ {"lighthouse", "", {
+ {"resmap.001", 0, "18e0ac1597fe1cf6dc663118fe983e3b", 7885},
+ {"ressci.001", 0, "14e922c47b92156377cb49e241691792", 99573473},
+ {"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) },
+
// Lighthouse - Spanish DOS (from jvprat)
// Executable scanning reports "3.000.000", VERSION file reports "1.1"
{"lighthouse", "", {
diff --git a/engines/sci/engine/kfile.cpp b/engines/sci/engine/kfile.cpp
index c56eb09482..61ac76d0a7 100644
--- a/engines/sci/engine/kfile.cpp
+++ b/engines/sci/engine/kfile.cpp
@@ -933,6 +933,11 @@ reg_t kRestoreGame(EngineState *s, int argc, reg_t *argv) {
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;
}
diff --git a/engines/sci/engine/script.cpp b/engines/sci/engine/script.cpp
index 6034378ef6..36e33ccfa6 100644
--- a/engines/sci/engine/script.cpp
+++ b/engines/sci/engine/script.cpp
@@ -121,8 +121,8 @@ void Script::load(int script_nr, ResourceManager *resMan, ScriptPatcher *scriptP
//
// TODO: Remove this once such a mechanism is in place
if (script->size > 65535)
- error("TODO: SCI script %d is over 64KB - it's %d bytes long. This can't "
- "be handled at the moment, thus stopping", script_nr, script->size);
+ warning("TODO: SCI script %d is over 64KB - it's %d bytes long. This can't "
+ "be fully handled at the moment", script_nr, script->size);
}
uint extraLocalsWorkaround = 0;
@@ -1086,9 +1086,14 @@ void Script::initializeObjectsSci3(SegManager *segMan, SegmentId segmentId) {
const byte *seeker = getSci3ObjectsPointer();
while (READ_SCI11ENDIAN_UINT16(seeker) == SCRIPT_OBJECT_MAGIC_NUMBER) {
- reg_t reg = make_reg(segmentId, seeker - _buf);
- Object *obj = scriptObjInit(reg);
+ // We call setSegment and setOffset directly here, instead of using
+ // make_reg, as in large scripts, seeker - _buf can be larger than
+ // a 16-bit integer
+ reg_t reg;
+ reg.setSegment(segmentId);
+ reg.setOffset(seeker - _buf);
+ Object *obj = scriptObjInit(reg);
obj->setSuperClassSelector(segMan->getClassAddress(obj->getSuperClassSelector().getOffset(), SCRIPT_GET_LOCK, 0));
seeker += READ_SCI11ENDIAN_UINT16(seeker + 2);
}
diff --git a/engines/sci/graphics/transitions.cpp b/engines/sci/graphics/transitions.cpp
index ccc7a4389a..c75580a077 100644
--- a/engines/sci/graphics/transitions.cpp
+++ b/engines/sci/graphics/transitions.cpp
@@ -124,6 +124,10 @@ void GfxTransitions::setup(int16 number, bool blackoutFlag) {
}
}
+// Checks, if current time is lower than expected time of the current frame
+// If current time is higher, then we have to assume that the current system isn't capable
+// of either rendering frames that fast or has 60hz V'Sync enabled, which is why we drop frames
+// in those cases, so that transitions work as fast as expected.
bool GfxTransitions::doCreateFrame(uint32 shouldBeAtMsec) {
uint32 msecPos = g_system->getMillis() - _transitionStartTime;
@@ -132,12 +136,16 @@ bool GfxTransitions::doCreateFrame(uint32 shouldBeAtMsec) {
return false;
}
-void GfxTransitions::updateScreenAndWait(uint32 shouldBeAtMsec) {
+void GfxTransitions::updateScreen() {
Common::Event ev;
while (g_system->getEventManager()->pollEvent(ev)) {} // discard all events
g_system->updateScreen();
+}
+
+void GfxTransitions::updateScreenAndWait(uint32 shouldBeAtMsec) {
+ updateScreen();
// if we have still some time left, delay accordingly
uint32 msecPos = g_system->getMillis() - _transitionStartTime;
if (shouldBeAtMsec > msecPos)
@@ -257,6 +265,9 @@ void GfxTransitions::doTransition(int16 number, bool blackoutFlag) {
warning("Transitions: ID %d not implemented", number);
setNewScreen(blackoutFlag);
}
+ // Just to make sure that the current frame is shown in case we skipped the last update-call b/c of timing
+ updateScreen();
+ debugC(kDebugLevelGraphics, "Transition took %d milliseconds", g_system->getMillis() - _transitionStartTime);
}
void GfxTransitions::setNewPalette(bool blackoutFlag) {
@@ -348,7 +359,9 @@ void GfxTransitions::pixelation(bool blackoutFlag) {
copyRectToScreen(pixelRect, blackoutFlag);
if ((stepNr & 0x3FF) == 0) {
msecCount += 9;
- updateScreenAndWait(msecCount);
+ if (doCreateFrame(msecCount)) {
+ updateScreenAndWait(msecCount);
+ }
}
stepNr++;
} while (mask != 0x40);
@@ -372,7 +385,9 @@ void GfxTransitions::blocks(bool blackoutFlag) {
copyRectToScreen(blockRect, blackoutFlag);
if ((stepNr & 7) == 0) {
msecCount += 5;
- updateScreenAndWait(msecCount);
+ if (doCreateFrame(msecCount)) {
+ updateScreenAndWait(msecCount);
+ }
}
stepNr++;
} while (mask != 0x40);
@@ -392,7 +407,9 @@ void GfxTransitions::straight(int16 number, bool blackoutFlag) {
copyRectToScreen(newScreenRect, blackoutFlag);
if ((stepNr & 1) == 0) {
msecCount += 2;
- updateScreenAndWait(msecCount);
+ if (doCreateFrame(msecCount)) {
+ updateScreenAndWait(msecCount);
+ }
}
stepNr++;
newScreenRect.translate(-1, 0);
@@ -405,7 +422,9 @@ void GfxTransitions::straight(int16 number, bool blackoutFlag) {
copyRectToScreen(newScreenRect, blackoutFlag);
if ((stepNr & 1) == 0) {
msecCount += 2;
- updateScreenAndWait(msecCount);
+ if (doCreateFrame(msecCount)) {
+ updateScreenAndWait(msecCount);
+ }
}
stepNr++;
newScreenRect.translate(1, 0);
@@ -417,7 +436,9 @@ void GfxTransitions::straight(int16 number, bool blackoutFlag) {
while (newScreenRect.top >= _picRect.top) {
copyRectToScreen(newScreenRect, blackoutFlag);
msecCount += 4;
- updateScreenAndWait(msecCount);
+ if (doCreateFrame(msecCount)) {
+ updateScreenAndWait(msecCount);
+ }
stepNr++;
newScreenRect.translate(0, -1);
}
@@ -428,7 +449,9 @@ void GfxTransitions::straight(int16 number, bool blackoutFlag) {
while (newScreenRect.bottom <= _picRect.bottom) {
copyRectToScreen(newScreenRect, blackoutFlag);
msecCount += 4;
- updateScreenAndWait(msecCount);
+ if (doCreateFrame(msecCount)) {
+ updateScreenAndWait(msecCount);
+ }
stepNr++;
newScreenRect.translate(0, 1);
}
@@ -534,7 +557,6 @@ void GfxTransitions::scroll(int16 number) {
// Copy over final position just in case
_screen->copyRectToScreen(newScreenRect);
- g_system->updateScreen();
}
// Vertically displays new screen starting from center - works on _picRect area
@@ -552,7 +574,9 @@ void GfxTransitions::verticalRollFromCenter(bool blackoutFlag) {
copyRectToScreen(leftRect, blackoutFlag); leftRect.translate(-1, 0);
copyRectToScreen(rightRect, blackoutFlag); rightRect.translate(1, 0);
msecCount += 3;
- updateScreenAndWait(msecCount);
+ if (doCreateFrame(msecCount)) {
+ updateScreenAndWait(msecCount);
+ }
}
}
@@ -567,7 +591,9 @@ void GfxTransitions::verticalRollToCenter(bool blackoutFlag) {
copyRectToScreen(leftRect, blackoutFlag); leftRect.translate(1, 0);
copyRectToScreen(rightRect, blackoutFlag); rightRect.translate(-1, 0);
msecCount += 3;
- updateScreenAndWait(msecCount);
+ if (doCreateFrame(msecCount)) {
+ updateScreenAndWait(msecCount);
+ }
}
}
@@ -586,7 +612,9 @@ void GfxTransitions::horizontalRollFromCenter(bool blackoutFlag) {
copyRectToScreen(upperRect, blackoutFlag); upperRect.translate(0, -1);
copyRectToScreen(lowerRect, blackoutFlag); lowerRect.translate(0, 1);
msecCount += 4;
- updateScreenAndWait(msecCount);
+ if (doCreateFrame(msecCount)) {
+ updateScreenAndWait(msecCount);
+ }
}
}
@@ -601,7 +629,9 @@ void GfxTransitions::horizontalRollToCenter(bool blackoutFlag) {
copyRectToScreen(upperRect, blackoutFlag); upperRect.translate(0, 1);
copyRectToScreen(lowerRect, blackoutFlag); lowerRect.translate(0, -1);
msecCount += 4;
- updateScreenAndWait(msecCount);
+ if (doCreateFrame(msecCount)) {
+ updateScreenAndWait(msecCount);
+ }
}
}
@@ -633,7 +663,9 @@ void GfxTransitions::diagonalRollFromCenter(bool blackoutFlag) {
copyRectToScreen(leftRect, blackoutFlag); leftRect.translate(-1, 0); leftRect.top--; leftRect.bottom++;
copyRectToScreen(rightRect, blackoutFlag); rightRect.translate(1, 0); rightRect.top--; rightRect.bottom++;
msecCount += 4;
- updateScreenAndWait(msecCount);
+ if (doCreateFrame(msecCount)) {
+ updateScreenAndWait(msecCount);
+ }
}
}
@@ -652,7 +684,9 @@ void GfxTransitions::diagonalRollToCenter(bool blackoutFlag) {
copyRectToScreen(leftRect, blackoutFlag); leftRect.translate(1, 0);
copyRectToScreen(rightRect, blackoutFlag); rightRect.translate(-1, 0);
msecCount += 4;
- updateScreenAndWait(msecCount);
+ if (doCreateFrame(msecCount)) {
+ updateScreenAndWait(msecCount);
+ }
}
}
diff --git a/engines/sci/graphics/transitions.h b/engines/sci/graphics/transitions.h
index ae9ca4b48a..05842a4d2a 100644
--- a/engines/sci/graphics/transitions.h
+++ b/engines/sci/graphics/transitions.h
@@ -89,6 +89,7 @@ private:
void diagonalRollFromCenter(bool blackoutFlag);
void diagonalRollToCenter(bool blackoutFlag);
bool doCreateFrame(uint32 shouldBeAtMsec);
+ void updateScreen();
void updateScreenAndWait(uint32 shouldBeAtMsec);
GfxScreen *_screen;
diff --git a/engines/sci/sound/audio.cpp b/engines/sci/sound/audio.cpp
index 8e35d6b055..fb9a3f17b9 100644
--- a/engines/sci/sound/audio.cpp
+++ b/engines/sci/sound/audio.cpp
@@ -391,18 +391,13 @@ Audio::RewindableAudioStream *AudioPlayer::getAudioStream(uint32 number, uint32
} else if (audioRes->size > 4 && READ_BE_UINT32(audioRes->data) == MKTAG('F','O','R','M')) {
// AIFF detected
Common::SeekableReadStream *waveStream = new Common::MemoryReadStream(audioRes->data, audioRes->size, DisposeAfterUse::NO);
+ Audio::RewindableAudioStream *rewindStream = Audio::makeAIFFStream(waveStream, DisposeAfterUse::YES);
+ audioSeekStream = dynamic_cast<Audio::SeekableAudioStream *>(rewindStream);
- // Calculate samplelen from AIFF header
- int waveSize = 0, waveRate = 0;
- byte waveFlags = 0;
- bool ret = Audio::loadAIFFFromStream(*waveStream, waveSize, waveRate, waveFlags);
- if (!ret)
- error("Failed to load AIFF from stream");
-
- *sampleLen = (waveFlags & Audio::FLAG_16BITS ? waveSize >> 1 : waveSize) * 60 / waveRate;
-
- waveStream->seek(0, SEEK_SET);
- audioStream = Audio::makeAIFFStream(waveStream, DisposeAfterUse::YES);
+ if (!audioSeekStream) {
+ warning("AIFF file is not seekable");
+ delete rewindStream;
+ }
} else if (audioRes->size > 14 && READ_BE_UINT16(audioRes->data) == 1 && READ_BE_UINT16(audioRes->data + 2) == 1
&& READ_BE_UINT16(audioRes->data + 4) == 5 && READ_BE_UINT32(audioRes->data + 10) == 0x00018051) {
// Mac snd detected
diff --git a/engines/sci/sound/drivers/adlib.cpp b/engines/sci/sound/drivers/adlib.cpp
index fcfda2f532..4f557be95e 100644
--- a/engines/sci/sound/drivers/adlib.cpp
+++ b/engines/sci/sound/drivers/adlib.cpp
@@ -27,7 +27,7 @@
#include "common/textconsole.h"
#include "audio/fmopl.h"
-#include "audio/softsynth/emumidi.h"
+#include "audio/mididrv.h"
#include "sci/resource.h"
#include "sci/sound/drivers/mididriver.h"
@@ -43,29 +43,30 @@ namespace Sci {
// FIXME: We don't seem to be sending the polyphony init data, so disable this for now
#define ADLIB_DISABLE_VOICE_MAPPING
-class MidiDriver_AdLib : public MidiDriver_Emulated {
+class MidiDriver_AdLib : public MidiDriver {
public:
enum {
kVoices = 9,
kRhythmKeys = 62
};
- MidiDriver_AdLib(Audio::Mixer *mixer) : MidiDriver_Emulated(mixer), _playSwitch(true), _masterVolume(15), _rhythmKeyMap(0), _opl(0) { }
+ MidiDriver_AdLib(Audio::Mixer *mixer) :_playSwitch(true), _masterVolume(15), _rhythmKeyMap(0), _opl(0), _isOpen(false) { }
virtual ~MidiDriver_AdLib() { }
// MidiDriver
+ int open() { return -1; } // Dummy implementation (use openAdLib)
int openAdLib(bool isSCI0);
void close();
void send(uint32 b);
MidiChannel *allocateChannel() { return NULL; }
MidiChannel *getPercussionChannel() { return NULL; }
+ bool isOpen() const { return _isOpen; }
+ uint32 getBaseTempo() { return 1000000 / OPL::OPL::kDefaultCallbackFrequency; }
- // AudioStream
- bool isStereo() const { return _stereo; }
- int getRate() const { return _mixer->getOutputRate(); }
+ // MidiDriver
+ void setTimerCallback(void *timerParam, Common::TimerManager::TimerProc timerProc);
- // MidiDriver_Emulated
- void generateSamples(int16 *buf, int len);
+ void onTimer();
void setVolume(byte volume);
void playSwitch(bool play);
@@ -133,6 +134,7 @@ private:
bool _stereo;
bool _isSCI0;
OPL::OPL *_opl;
+ bool _isOpen;
bool _playSwitch;
int _masterVolume;
Channel _channels[MIDI_CHANNELS];
@@ -140,6 +142,9 @@ private:
byte *_rhythmKeyMap;
Common::Array<AdLibPatch> _patches;
+ Common::TimerManager::TimerProc _adlibTimerProc;
+ void *_adlibTimerParam;
+
void loadInstrument(const byte *ins);
void voiceOn(int voice, int note, int velocity);
void voiceOff(int voice);
@@ -215,14 +220,12 @@ static const int ym3812_note[13] = {
};
int MidiDriver_AdLib::openAdLib(bool isSCI0) {
- int rate = _mixer->getOutputRate();
-
_stereo = STEREO;
debug(3, "ADLIB: Starting driver in %s mode", (isSCI0 ? "SCI0" : "SCI1"));
_isSCI0 = isSCI0;
- _opl = OPL::Config::create(isStereo() ? OPL::Config::kDualOpl2 : OPL::Config::kOpl2);
+ _opl = OPL::Config::create(_stereo ? OPL::Config::kDualOpl2 : OPL::Config::kOpl2);
// Try falling back to mono, thus plain OPL2 emualtor, when no Dual OPL2 is available.
if (!_opl && _stereo) {
@@ -233,22 +236,24 @@ int MidiDriver_AdLib::openAdLib(bool isSCI0) {
if (!_opl)
return -1;
- _opl->init(rate);
+ if (!_opl->init()) {
+ delete _opl;
+ _opl = nullptr;
+ return -1;
+ }
setRegister(0xBD, 0);
setRegister(0x08, 0);
setRegister(0x01, 0x20);
- MidiDriver_Emulated::open();
+ _isOpen = true;
- _mixer->playStream(Audio::Mixer::kPlainSoundType, &_mixerSoundHandle, this, -1, _mixer->kMaxChannelVolume, 0, DisposeAfterUse::NO);
+ _opl->start(new Common::Functor0Mem<void, MidiDriver_AdLib>(this, &MidiDriver_AdLib::onTimer));
return 0;
}
void MidiDriver_AdLib::close() {
- _mixer->stopHandle(_mixerSoundHandle);
-
delete _opl;
delete[] _rhythmKeyMap;
}
@@ -325,10 +330,14 @@ void MidiDriver_AdLib::send(uint32 b) {
}
}
-void MidiDriver_AdLib::generateSamples(int16 *data, int len) {
- if (isStereo())
- len <<= 1;
- _opl->readBuffer(data, len);
+void MidiDriver_AdLib::setTimerCallback(void *timerParam, Common::TimerManager::TimerProc timerProc) {
+ _adlibTimerProc = timerProc;
+ _adlibTimerParam = timerParam;
+}
+
+void MidiDriver_AdLib::onTimer() {
+ if (_adlibTimerProc)
+ (*_adlibTimerProc)(_adlibTimerParam);
// Increase the age of the notes
for (int i = 0; i < kVoices; i++) {
@@ -684,7 +693,7 @@ void MidiDriver_AdLib::setVelocityReg(int regOffset, int velocity, int kbScaleLe
if (!_playSwitch)
velocity = 0;
- if (isStereo()) {
+ if (_stereo) {
int velLeft = velocity;
int velRight = velocity;
@@ -734,7 +743,7 @@ void MidiDriver_AdLib::setRegister(int reg, int value, int channels) {
_opl->write(0x221, value);
}
- if (isStereo()) {
+ if (_stereo) {
if (channels & kRightChannel) {
_opl->write(0x222, reg);
_opl->write(0x223, value);
diff --git a/engines/scumm/detection_tables.h b/engines/scumm/detection_tables.h
index d42a7251d9..5a994cb699 100644
--- a/engines/scumm/detection_tables.h
+++ b/engines/scumm/detection_tables.h
@@ -306,9 +306,9 @@ static const GameSettings gameVariantsTable[] = {
// Humongous Entertainment Scumm Version 7.2
{"airport", "", 0, GID_HEGAME, 6, 72, MDT_NONE, GF_USE_KEY, UNK, GUIO3(GUIO_NOLAUNCHLOAD, GUIO_NOMIDI, GUIO_NOASPECT)},
+ {"farm", "", 0, GID_HEGAME, 6, 72, MDT_NONE, GF_USE_KEY, UNK, GUIO3(GUIO_NOLAUNCHLOAD, GUIO_NOMIDI, GUIO_NOASPECT)},
// Changed o_getResourceSize to cover all resource types
- {"farm", "", 0, GID_HEGAME, 6, 73, MDT_NONE, GF_USE_KEY, UNK, GUIO3(GUIO_NOLAUNCHLOAD, GUIO_NOMIDI, GUIO_NOASPECT)},
{"puttzoo", "", 0, GID_PUTTZOO, 6, 73, MDT_NONE, GF_USE_KEY, UNK, GUIO3(GUIO_NOLAUNCHLOAD, GUIO_NOMIDI, GUIO_NOASPECT)},
{"puttzoo", "HE 72", 0, GID_PUTTZOO, 6, 72, MDT_NONE, GF_USE_KEY, UNK, GUIO3(GUIO_NOLAUNCHLOAD, GUIO_NOMIDI, GUIO_NOASPECT)},
{"puttzoo", "HE 98.5", 0, GID_PUTTZOO, 6, 98, MDT_NONE, GF_USE_KEY | GF_HE_985, UNK, GUIO3(GUIO_NOLAUNCHLOAD, GUIO_NOMIDI, GUIO_NOASPECT)},
diff --git a/engines/scumm/players/player_ad.cpp b/engines/scumm/players/player_ad.cpp
index adcda68e10..4d4be2c3c2 100644
--- a/engines/scumm/players/player_ad.cpp
+++ b/engines/scumm/players/player_ad.cpp
@@ -27,6 +27,7 @@
#include "scumm/saveload.h"
#include "audio/fmopl.h"
+#include "audio/mixer.h"
#include "common/textconsole.h"
#include "common/config-manager.h"
@@ -35,26 +36,19 @@ namespace Scumm {
#define AD_CALLBACK_FREQUENCY 472
-Player_AD::Player_AD(ScummEngine *scumm, Audio::Mixer *mixer)
- : _vm(scumm), _mixer(mixer), _rate(mixer->getOutputRate()) {
+Player_AD::Player_AD(ScummEngine *scumm)
+ : _vm(scumm) {
_opl2 = OPL::Config::create();
- if (!_opl2->init(_rate)) {
+ if (!_opl2->init()) {
error("Could not initialize OPL2 emulator");
}
- _samplesPerCallback = _rate / AD_CALLBACK_FREQUENCY;
- _samplesPerCallbackRemainder = _rate % AD_CALLBACK_FREQUENCY;
- _samplesTillCallback = 0;
- _samplesTillCallbackRemainder = 0;
-
memset(_registerBackUpTable, 0, sizeof(_registerBackUpTable));
writeReg(0x01, 0x00);
writeReg(0xBD, 0x00);
writeReg(0x08, 0x00);
writeReg(0x01, 0x20);
- _mixer->playStream(Audio::Mixer::kPlainSoundType, &_soundHandle, this, -1, Audio::Mixer::kMaxChannelVolume, 0, DisposeAfterUse::NO, true);
-
_engineMusicTimer = 0;
_soundPlaying = -1;
@@ -78,11 +72,11 @@ Player_AD::Player_AD(ScummEngine *scumm, Audio::Mixer *mixer)
_musicVolume = _sfxVolume = 255;
_isSeeking = false;
+
+ _opl2->start(new Common::Functor0Mem<void, Player_AD>(this, &Player_AD::onTimer), AD_CALLBACK_FREQUENCY);
}
Player_AD::~Player_AD() {
- _mixer->stopHandle(_soundHandle);
-
stopAllSounds();
Common::StackLock lock(_mutex);
delete _opl2;
@@ -244,36 +238,14 @@ void Player_AD::saveLoadWithSerializer(Serializer *ser) {
}
}
-int Player_AD::readBuffer(int16 *buffer, const int numSamples) {
+void Player_AD::onTimer() {
Common::StackLock lock(_mutex);
- int len = numSamples;
-
- while (len > 0) {
- if (!_samplesTillCallback) {
- if (_curOffset) {
- updateMusic();
- }
-
- updateSfx();
-
- _samplesTillCallback = _samplesPerCallback;
- _samplesTillCallbackRemainder += _samplesPerCallbackRemainder;
- if (_samplesTillCallbackRemainder >= AD_CALLBACK_FREQUENCY) {
- ++_samplesTillCallback;
- _samplesTillCallbackRemainder -= AD_CALLBACK_FREQUENCY;
- }
- }
-
- const int samplesToRead = MIN(len, _samplesTillCallback);
- _opl2->readBuffer(buffer, samplesToRead);
-
- buffer += samplesToRead;
- len -= samplesToRead;
- _samplesTillCallback -= samplesToRead;
+ if (_curOffset) {
+ updateMusic();
}
- return numSamples;
+ updateSfx();
}
void Player_AD::setupVolume() {
diff --git a/engines/scumm/players/player_ad.h b/engines/scumm/players/player_ad.h
index 63a8503f47..63fda3cc7c 100644
--- a/engines/scumm/players/player_ad.h
+++ b/engines/scumm/players/player_ad.h
@@ -26,7 +26,6 @@
#include "scumm/music.h"
#include "audio/audiostream.h"
-#include "audio/mixer.h"
#include "common/mutex.h"
@@ -41,9 +40,9 @@ class ScummEngine;
/**
* Sound output for v3/v4 AdLib data.
*/
-class Player_AD : public MusicEngine, public Audio::AudioStream {
+class Player_AD : public MusicEngine {
public:
- Player_AD(ScummEngine *scumm, Audio::Mixer *mixer);
+ Player_AD(ScummEngine *scumm);
virtual ~Player_AD();
// MusicEngine API
@@ -56,18 +55,12 @@ public:
virtual void saveLoadWithSerializer(Serializer *ser);
- // AudioStream API
- virtual int readBuffer(int16 *buffer, const int numSamples);
- virtual bool isStereo() const { return false; }
- virtual bool endOfData() const { return false; }
- virtual int getRate() const { return _rate; }
+ // Timer callback
+ void onTimer();
private:
ScummEngine *const _vm;
Common::Mutex _mutex;
- Audio::Mixer *const _mixer;
- const int _rate;
- Audio::SoundHandle _soundHandle;
void setupVolume();
int _musicVolume;
@@ -75,11 +68,6 @@ private:
OPL::OPL *_opl2;
- int _samplesPerCallback;
- int _samplesPerCallbackRemainder;
- int _samplesTillCallback;
- int _samplesTillCallbackRemainder;
-
int _soundPlaying;
int32 _engineMusicTimer;
diff --git a/engines/scumm/scumm-md5.h b/engines/scumm/scumm-md5.h
index 1cbefee105..a836cf12bc 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 May 10 14:23:43 2015
+ This file was generated by the md5table tool on Sun Jun 28 03:19:52 2015
DO NOT EDIT MANUALLY!
*/
@@ -272,7 +272,7 @@ static const MD5Table md5table[] = {
{ "5c21fc49aee8f46e58fef21579e614a1", "thinker1", "", "", -1, Common::EN_USA, Common::kPlatformUnknown },
{ "5c9cecbd2952ccec14c9ecebf5822a34", "puttzoo", "HE 100", "", -1, Common::EN_ANY, Common::kPlatformIOS },
{ "5d88b9d6a88e6f8e90cded9d01b7f082", "loom", "VGA", "VGA", 8307, Common::EN_ANY, Common::kPlatformDOS },
- { "5dda73606533d66a4c3f4f9ea6e842af", "farm", "", "", 87061, Common::RU_RUS, Common::kPlatformWindows },
+ { "5dda73606533d66a4c3f4f9ea6e842af", "farm", "HE 73", "", 87061, Common::RU_RUS, Common::kPlatformWindows },
{ "5e8fb66971a60e523e5afbc4c129c0e8", "socks", "HE 85", "", -1, Common::EN_USA, Common::kPlatformUnknown },
{ "5ebb57234b2fe5c5dff641e00184ad81", "freddi", "HE 73", "", -1, Common::FR_FRA, Common::kPlatformWindows },
{ "5fbe557049892eb4b709d90916ec97ca", "indy3", "EGA", "EGA", 5361, Common::EN_ANY, Common::kPlatformDOS },
@@ -465,7 +465,7 @@ static const MD5Table md5table[] = {
{ "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 },
- { "a2386da005672cbd5136f4f27a626c5f", "farm", "", "", 87061, 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 },
{ "a3036878840720fbefa41e6965fa4a0a", "samnmax", "Floppy", "Floppy", -1, Common::EN_ANY, Common::kPlatformDOS },
@@ -480,7 +480,7 @@ static const MD5Table md5table[] = {
{ "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 },
- { "a85856675429fe88051744f755b72f93", "farm", "", "", -1, Common::EN_ANY, Common::kPlatformWindows },
+ { "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 },
{ "a9543ef0d79bcb47cd76ec197ad0a967", "puttmoon", "", "", -1, Common::EN_ANY, Common::kPlatform3DO },
@@ -650,7 +650,7 @@ static const MD5Table md5table[] = {
{ "ee785fe2569bc9965526e774f7ab86f1", "spyfox", "HE 99", "", -1, Common::FR_FRA, Common::kPlatformMacintosh },
{ "ee8cfeb76e55d43a01c25e0865a9db76", "puttrace", "HE 98", "Demo", 13135, Common::NL_NLD, Common::kPlatformMacintosh },
{ "eea4d9ac2fb6f145945a308e8866915b", "maniac", "C64", "", -1, Common::EN_ANY, Common::kPlatformC64 },
- { "eeb606c2d2ec877a712a9f20c10bcdda", "farm", "", "", 87034, Common::NL_NLD, Common::kPlatformMacintosh },
+ { "eeb606c2d2ec877a712a9f20c10bcdda", "farm", "HE 73", "", 87034, Common::NL_NLD, Common::kPlatformMacintosh },
{ "ef347474f3c7be3b29584eaa133cca05", "samnmax", "Floppy", "Floppy", -1, Common::FR_FRA, Common::kPlatformDOS },
{ "ef71a322b6530ac45b1a070f7c0795f7", "moonbase", "Demo", "Demo", -1, Common::EN_ANY, Common::kPlatformWindows },
{ "ef74d9071d4e564b037cb44bd6774de7", "fbear", "HE 62", "", -1, Common::HE_ISR, Common::kPlatformDOS },
@@ -679,7 +679,7 @@ static const MD5Table md5table[] = {
{ "faa89ab5e67ba4eebb4399f584f7490c", "pajama3", "", "Mini Game", 13911, Common::FR_FRA, Common::kPlatformWindows },
{ "fb66aa42de21675116346213f176a366", "monkey", "VGA", "VGA", -1, Common::IT_ITA, Common::kPlatformAmiga },
{ "fbb697d89d2beca87360a145f467bdae", "PuttTime", "HE 90", "Demo", -1, Common::DE_DEU, Common::kPlatformUnknown },
- { "fbbbb38a81fc9d6a61d509278390a290", "farm", "", "", -1, Common::EN_ANY, Common::kPlatformMacintosh },
+ { "fbbbb38a81fc9d6a61d509278390a290", "farm", "HE 73", "", -1, Common::EN_ANY, Common::kPlatformMacintosh },
{ "fbdd947d21e8f5bac6d6f7a316af1c5a", "spyfox", "", "Demo", 15693, Common::EN_ANY, Common::kPlatformUnknown },
{ "fc53ce0e5f6562b1c1e1b4b8203acafb", "samnmax", "Floppy", "Floppy", -1, Common::ES_ESP, Common::kPlatformDOS },
{ "fc6b6148e80d67939d9a18697c0f626a", "monkey", "EGA", "EGA", 8367, Common::DE_DEU, Common::kPlatformDOS },
diff --git a/engines/scumm/scumm.cpp b/engines/scumm/scumm.cpp
index 99b4e695bb..24d676a1ff 100644
--- a/engines/scumm/scumm.cpp
+++ b/engines/scumm/scumm.cpp
@@ -316,6 +316,7 @@ ScummEngine::ScummEngine(OSystem *syst, const DetectorResult &dr)
_NES_lastTalkingActor = 0;
_NES_talkColor = 0;
_keepText = false;
+ _msgCount = 0;
_costumeLoader = NULL;
_costumeRenderer = NULL;
_2byteFontPtr = 0;
@@ -1904,7 +1905,7 @@ void ScummEngine::setupMusic(int midi) {
// EGA/VGA. However, we support multi MIDI for that game and we cannot
// support this with the Player_AD code at the moment. The reason here
// is that multi MIDI is supported internally by our iMuse output.
- _musicEngine = new Player_AD(this, _mixer);
+ _musicEngine = new Player_AD(this);
} else if (_game.version >= 3 && _game.heversion <= 62) {
MidiDriver *nativeMidiDriver = 0;
MidiDriver *adlibMidiDriver = 0;
diff --git a/engines/scumm/scumm.h b/engines/scumm/scumm.h
index 30b4d61880..6e0adc3ff3 100644
--- a/engines/scumm/scumm.h
+++ b/engines/scumm/scumm.h
@@ -1182,6 +1182,7 @@ protected:
byte _charsetBuffer[512];
bool _keepText;
+ byte _msgCount;
int _nextLeft, _nextTop;
diff --git a/engines/scumm/string.cpp b/engines/scumm/string.cpp
index d60c4c6a50..3049fbcf62 100644
--- a/engines/scumm/string.cpp
+++ b/engines/scumm/string.cpp
@@ -283,6 +283,7 @@ bool ScummEngine::handleNextCharsetCode(Actor *a, int *code) {
switch (c) {
case 1:
c = 13; // new line
+ _msgCount = _screenWidth;
endLoop = true;
break;
case 2:
@@ -293,6 +294,7 @@ bool ScummEngine::handleNextCharsetCode(Actor *a, int *code) {
case 3:
_haveMsg = (_game.version >= 7) ? 1 : 0xFF;
_keepText = false;
+ _msgCount = 0;
endLoop = true;
break;
case 8:
@@ -573,6 +575,9 @@ void ScummEngine::CHARSET_1() {
#endif
restoreCharsetBg();
}
+ _msgCount = 0;
+ } else if (_game.version <= 2) {
+ _talkDelay += _msgCount * _defaultTalkDelay;
}
if (_game.version > 3) {
@@ -600,6 +605,7 @@ void ScummEngine::CHARSET_1() {
// End of text reached, set _haveMsg accordingly
_haveMsg = (_game.version >= 7) ? 2 : 1;
_keepText = false;
+ _msgCount = 0;
break;
}
@@ -648,6 +654,7 @@ void ScummEngine::CHARSET_1() {
}
if (_game.version <= 3) {
_charset->printChar(c, false);
+ _msgCount += 1;
} else {
if (_game.features & GF_16BIT_COLOR) {
// HE games which use sprites for subtitles
diff --git a/engines/sherlock/animation.cpp b/engines/sherlock/animation.cpp
index 21d63633d3..bbf7c913b7 100644
--- a/engines/sherlock/animation.cpp
+++ b/engines/sherlock/animation.cpp
@@ -31,7 +31,7 @@ static const int NO_FRAMES = FRAMES_END;
Animation::Animation(SherlockEngine *vm) : _vm(vm) {
}
-bool Animation::play(const Common::String &filename, int minDelay, int fade,
+bool Animation::play(const Common::String &filename, bool intro, int minDelay, int fade,
bool setPalette, int speed) {
Events &events = *_vm->_events;
Screen &screen = *_vm->_screen;
@@ -39,7 +39,7 @@ bool Animation::play(const Common::String &filename, int minDelay, int fade,
int soundNumber = 0;
// Check for any any sound frames for the given animation
- const int *soundFrames = checkForSoundFrames(filename);
+ const int *soundFrames = checkForSoundFrames(filename, intro);
// Add on the VDX extension
Common::String vdxName = filename + ".vdx";
@@ -102,12 +102,19 @@ bool Animation::play(const Common::String &filename, int minDelay, int fade,
if (frameNumber++ == *soundFrames) {
++soundNumber;
++soundFrames;
- Common::String fname = _soundLibraryFilename.empty() ?
- Common::String::format("%s%01d", filename.c_str(), soundNumber) :
- Common::String::format("%s%02d", filename.c_str(), soundNumber);
+
+ Common::String sampleFilename;
+
+ if (!intro) {
+ // regular animation, append 1-digit number
+ sampleFilename = Common::String::format("%s%01d", filename.c_str(), soundNumber);
+ } else {
+ // intro animation, append 2-digit number
+ sampleFilename = Common::String::format("%s%02d", filename.c_str(), soundNumber);
+ }
if (sound._voices)
- sound.playSound(fname, WAIT_RETURN_IMMEDIATELY, 100, _soundLibraryFilename.c_str());
+ sound.playSound(sampleFilename, WAIT_RETURN_IMMEDIATELY, 100, _soundLibraryFilename.c_str());
}
events.wait(speed * 3);
@@ -133,6 +140,133 @@ bool Animation::play(const Common::String &filename, int minDelay, int fade,
return !skipped && !_vm->shouldQuit();
}
+bool Animation::play3DO(const Common::String &filename, bool intro, int minDelay, bool fadeFromGrey,
+ int speed) {
+ Events &events = *_vm->_events;
+ Screen &screen = *_vm->_screen;
+ Sound &sound = *_vm->_sound;
+ int soundNumber = 0;
+
+ bool fadeActive = false;
+ uint16 fadeLimitColor = 0;
+ uint16 fadeLimitColorRed = 0;
+ uint16 fadeLimitColorGreen = 0;
+ uint16 fadeLimitColorBlue = 0;
+
+ // Check for any any sound frames for the given animation
+ const int *soundFrames = checkForSoundFrames(filename, intro);
+
+ // Add the VDX extension
+ Common::String indexName = "prologue/" + filename + ".3dx";
+
+ // Load the animation
+ Common::File *indexStream = new Common::File();
+
+ if (!indexStream->open(indexName)) {
+ warning("unable to open %s\n", indexName.c_str());
+ return false;
+ }
+
+ // Load initial image
+ Common::String graphicsName = "prologue/" + filename + ".3da";
+ ImageFile3DO images(graphicsName, kImageFile3DOType_Animation);
+
+ events.wait(minDelay);
+
+ if (fadeFromGrey) {
+ fadeActive = true;
+ fadeLimitColor = 0xCE59; // RGB565: 25, 50, 25 -> "grey"
+ }
+
+ int frameNumber = 0;
+ Common::Point pt;
+ bool skipped = false;
+ while (!_vm->shouldQuit()) {
+ // Get the next sprite to display
+ int imageFrame = indexStream->readSint16BE();
+
+ if (imageFrame == -2) {
+ // End of animation reached
+ break;
+ } else if (imageFrame != -1) {
+ // Read position from either animation stream or the sprite frame itself
+ if (imageFrame < 0) {
+ imageFrame += 32768;
+ pt.x = indexStream->readUint16BE();
+ pt.y = indexStream->readUint16BE();
+ } else {
+ pt = images[imageFrame]._offset;
+ }
+
+ // 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
+ if (!fadeActive) {
+ screen.transBlitFrom(images[imageFrame]._frame, pt);
+ } else {
+ // Fade active, blit to backbuffer1
+ screen._backBuffer1.transBlitFrom(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
+
+ if (fadeActive) {
+ // process fading
+ screen.blitFrom3DOcolorLimit(fadeLimitColor);
+
+ if (!fadeLimitColor) {
+ // we are at the end, so stop
+ fadeActive = false;
+ } else {
+ // decrease limit color
+ fadeLimitColorRed = fadeLimitColor & 0xF800;
+ fadeLimitColorGreen = fadeLimitColor & 0x07E0;
+ fadeLimitColorBlue = fadeLimitColor & 0x001F;
+ if (fadeLimitColorRed)
+ fadeLimitColor -= 0x0800;
+ if (fadeLimitColorGreen)
+ fadeLimitColor -= 0x0040; // -2 because we are using RGB565, sherlock uses RGB555
+ if (fadeLimitColorBlue)
+ fadeLimitColor -= 0x0001;
+ }
+ }
+
+ // Check if we've reached a frame with sound
+ if (frameNumber++ == *soundFrames) {
+ ++soundNumber;
+ ++soundFrames;
+
+ Common::String sampleFilename;
+
+ // append 1-digit number
+ sampleFilename = Common::String::format("prologue/sounds/%s%01d", filename.c_str(), soundNumber);
+
+ if (sound._voices)
+ sound.playSound(sampleFilename, WAIT_RETURN_IMMEDIATELY, 100); // no sound library
+ }
+ events.wait(speed * 3);
+ }
+
+ if (events.kbHit()) {
+ Common::KeyState keyState = events.getKey();
+ if (keyState.keycode == Common::KEYCODE_ESCAPE ||
+ keyState.keycode == Common::KEYCODE_SPACE) {
+ skipped = true;
+ break;
+ }
+ } else if (events._pressed) {
+ skipped = true;
+ break;
+ }
+ }
+
+ events.clearEvents();
+ sound.stopSound();
+ delete indexStream;
+
+ return !skipped && !_vm->shouldQuit();
+}
+
void Animation::setPrologueNames(const char *const *names, int count) {
for (int idx = 0; idx < count; ++idx, ++names) {
_prologueNames.push_back(*names);
@@ -163,10 +297,11 @@ void Animation::setTitleFrames(const int *frames, int count, int maxFrames) {
}
}
-const int *Animation::checkForSoundFrames(const Common::String &filename) {
+const int *Animation::checkForSoundFrames(const Common::String &filename, bool intro) {
const int *frames = &NO_FRAMES;
- if (_soundLibraryFilename.empty()) {
+ if (!intro) {
+ // regular animation is playing
for (uint idx = 0; idx < _prologueNames.size(); ++idx) {
if (filename.equalsIgnoreCase(_prologueNames[idx])) {
frames = &_prologueFrames[idx][0];
@@ -174,6 +309,7 @@ const int *Animation::checkForSoundFrames(const Common::String &filename) {
}
}
} else {
+ // intro-animation is playing
for (uint idx = 0; idx < _titleNames.size(); ++idx) {
if (filename.equalsIgnoreCase(_titleNames[idx])) {
frames = &_titleFrames[idx][0];
diff --git a/engines/sherlock/animation.h b/engines/sherlock/animation.h
index b7811d3fa8..f3c95d4027 100644
--- a/engines/sherlock/animation.h
+++ b/engines/sherlock/animation.h
@@ -45,10 +45,11 @@ private:
/**
* Checks for whether an animation is being played that has associated sound
*/
- const int *checkForSoundFrames(const Common::String &filename);
+ const int *checkForSoundFrames(const Common::String &filename, bool intro);
public:
Common::String _soundLibraryFilename;
Common::String _gfxLibraryFilename;
+
public:
Animation(SherlockEngine *vm);
@@ -75,7 +76,9 @@ public:
/**
* Play a full-screen animation
*/
- bool play(const Common::String &filename, int minDelay, int fade, bool setPalette, int speed);
+ bool play(const Common::String &filename, bool intro, int minDelay, int fade, bool setPalette, int speed);
+
+ bool play3DO(const Common::String &filename, bool intro, int minDelay, bool fadeFromGrey, int speed);
};
} // End of namespace Sherlock
diff --git a/engines/sherlock/debugger.cpp b/engines/sherlock/debugger.cpp
index cfbea2bc24..50293db648 100644
--- a/engines/sherlock/debugger.cpp
+++ b/engines/sherlock/debugger.cpp
@@ -22,12 +22,44 @@
#include "sherlock/debugger.h"
#include "sherlock/sherlock.h"
+#include "sherlock/music.h"
+#include "sherlock/scalpel/3do/movie_decoder.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 {
+Debugger *Debugger::init(SherlockEngine *vm) {
+ if (vm->getGameID() == GType_RoseTattoo)
+ return new Tattoo::TattooDebugger(vm);
+ else
+ return new Scalpel::ScalpelDebugger(vm);
+}
+
Debugger::Debugger(SherlockEngine *vm) : GUI::Debugger(), _vm(vm) {
- registerCmd("continue", WRAP_METHOD(Debugger, cmdExit));
- registerCmd("scene", WRAP_METHOD(Debugger, cmdScene));
+ _showAllLocations = LOC_DISABLED;
+
+ registerCmd("continue", WRAP_METHOD(Debugger, cmdExit));
+ registerCmd("scene", WRAP_METHOD(Debugger, cmdScene));
+ registerCmd("song", WRAP_METHOD(Debugger, cmdSong));
+ registerCmd("songs", WRAP_METHOD(Debugger, cmdListSongs));
+ registerCmd("listfiles", WRAP_METHOD(Debugger, cmdListFiles));
+ registerCmd("dumpfile", WRAP_METHOD(Debugger, cmdDumpFile));
+ registerCmd("locations", WRAP_METHOD(Debugger, cmdLocations));
+}
+
+void Debugger::postEnter() {
+ if (!_3doPlayMovieFile.empty()) {
+ Scalpel3DOMoviePlay(_3doPlayMovieFile.c_str(), Common::Point(0, 0));
+
+ _3doPlayMovieFile.clear();
+ }
+
+ _vm->pauseEngine(false);
}
int Debugger::strToInt(const char *s) {
@@ -56,4 +88,79 @@ bool Debugger::cmdScene(int argc, const char **argv) {
}
}
+bool Debugger::cmdSong(int argc, const char **argv) {
+ if (argc != 2) {
+ debugPrintf("Format: song <name>\n");
+ return true;
+ }
+
+ Common::StringArray songs;
+ _vm->_music->getSongNames(songs);
+
+ for (uint i = 0; i < songs.size(); i++) {
+ if (songs[i].equalsIgnoreCase(argv[1])) {
+ _vm->_music->loadSong(songs[i]);
+ return false;
+ }
+ }
+
+ debugPrintf("Invalid song. Use the 'songs' command to see which ones are available.\n");
+ return true;
+}
+
+bool Debugger::cmdListSongs(int argc, const char **argv) {
+ Common::StringArray songs;
+ _vm->_music->getSongNames(songs);
+ debugPrintColumns(songs);
+ return true;
+}
+
+bool Debugger::cmdListFiles(int argc, const char **argv) {
+ if (argc != 2) {
+ debugPrintf("Format: listfiles <resource file>\n");
+ return true;
+ }
+ Common::StringArray files;
+ _vm->_res->getResourceNames(Common::String(argv[1]), files);
+ debugPrintColumns(files);
+ return true;
+}
+
+bool Debugger::cmdDumpFile(int argc, const char **argv) {
+ if (argc != 2) {
+ debugPrintf("Format: dumpfile <resource name>\n");
+ return true;
+ }
+
+ Common::SeekableReadStream *s = _vm->_res->load(argv[1]);
+ if (!s) {
+ debugPrintf("Invalid resource.\n");
+ return true;
+ }
+
+ byte *buffer = new byte[s->size()];
+ s->read(buffer, s->size());
+
+ Common::DumpFile dumpFile;
+ dumpFile.open(argv[1]);
+
+ dumpFile.write(buffer, s->size());
+ dumpFile.flush();
+ dumpFile.close();
+
+ delete[] buffer;
+
+ debugPrintf("Resource %s has been dumped to disk.\n", argv[1]);
+
+ return true;
+}
+
+bool Debugger::cmdLocations(int argc, const char **argv) {
+ _showAllLocations = LOC_REFRESH;
+
+ debugPrintf("Now showing all map locations\n");
+ return false;
+}
+
+
} // End of namespace Sherlock
diff --git a/engines/sherlock/debugger.h b/engines/sherlock/debugger.h
index e6a3aba828..bcc4448c32 100644
--- a/engines/sherlock/debugger.h
+++ b/engines/sherlock/debugger.h
@@ -30,10 +30,10 @@ namespace Sherlock {
class SherlockEngine;
+enum AllLocations { LOC_REFRESH = -1, LOC_DISABLED = 0, LOC_ALL = 1 };
+
class Debugger : public GUI::Debugger {
private:
- SherlockEngine *_vm;
-
/**
* Converts a decimal or hexadecimal string into a number
*/
@@ -43,9 +43,42 @@ private:
* Switch to another scene
*/
bool cmdScene(int argc, const char **argv);
+
+ /**
+ * Plays a song
+ */
+ bool cmdSong(int argc, const char **argv);
+
+ /**
+ * Lists all available songs
+ */
+ bool cmdListSongs(int argc, const char **argv);
+
+ /**
+ * Lists all files in a library (use at your own risk)
+ */
+ bool cmdListFiles(int argc, const char **argv);
+
+ /**
+ * Dumps a file to disk
+ */
+ bool cmdDumpFile(int argc, const char **argv);
+
+ /**
+ * Show all locations on the map
+ */
+ bool cmdLocations(int argc, const char **argv);
+protected:
+ SherlockEngine *_vm;
+ Common::String _3doPlayMovieFile;
+public:
+ AllLocations _showAllLocations;
public:
Debugger(SherlockEngine *vm);
virtual ~Debugger() {}
+ static Debugger *init(SherlockEngine *vm);
+
+ void postEnter();
};
} // End of namespace Sherlock
diff --git a/engines/sherlock/detection.cpp b/engines/sherlock/detection.cpp
index ea68d79a1b..5a94b3485f 100644
--- a/engines/sherlock/detection.cpp
+++ b/engines/sherlock/detection.cpp
@@ -44,6 +44,10 @@ Common::Platform SherlockEngine::getPlatform() const {
return _gameDescription->desc.platform;
}
+Common::Language SherlockEngine::getLanguage() const {
+ return _gameDescription->desc.language;
+}
+
} // End of namespace Sherlock
static const PlainGameDescriptor sherlockGames[] = {
@@ -58,6 +62,7 @@ static const PlainGameDescriptor sherlockGames[] = {
#define GAMEOPTION_HELP_STYLE GUIO_GAMEOPTIONS3
#define GAMEOPTION_PORTRAITS_ON GUIO_GAMEOPTIONS4
#define GAMEOPTION_WINDOW_STYLE GUIO_GAMEOPTIONS5
+#define GAMEOPTION_TRANSPARENT_WINDOWS GUIO_GAMEOPTIONS6
static const ADExtraGuiOptionsMap optionsList[] = {
{
@@ -110,6 +115,16 @@ static const ADExtraGuiOptionsMap optionsList[] = {
}
},
+ {
+ GAMEOPTION_TRANSPARENT_WINDOWS,
+ {
+ _s("Transparent windows"),
+ _s("Show windows with a partially transparent background"),
+ "transparent_windows",
+ true
+ }
+ },
+
AD_EXTRA_GUI_OPTIONS_TERMINATOR
};
diff --git a/engines/sherlock/detection_tables.h b/engines/sherlock/detection_tables.h
index 208b6710af..e2b5a3dce9 100644
--- a/engines/sherlock/detection_tables.h
+++ b/engines/sherlock/detection_tables.h
@@ -40,6 +40,75 @@ static const SherlockGameDescription gameDescriptions[] = {
},
{
+ // Case of the Serrated Scalpel - German CD (from multilingual CD)
+ // Provided by m_kiewitz
+ {
+ "scalpel",
+ 0, {
+ {"talk.lib", 0, "40a5f9f37c0e0d2ad48d8f44d8e393c9", 284278},
+ {"music.lib", 0, "68ae2f7684ecf903bd60a00bb6bae195", 366465},
+ AD_LISTEND},
+ Common::DE_DEU,
+ Common::kPlatformDOS,
+ ADGF_UNSTABLE,
+ GUIO6(GUIO_NOSPEECH, GAMEOPTION_ORIGINAL_SAVES, GAMEOPTION_FADE_STYLE, GAMEOPTION_HELP_STYLE,
+ GAMEOPTION_PORTRAITS_ON, GAMEOPTION_WINDOW_STYLE)
+ },
+ GType_SerratedScalpel,
+ },
+
+ {
+ // Case of the Serrated Scalpel - German
+ // Provided by mgerhardy
+ {
+ "scalpel",
+ 0, {
+ {"talk.lib", 0, "44652e54172e13b1b075b1ef7d89de24", 284043},
+ {"music.lib", 0, "68ae2f7684ecf903bd60a00bb6bae195", 366465},
+ AD_LISTEND},
+ Common::DE_DEU,
+ Common::kPlatformDOS,
+ ADGF_UNSTABLE,
+ GUIO6(GUIO_NOSPEECH, GAMEOPTION_ORIGINAL_SAVES, GAMEOPTION_FADE_STYLE, GAMEOPTION_HELP_STYLE,
+ GAMEOPTION_PORTRAITS_ON, GAMEOPTION_WINDOW_STYLE)
+ },
+ GType_SerratedScalpel,
+ },
+
+ {
+ // Case of the Serrated Scalpel - Spanish CD (from multilingual CD)
+ // Provided by m_kiewitz
+ {
+ "scalpel",
+ 0, {
+ {"talk.lib", 0, "27697804b637a7f3b77234bf16f15dce", 171419},
+ {"music.lib", 0, "68ae2f7684ecf903bd60a00bb6bae195", 366465},
+ AD_LISTEND},
+ Common::ES_ESP,
+ Common::kPlatformDOS,
+ ADGF_UNSTABLE,
+ GUIO6(GUIO_NOSPEECH, GAMEOPTION_ORIGINAL_SAVES, GAMEOPTION_FADE_STYLE, GAMEOPTION_HELP_STYLE,
+ GAMEOPTION_PORTRAITS_ON, GAMEOPTION_WINDOW_STYLE)
+ },
+ GType_SerratedScalpel,
+ },
+
+ {
+ // Case of the Serrated Scalpel - English 3DO
+ {
+ "scalpel",
+ 0,
+ AD_ENTRY1s("talk.lib", "20f74a29f2db6475e85b029ac9fc03bc", 240610),
+ Common::EN_ANY,
+ Common::kPlatform3DO,
+ ADGF_UNSTABLE,
+ GUIO6(GUIO_NOSPEECH, GAMEOPTION_ORIGINAL_SAVES, GAMEOPTION_FADE_STYLE, GAMEOPTION_HELP_STYLE,
+ GAMEOPTION_PORTRAITS_ON, GAMEOPTION_WINDOW_STYLE)
+ },
+ GType_SerratedScalpel,
+ },
+
+ {
// Case of the Serrated Scalpel - Interactive English Demo
// Provided by Strangerke
{
@@ -79,7 +148,7 @@ static const SherlockGameDescription gameDescriptions[] = {
Common::EN_ANY,
Common::kPlatformDOS,
ADGF_UNSTABLE,
- GUIO0()
+ GUIO3(GAMEOPTION_ORIGINAL_SAVES, GAMEOPTION_HELP_STYLE, GAMEOPTION_TRANSPARENT_WINDOWS)
},
GType_RoseTattoo
},
@@ -94,7 +163,7 @@ static const SherlockGameDescription gameDescriptions[] = {
Common::EN_ANY,
Common::kPlatformDOS,
ADGF_UNSTABLE,
- GUIO0()
+ GUIO3(GAMEOPTION_ORIGINAL_SAVES, GAMEOPTION_HELP_STYLE, GAMEOPTION_TRANSPARENT_WINDOWS)
},
GType_RoseTattoo,
},
@@ -109,7 +178,7 @@ static const SherlockGameDescription gameDescriptions[] = {
Common::DE_DEU,
Common::kPlatformDOS,
ADGF_UNSTABLE,
- GUIO0()
+ 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 b238605e13..079ea0e663 100644
--- a/engines/sherlock/events.cpp
+++ b/engines/sherlock/events.cpp
@@ -27,6 +27,7 @@
#include "graphics/cursorman.h"
#include "sherlock/sherlock.h"
#include "sherlock/events.h"
+#include "sherlock/surface.h"
namespace Sherlock {
@@ -41,6 +42,9 @@ Events::Events(SherlockEngine *vm): _vm(vm) {
_pressed = _released = false;
_rightPressed = _rightReleased = false;
_oldButtons = _oldRightButton = false;
+ _firstPress = false;
+ _waitCounter = 0;
+ _frameRate = 0;
if (_vm->_interactiveFl)
loadCursors("rmouse.vgs");
@@ -54,35 +58,102 @@ void Events::loadCursors(const Common::String &filename) {
hideCursor();
delete _cursorImages;
- _cursorImages = new ImageFile(filename);
+ if (!IS_3DO) {
+ // PC
+ _cursorImages = new ImageFile(filename);
+ } else {
+ // 3DO
+ _cursorImages = new ImageFile3DO(filename, kImageFile3DOType_RoomFormat);
+ }
_cursorId = INVALID_CURSOR;
}
void Events::setCursor(CursorId cursorId) {
- if (cursorId == _cursorId)
+ if (cursorId == _cursorId || _waitCounter > 0)
return;
- _cursorId = cursorId;
+ int hotspotX, hotspotY;
+
+ if (cursorId == MAGNIFY) {
+ hotspotX = 8;
+ hotspotY = 8;
+ } else {
+ hotspotX = 0;
+ hotspotY = 0;
+ }
// Set the cursor data
Graphics::Surface &s = (*_cursorImages)[cursorId]._frame;
- setCursor(s);
+ setCursor(s, hotspotX, hotspotY);
+
+ _cursorId = cursorId;
}
-void Events::setCursor(const Graphics::Surface &src) {
- CursorMan.replaceCursor(src.getPixels(), src.w, src.h, 0, 0, 0xff);
+void Events::setCursor(const Graphics::Surface &src, int hotspotX, int hotspotY) {
+ _cursorId = INVALID_CURSOR;
+ _hotspotPos = Common::Point(hotspotX, hotspotY);
+
+ if (!IS_3DO) {
+ // PC 8-bit palettized
+ CursorMan.replaceCursor(src.getPixels(), src.w, src.h, hotspotX, hotspotY, 0xff);
+ } else {
+ // 3DO RGB565
+ CursorMan.replaceCursor(src.getPixels(), src.w, src.h, hotspotX, hotspotY, 0x0000, false, &src.format);
+ }
showCursor();
}
+void Events::setCursor(CursorId cursorId, const Common::Point &cursorPos, const Graphics::Surface &surface) {
+ _cursorId = cursorId;
+
+ // Get the standard cursor frame
+ Graphics::Surface &cursorImg = (*_cursorImages)[cursorId]._frame;
+
+ // If the X pos for the cursor image is -100, this is a special value to indicate
+ // the cursor should be horizontally centered
+ Common::Point cursorPt = cursorPos;
+ if (cursorPos.x == -100)
+ cursorPt.x = (surface.w - cursorImg.w) / 2;
+
+ // Figure total bounds needed for cursor image and passed image
+ Common::Rect bounds(surface.w, surface.h);
+ bounds.extend(Common::Rect(cursorPt.x, cursorPt.y, cursorPt.x + cursorImg.w, cursorPt.y + cursorImg.h));
+ Common::Rect r = bounds;
+ r.moveTo(0, 0);
+
+ // Form a single surface containing both frames
+ Surface s(r.width(), r.height());
+ s.fill(TRANSPARENCY);
+
+ // Draw the passed image
+ Common::Point drawPos;
+ if (cursorPt.x < 0)
+ drawPos.x = -cursorPt.x;
+ if (cursorPt.y < 0)
+ drawPos.y = -cursorPt.y;
+ s.blitFrom(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));
+
+ // Set up hotspot position for cursor, adjusting for cursor image's position within the surface
+ Common::Point hotspot;
+ if (cursorId == MAGNIFY)
+ hotspot = Common::Point(8, 8);
+ hotspot += drawPos;
+ // Set the cursor
+ setCursor(s.getRawSurface(), hotspot.x, hotspot.y);
+}
+
void Events::animateCursorIfNeeded() {
if (_cursorId >= WAIT && _cursorId < (WAIT + 3)) {
- CursorId newId = (WAIT + 2) ? WAIT : (CursorId)((int)_cursorId + 1);
+ CursorId newId = (_cursorId == WAIT + 2) ? WAIT : (CursorId)((int)_cursorId + 1);
setCursor(newId);
}
}
-
void Events::showCursor() {
CursorMan.showMouse(true);
}
@@ -99,16 +170,14 @@ bool Events::isCursorVisible() const {
return CursorMan.isVisible();
}
-void Events::moveMouse(const Common::Point &pt) {
- g_system->warpMouse(pt.x, pt.y);
-}
-
void Events::pollEvents() {
checkForNextFrameCounter();
Common::Event event;
while (g_system->getEventManager()->pollEvent(event)) {
- // Handle keypress
+ _mousePos = event.mouse;
+
+ // Handle events
switch (event.type) {
case Common::EVENT_QUIT:
case Common::EVENT_RTL:
@@ -149,10 +218,29 @@ void Events::pollEventsAndWait() {
g_system->delayMillis(10);
}
+void Events::warpMouse(const Common::Point &pt) {
+ _mousePos = pt - _vm->_screen->_currentScroll;
+ g_system->warpMouse(_mousePos.x, _mousePos.y);
+}
+
+void Events::warpMouse() {
+ Screen &screen = *_vm->_screen;
+ warpMouse(Common::Point(screen._currentScroll.x + SHERLOCK_SCREEN_WIDTH / 2,
+ screen._currentScroll.y + SHERLOCK_SCREEN_HEIGHT / 2));
+}
+
+Common::Point Events::mousePos() const {
+ return _vm->_screen->_currentScroll + _mousePos;
+}
+
+void Events::setFrameRate(int newRate) {
+ _frameRate = newRate;
+}
+
bool Events::checkForNextFrameCounter() {
// Check for next game frame
uint32 milli = g_system->getMillis();
- if ((milli - _priorFrameTime) >= GAME_FRAME_TIME) {
+ if ((milli - _priorFrameTime) >= (1000 / _frameRate)) {
++_frameCounter;
_priorFrameTime = milli;
@@ -168,12 +256,42 @@ bool Events::checkForNextFrameCounter() {
return false;
}
-Common::Point Events::mousePos() const {
- return g_system->getEventManager()->getMousePos();
-}
-
Common::KeyState Events::getKey() {
- return _pendingKeys.pop();
+ Common::KeyState keyState = _pendingKeys.pop();
+
+ switch (keyState.keycode) {
+ case Common::KEYCODE_KP1:
+ keyState.keycode = Common::KEYCODE_END;
+ break;
+ case Common::KEYCODE_KP2:
+ keyState.keycode = Common::KEYCODE_DOWN;
+ break;
+ case Common::KEYCODE_KP3:
+ keyState.keycode = Common::KEYCODE_PAGEDOWN;
+ break;
+ case Common::KEYCODE_KP4:
+ keyState.keycode = Common::KEYCODE_LEFT;
+ break;
+ case Common::KEYCODE_KP6:
+ keyState.keycode = Common::KEYCODE_RIGHT;
+ break;
+ case Common::KEYCODE_KP7:
+ keyState.keycode = Common::KEYCODE_HOME;
+ break;
+ case Common::KEYCODE_KP8:
+ keyState.keycode = Common::KEYCODE_UP;
+ break;
+ case Common::KEYCODE_KP9:
+ keyState.keycode = Common::KEYCODE_PAGEUP;
+ break;
+ case Common::KEYCODE_KP_ENTER:
+ keyState.keycode = Common::KEYCODE_RETURN;
+ break;
+ default:
+ break;
+ }
+
+ return keyState;
}
void Events::clearEvents() {
@@ -182,6 +300,7 @@ void Events::clearEvents() {
_pressed = _released = false;
_rightPressed = _rightReleased = false;
_oldButtons = _oldRightButton = false;
+ _firstPress = false;
}
void Events::clearKeyboard() {
@@ -189,7 +308,7 @@ void Events::clearKeyboard() {
}
void Events::wait(int numFrames) {
- uint32 totalMilli = numFrames * 1000 / GAME_FRAME_RATE;
+ uint32 totalMilli = numFrames * 1000 / _frameRate;
delay(totalMilli);
}
@@ -199,7 +318,7 @@ bool Events::delay(uint32 time, bool interruptable) {
// For really short periods, simply delay by the desired amount
pollEvents();
g_system->delayMillis(time);
- bool result = !(interruptable && (kbHit() || _pressed));
+ bool result = !(interruptable && (kbHit() || _pressed || _vm->shouldQuit()));
clearEvents();
return result;
@@ -212,17 +331,19 @@ bool Events::delay(uint32 time, bool interruptable) {
while (!_vm->shouldQuit() && g_system->getMillis() < delayEnd) {
pollEventsAndWait();
- if (interruptable && (kbHit() || _pressed)) {
+ if (interruptable && (kbHit() || _mouseButtons)) {
clearEvents();
return false;
}
}
- return true;
+ return !_vm->shouldQuit();
}
}
void Events::setButtonState() {
+ _firstPress = ((_mouseButtons & 1) && !_pressed) || ((_mouseButtons & 2) && !_rightPressed);
+
_released = _rightReleased = false;
if (_mouseButtons & LEFT_BUTTON)
_pressed = _oldButtons = true;
@@ -246,4 +367,14 @@ bool Events::checkInput() {
return kbHit() || _pressed || _released || _rightPressed || _rightReleased;
}
+void Events::incWaitCounter() {
+ setCursor(WAIT);
+ ++_waitCounter;
+}
+
+void Events::decWaitCounter() {
+ assert(_waitCounter > 0);
+ --_waitCounter;
+}
+
} // End of namespace Sherlock
diff --git a/engines/sherlock/events.h b/engines/sherlock/events.h
index b35109fefe..e13ef18822 100644
--- a/engines/sherlock/events.h
+++ b/engines/sherlock/events.h
@@ -26,11 +26,11 @@
#include "common/scummsys.h"
#include "common/events.h"
#include "common/stack.h"
-#include "sherlock/resources.h"
+#include "sherlock/image_file.h"
namespace Sherlock {
-#define GAME_FRAME_RATE 60
+#define GAME_FRAME_RATE 30
#define GAME_FRAME_TIME (1000 / GAME_FRAME_RATE)
enum CursorId { ARROW = 0, MAGNIFY = 1, WAIT = 2, EXIT_ZONES_START = 5, INVALID_CURSOR = -1 };
@@ -44,6 +44,9 @@ private:
uint32 _priorFrameTime;
ImageFile *_cursorImages;
int _mouseButtons;
+ Common::Point _mousePos;
+ int _waitCounter;
+ uint _frameRate;
/**
* Check whether it's time to display the next screen frame
@@ -57,7 +60,9 @@ public:
bool _rightReleased;
bool _oldButtons;
bool _oldRightButton;
+ bool _firstPress;
Common::Stack<Common::KeyState> _pendingKeys;
+ Common::Point _hotspotPos;
public:
Events(SherlockEngine *vm);
~Events();
@@ -75,7 +80,12 @@ public:
/**
* Set the cursor to show from a passed frame
*/
- void setCursor(const Graphics::Surface &src);
+ void setCursor(const Graphics::Surface &src, int hotspotX = 0, int hotspotY = 0);
+
+ /**
+ * Set both a standard cursor as well as an inventory item above it
+ */
+ void setCursor(CursorId cursorId, const Common::Point &cursorPos, const Graphics::Surface &surface);
/**
* Animates the mouse cursor if the Wait cursor is showing
@@ -103,11 +113,6 @@ public:
bool isCursorVisible() const;
/**
- * Move the mouse
- */
- void moveMouse(const Common::Point &pt);
-
- /**
* Check for any pending events
*/
void pollEvents();
@@ -119,12 +124,38 @@ public:
void pollEventsAndWait();
/**
+ * Move the mouse cursor
+ */
+ void warpMouse(const Common::Point &pt);
+
+ /**
+ * Move the mouse cursor to the center of the screen
+ */
+ void warpMouse();
+
+ /**
* Get the current mouse position
*/
+ Common::Point screenMousePos() const { return _mousePos; }
+
+ /**
+ * Get the current mouse position within the scene, adjusted by the scroll position
+ */
Common::Point mousePos() const;
+ /**
+ * Override the default frame rate
+ */
+ void setFrameRate(int newRate);
+
+ /**
+ * Return the current game frame number
+ */
uint32 getFrameCounter() const { return _frameCounter; }
+ /**
+ * Returns true if there's a pending keyboard key
+ */
bool kbHit() const { return !_pendingKeys.empty(); }
/**
@@ -164,6 +195,16 @@ public:
* Checks to see to see if a key or a mouse button is pressed.
*/
bool checkInput();
+
+ /**
+ * Increment the wait counter
+ */
+ void incWaitCounter();
+
+ /**
+ * Decrement the wait counter
+ */
+ void decWaitCounter();
};
} // End of namespace Sherlock
diff --git a/engines/sherlock/fixed_text.cpp b/engines/sherlock/fixed_text.cpp
new file mode 100644
index 0000000000..cbee944120
--- /dev/null
+++ b/engines/sherlock/fixed_text.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/sherlock.h"
+#include "sherlock/fixed_text.h"
+#include "sherlock/scalpel/scalpel_fixed_text.h"
+#include "sherlock/tattoo/tattoo_fixed_text.h"
+
+namespace Sherlock {
+
+FixedText *FixedText::init(SherlockEngine *vm) {
+ if (vm->getGameID() == GType_SerratedScalpel)
+ return new Scalpel::ScalpelFixedText(vm);
+ else
+ return new Tattoo::TattooFixedText(vm);
+}
+
+
+} // End of namespace Sherlock
diff --git a/engines/sherlock/fixed_text.h b/engines/sherlock/fixed_text.h
new file mode 100644
index 0000000000..40444f4052
--- /dev/null
+++ b/engines/sherlock/fixed_text.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 SHERLOCK_FIXED_TEXT_H
+#define SHERLOCK_FIXED_TEXT_H
+
+#include "common/scummsys.h"
+#include "common/language.h"
+
+namespace Sherlock {
+
+#define FIXED(MSG) _vm->_fixedText->getText(kFixedText_##MSG)
+
+enum FixedTextActionId {
+ kFixedTextAction_Invalid = -1,
+ kFixedTextAction_Open = 0,
+ kFixedTextAction_Close,
+ kFixedTextAction_Move,
+ kFixedTextAction_Pick,
+ kFixedTextAction_Use
+};
+
+class SherlockEngine;
+
+class FixedText {
+protected:
+ SherlockEngine *_vm;
+
+ FixedText(SherlockEngine *vm) : _vm(vm) {}
+public:
+ static FixedText *init(SherlockEngine *vm);
+ virtual ~FixedText() {}
+
+ /**
+ * Gets text
+ */
+ virtual const char *getText(int fixedTextId) = 0;
+
+ /**
+ * Get action message
+ */
+ virtual const Common::String getActionMessage(FixedTextActionId actionId, int messageIndex) = 0;
+};
+
+} // End of namespace Sherlock
+
+#endif
diff --git a/engines/sherlock/fonts.cpp b/engines/sherlock/fonts.cpp
new file mode 100644
index 0000000000..482e795b6d
--- /dev/null
+++ b/engines/sherlock/fonts.cpp
@@ -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.
+ *
+ */
+
+#include "common/system.h"
+#include "common/platform.h"
+#include "sherlock/fonts.h"
+#include "sherlock/image_file.h"
+#include "sherlock/surface.h"
+#include "sherlock/sherlock.h"
+
+namespace Sherlock {
+
+SherlockEngine *Fonts::_vm;
+ImageFile *Fonts::_font;
+int Fonts::_fontNumber;
+int Fonts::_fontHeight;
+int Fonts::_widestChar;
+uint16 Fonts::_charCount;
+byte Fonts::_yOffsets[255];
+
+void Fonts::setVm(SherlockEngine *vm) {
+ _vm = vm;
+ _font = nullptr;
+ _charCount = 0;
+}
+
+void Fonts::free() {
+ delete _font;
+}
+
+void Fonts::setFont(int fontNum) {
+ _fontNumber = fontNum;
+
+ // Discard previous font
+ delete _font;
+
+ Common::String fontFilename;
+
+ if (_vm->getPlatform() != Common::kPlatform3DO) {
+ // PC
+ // use FONT[number].VGS, which is a regular sherlock graphic file
+ fontFilename = Common::String::format("FONT%d.VGS", fontNum + 1);
+
+ // load font data
+ _font = new ImageFile(fontFilename);
+ } else {
+ // 3DO
+ switch (fontNum) {
+ case 0:
+ case 1:
+ fontFilename = "helvetica14.font";
+ break;
+ case 2:
+ fontFilename = "darts.font";
+ break;
+ default:
+ error("setFont(): unsupported 3DO font number");
+ }
+
+ // load font data
+ _font = new ImageFile3DO(fontFilename, kImageFile3DOType_Font);
+ }
+
+ _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) {
+ _fontHeight = MAX((uint16)_fontHeight, (*_font)[idx]._frame.h);
+ _widestChar = MAX((uint16)_widestChar, (*_font)[idx]._frame.w);
+ }
+
+ // Initialize the Y offset table for the extended character set
+ for (int idx = 0; idx < 255; ++idx) {
+ _yOffsets[idx] = 0;
+
+ if (IS_ROSE_TATTOO) {
+ if ((idx >= 129 && idx < 135) || (idx >= 136 && idx < 143) || (idx >= 147 && idx < 155) ||
+ (idx >= 156 && idx < 165))
+ _yOffsets[idx] = 1;
+ else if ((idx >= 143 && idx < 146) || idx == 165)
+ _yOffsets[idx] = 2;
+ }
+ }
+}
+
+inline byte Fonts::translateChar(byte c) {
+ switch (c) {
+ case ' ':
+ return 0; // translate to first actual character
+ case 225:
+ // This was done in the German interpreter
+ // SH1: happens, when talking to the kid in the 2nd room
+ // SH2: happens, when looking at the newspaper right at the start in the backalley
+ // Special handling for 0xE1 (German Sharp-S character)
+ if (IS_ROSE_TATTOO) {
+ return 136; // it got translated to this for SH2
+ }
+ return 135; // and this for SH1
+ default:
+ if (IS_SERRATED_SCALPEL) {
+ if (c >= 0x80) { // German SH1 version did this, but not German SH2
+ c--;
+ }
+ // Spanish SH1 did this (reverse engineered code)
+ //if ((c >= 0xA0) && (c <= 0xAD) || (c == 0x82)) {
+ // c--;
+ //}
+ }
+ assert(c > 32); // anything above space is allowed
+ return c - 33;
+ }
+}
+
+void Fonts::writeString(Surface *surface, const Common::String &str,
+ const Common::Point &pt, int overrideColor) {
+ Common::Point charPos = pt;
+
+ if (!_font)
+ return;
+
+ for (const char *curCharPtr = str.c_str(); *curCharPtr; ++curCharPtr) {
+ byte curChar = *curCharPtr;
+
+ if (curChar == ' ') {
+ charPos.x += 5; // hardcoded space
+ continue;
+ }
+ 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;
+ }
+}
+
+int Fonts::stringWidth(const Common::String &str) {
+ int width = 0;
+
+ if (!_font)
+ return 0;
+
+ for (const char *c = str.c_str(); *c; ++c)
+ width += charWidth(*c);
+
+ return width;
+}
+
+int Fonts::stringHeight(const Common::String &str) {
+ int height = 0;
+
+ if (!_font)
+ return 0;
+
+ for (const char *c = str.c_str(); *c; ++c)
+ height = MAX(height, charHeight(*c));
+
+ return height;
+}
+
+int Fonts::charWidth(unsigned char c) {
+ byte curChar;
+
+ if (!_font)
+ return 0;
+
+ if (c == ' ') {
+ return 5; // hardcoded space
+ }
+ curChar = translateChar(c);
+
+ if (curChar < _charCount)
+ return (*_font)[curChar]._frame.w + 1;
+ return 0;
+}
+
+int Fonts::charHeight(unsigned char c) {
+ byte curChar;
+
+ if (!_font)
+ return 0;
+
+ // Space is supposed to be handled like the first actual character (which is decimal 33)
+ curChar = translateChar(c);
+
+ assert(curChar < _charCount);
+ const ImageFrame &img = (*_font)[curChar];
+ return img._height + img._offset.y + 1;
+}
+
+} // End of namespace Sherlock
diff --git a/engines/sherlock/fonts.h b/engines/sherlock/fonts.h
new file mode 100644
index 0000000000..a527cc73c0
--- /dev/null
+++ b/engines/sherlock/fonts.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.
+ *
+ */
+
+#ifndef SHERLOCK_FONTS_H
+#define SHERLOCK_FONTS_H
+
+#include "common/rect.h"
+#include "common/platform.h"
+#include "graphics/surface.h"
+
+namespace Sherlock {
+
+class SherlockEngine;
+class ImageFile;
+class Surface;
+
+class Fonts {
+private:
+ static ImageFile *_font;
+ static byte _yOffsets[255];
+protected:
+ static SherlockEngine *_vm;
+ static int _fontNumber;
+ static int _fontHeight;
+ static int _widestChar;
+ static uint16 _charCount;
+
+ static void writeString(Surface *surface, const Common::String &str,
+ const Common::Point &pt, int overrideColor = 0);
+
+ static inline byte translateChar(byte c);
+public:
+ /**
+ * Initialise the font manager
+ */
+ static void setVm(SherlockEngine *vm);
+
+ /**
+ * Frees the font manager
+ */
+ static void free();
+
+ /**
+ * Set the font to use for writing text on the screen
+ */
+ void setFont(int fontNum);
+
+ /**
+ * Returns the width of a string in pixels
+ */
+ int stringWidth(const Common::String &str);
+
+ /**
+ * Returns the height of a string in pixels (i.e. the tallest displayed character)
+ */
+ int stringHeight(const Common::String &str);
+
+ /**
+ * Returns the width of a character in pixels
+ */
+ int charWidth(unsigned char c);
+
+ /**
+ * Returns the width of a character in pixels
+ */
+ int charHeight(unsigned char c);
+
+ /**
+ * Return the font height
+ */
+ int fontHeight() const { return _fontHeight; }
+
+ /**
+ * Return the width of the widest character in the font
+ */
+ int widestChar() const { return _widestChar; }
+
+ /**
+ * Return the currently active font number
+ */
+ int fontNumber() const { return _fontNumber; }
+};
+
+} // End of namespace Sherlock
+
+#endif
diff --git a/engines/sherlock/image_file.cpp b/engines/sherlock/image_file.cpp
new file mode 100644
index 0000000000..3d881eb655
--- /dev/null
+++ b/engines/sherlock/image_file.cpp
@@ -0,0 +1,1098 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public 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/image_file.h"
+#include "sherlock/screen.h"
+#include "sherlock/sherlock.h"
+#include "common/debug.h"
+#include "common/memstream.h"
+
+namespace Sherlock {
+
+SherlockEngine *ImageFile::_vm;
+
+void ImageFile::setVm(SherlockEngine *vm) {
+ _vm = vm;
+}
+
+ImageFile::ImageFile() {
+}
+
+ImageFile::ImageFile(const Common::String &name, bool skipPal, bool animImages) {
+ Common::SeekableReadStream *stream = _vm->_res->load(name);
+
+ Common::fill(&_palette[0], &_palette[PALETTE_SIZE], 0);
+ load(*stream, skipPal, animImages);
+
+ delete stream;
+}
+
+ImageFile::ImageFile(Common::SeekableReadStream &stream, bool skipPal) {
+ Common::fill(&_palette[0], &_palette[PALETTE_SIZE], 0);
+ load(stream, skipPal, false);
+}
+
+ImageFile::~ImageFile() {
+ for (uint idx = 0; idx < size(); ++idx)
+ (*this)[idx]._frame.free();
+}
+
+void ImageFile::load(Common::SeekableReadStream &stream, bool skipPalette, bool animImages) {
+ loadPalette(stream);
+
+ int streamSize = stream.size();
+ while (stream.pos() < streamSize) {
+ ImageFrame frame;
+ frame._width = stream.readUint16LE() + 1;
+ frame._height = stream.readUint16LE() + 1;
+ frame._paletteBase = stream.readByte();
+
+ if (animImages) {
+ // Animation cutscene image files use a 16-bit x offset
+ frame._offset.x = stream.readUint16LE();
+ frame._rleEncoded = (frame._offset.x & 0xff) == 1;
+ frame._offset.y = stream.readByte();
+ } else {
+ // Standard image files have a separate byte for the RLE flag, and an 8-bit X offset
+ frame._rleEncoded = stream.readByte() == 1;
+ frame._offset.x = stream.readByte();
+ frame._offset.y = stream.readByte();
+ }
+
+ frame._rleEncoded = !skipPalette && frame._rleEncoded;
+
+ if (frame._paletteBase) {
+ // Nibble packed frame data
+ frame._size = (frame._width * frame._height) / 2;
+ } else if (frame._rleEncoded) {
+ // This size includes the header size, which we subtract
+ frame._size = stream.readUint16LE() - 11;
+ frame._rleMarker = stream.readByte();
+ } else {
+ // Uncompressed data
+ frame._size = frame._width * frame._height;
+ }
+
+ // Load data for frame and decompress it
+ byte *data = new byte[frame._size + 4];
+ stream.read(data, frame._size);
+ Common::fill(data + frame._size, data + frame._size + 4, 0);
+ frame.decompressFrame(data, IS_ROSE_TATTOO);
+ delete[] data;
+
+ push_back(frame);
+ }
+}
+
+void ImageFile::loadPalette(Common::SeekableReadStream &stream) {
+ // Check for palette
+ uint16 width = stream.readUint16LE() + 1;
+ uint16 height = stream.readUint16LE() + 1;
+ byte paletteBase = stream.readByte();
+ byte rleEncoded = stream.readByte();
+ byte offsetX = stream.readByte();
+ byte offsetY = stream.readByte();
+ uint32 palSignature = 0;
+
+ if ((width == 390) && (height == 2) && (!paletteBase) && (!rleEncoded) && (!offsetX) && (!offsetY)) {
+ // We check for these specific values
+ // We can't do "width * height", because at least the first German+Spanish menu bar is 60 x 13
+ // which is 780, which is the size of the palette. We obviously don't want to detect it as palette.
+
+ // As another security measure, we also check for the signature text
+ palSignature = stream.readUint32BE();
+ if (palSignature != MKTAG('V', 'G', 'A', ' ')) {
+ // signature mismatch, rewind
+ stream.seek(-12, SEEK_CUR);
+ return;
+ }
+ // Found palette, so read it in
+ stream.seek(8, SEEK_CUR); // Skip over the rest of the signature text "VGA palette"
+ for (int idx = 0; idx < PALETTE_SIZE; ++idx)
+ _palette[idx] = VGA_COLOR_TRANS(stream.readByte());
+ } else {
+ // Not a palette, so rewind to start of frame data for normal frame processing
+ stream.seek(-8, SEEK_CUR);
+ }
+}
+
+void ImageFrame::decompressFrame(const byte *src, bool isRoseTattoo) {
+ _frame.create(_width, _height, Graphics::PixelFormat::createFormatCLUT8());
+ byte *dest = (byte *)_frame.getPixels();
+ Common::fill(dest, dest + _width * _height, 0xff);
+
+ if (_paletteBase) {
+ // Nibble-packed
+ for (uint idx = 0; idx < _size; ++idx, ++src) {
+ *dest++ = *src & 0xF;
+ *dest++ = (*src >> 4);
+ }
+ } else if (_rleEncoded && isRoseTattoo) {
+ // Rose Tattoo run length encoding doesn't use the RLE marker byte
+ for (int yp = 0; yp < _height; ++yp) {
+ int xSize = _width;
+ while (xSize > 0) {
+ // Skip a given number of pixels
+ byte skip = *src++;
+ dest += skip;
+ xSize -= skip;
+ if (!xSize)
+ break;
+
+ // Get a run length, and copy the following number of pixels
+ int rleCount = *src++;
+ xSize -= rleCount;
+ while (rleCount-- > 0)
+ *dest++ = *src++;
+ }
+ assert(xSize == 0);
+ }
+ } else if (_rleEncoded) {
+ // RLE encoded
+ int frameSize = _width * _height;
+ while (frameSize > 0) {
+ if (*src == _rleMarker) {
+ byte rleColor = src[1];
+ byte rleCount = src[2];
+ src += 3;
+ frameSize -= rleCount;
+ while (rleCount--)
+ *dest++ = rleColor;
+ } else {
+ *dest++ = *src++;
+ --frameSize;
+ }
+ }
+ assert(frameSize == 0);
+ } else {
+ // Uncompressed frame
+ Common::copy(src, src + _width * _height, dest);
+ }
+}
+
+/*----------------------------------------------------------------*/
+
+int ImageFrame::sDrawXSize(int scaleVal) const {
+ int width = _width;
+ int scale = scaleVal == 0 ? 1 : scaleVal;
+
+ if (scaleVal >= SCALE_THRESHOLD)
+ --width;
+
+ int result = width * SCALE_THRESHOLD / scale;
+ if (scaleVal >= SCALE_THRESHOLD)
+ ++result;
+
+ return result;
+}
+
+int ImageFrame::sDrawYSize(int scaleVal) const {
+ int height = _height;
+ int scale = scaleVal == 0 ? 1 : scaleVal;
+
+ if (scaleVal >= SCALE_THRESHOLD)
+ --height;
+
+ int result = height * SCALE_THRESHOLD / scale;
+ if (scaleVal >= SCALE_THRESHOLD)
+ ++result;
+
+ return result;
+}
+
+int ImageFrame::sDrawXOffset(int scaleVal) const {
+ if (scaleVal == SCALE_THRESHOLD)
+ return _offset.x;
+
+ int width = _offset.x;
+ int scale = scaleVal == 0 ? 1 : scaleVal;
+
+ if (scaleVal >= SCALE_THRESHOLD)
+ --width;
+
+ int result = width * SCALE_THRESHOLD / scale;
+ if (scaleVal > SCALE_THRESHOLD)
+ ++result;
+
+ return result;
+}
+
+int ImageFrame::sDrawYOffset(int scaleVal) const {
+ if (scaleVal == SCALE_THRESHOLD)
+ return _offset.y;
+
+ int height = _offset.y;
+ int scale = scaleVal == 0 ? 1 : scaleVal;
+
+ if (scaleVal >= SCALE_THRESHOLD)
+ --height;
+
+ int result = height * SCALE_THRESHOLD / scale;
+ if (scaleVal > SCALE_THRESHOLD)
+ ++result;
+
+ return result;
+}
+
+// *******************************************************
+
+/*----------------------------------------------------------------*/
+
+SherlockEngine *ImageFile3DO::_vm;
+
+void ImageFile3DO::setVm(SherlockEngine *vm) {
+ _vm = vm;
+}
+
+ImageFile3DO::ImageFile3DO(const Common::String &name, ImageFile3DOType imageFile3DOType) {
+#if 0
+ Common::File *dataStream = new Common::File();
+
+ if (!dataStream->open(name)) {
+ error("unable to open %s\n", name.c_str());
+ }
+#endif
+ Common::SeekableReadStream *dataStream = _vm->_res->load(name);
+
+ switch(imageFile3DOType) {
+ case kImageFile3DOType_Animation:
+ loadAnimationFile(*dataStream);
+ break;
+ case kImageFile3DOType_Cel:
+ case kImageFile3DOType_CelAnimation:
+ load3DOCelFile(*dataStream);
+ break;
+ case kImageFile3DOType_RoomFormat:
+ load3DOCelRoomData(*dataStream);
+ break;
+ case kImageFile3DOType_Font:
+ loadFont(*dataStream);
+ break;
+ default:
+ error("unknown Imagefile-3DO-Type");
+ break;
+ }
+
+ delete dataStream;
+}
+
+ImageFile3DO::ImageFile3DO(Common::SeekableReadStream &stream, bool isRoomData) {
+ if (!isRoomData) {
+ load(stream, isRoomData);
+ } else {
+ load3DOCelRoomData(stream);
+ }
+}
+
+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;
+
+ if (isRoomData) {
+ load3DOCelRoomData(stream);
+ return;
+ }
+
+ headerId = stream.readUint32BE();
+ assert(!stream.eos());
+
+ // Seek back to the start
+ stream.seek(-4, SEEK_CUR);
+
+ // Identify type of file
+ switch (headerId) {
+ case MKTAG('C', 'C', 'B', ' '):
+ case MKTAG('A', 'N', 'I', 'M'):
+ case MKTAG('O', 'F', 'S', 'T'): // 3DOSplash.cel
+ // 3DO .cel (title1a.cel, etc.) or animation file (walk.anim)
+ load3DOCelFile(stream);
+ break;
+
+ default:
+ // Sherlock animation file (.3da files)
+ loadAnimationFile(stream);
+ break;
+ }
+}
+
+// 3DO uses RGB555, we use RGB565 internally so that more platforms are able to run us
+inline uint16 ImageFile3DO::convertPixel(uint16 pixel3DO) {
+ byte red = (pixel3DO >> 10) & 0x1F;
+ byte green = (pixel3DO >> 5) & 0x1F;
+ byte blue = pixel3DO & 0x1F;
+
+ return ((red << 11) | (green << 6) | (blue));
+}
+
+void ImageFile3DO::loadAnimationFile(Common::SeekableReadStream &stream) {
+ uint32 streamLeft = stream.size() - stream.pos();
+ uint32 celDataSize = 0;
+
+ while (streamLeft > 0) {
+ ImageFrame frame;
+
+ // We expect a basic header of 8 bytes
+ if (streamLeft < 8)
+ error("load3DOAnimationFile: expected animation header, not enough bytes");
+
+ celDataSize = stream.readUint16BE();
+
+ frame._width = stream.readUint16BE() + 1; // 2 bytes BE width
+ frame._height = stream.readByte() + 1; // 1 byte BE height
+ frame._paletteBase = 0;
+
+ frame._rleEncoded = true; // always compressed
+ if (frame._width & 0x8000) {
+ frame._width &= 0x7FFF;
+ celDataSize += 0x10000;
+ }
+
+ frame._offset.x = stream.readUint16BE();
+ frame._offset.y = stream.readByte();
+ frame._size = 0;
+ // Got header
+ streamLeft -= 8;
+
+ // cel data follows
+ 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);
+ streamLeft -= celDataSize;
+
+ // always 16 bits per pixel (RGB555)
+ decompress3DOCelFrame(frame, data, celDataSize, 16, NULL);
+
+ delete[] data;
+
+ push_back(frame);
+ }
+}
+
+static byte imagefile3DO_cel_bitsPerPixelLookupTable[8] = {
+ 0, 1, 2, 4, 6, 8, 16, 0
+};
+
+// Reads a 3DO .cel/.anim file
+void ImageFile3DO::load3DOCelFile(Common::SeekableReadStream &stream) {
+ int32 streamSize = stream.size();
+ int32 chunkStartPos = 0;
+ uint32 chunkTag = 0;
+ uint32 chunkSize = 0;
+ byte *chunkDataPtr = NULL;
+
+ // ANIM chunk (animation header for animation files)
+ bool animFound = false;
+ uint32 animVersion = 0;
+ uint32 animType = 0;
+ uint32 animFrameCount = 1; // we expect 1 frame without an ANIM header
+ // CCB chunk (cel control block)
+ bool ccbFound = false;
+ uint32 ccbVersion = 0;
+ uint32 ccbFlags = 0;
+ bool ccbFlags_compressed = false;
+ uint16 ccbPPMP0 = 0;
+ uint16 ccbPPMP1 = 0;
+ uint32 ccbPRE0 = 0;
+ uint16 ccbPRE0_height = 0;
+ byte ccbPRE0_bitsPerPixel = 0;
+ uint32 ccbPRE1 = 0;
+ uint16 ccbPRE1_width = 0;
+ uint32 ccbWidth = 0;
+ uint32 ccbHeight = 0;
+ // pixel lookup table
+ bool plutFound = false;
+ uint32 plutCount = 0;
+ ImageFile3DOPixelLookupTable plutRGBlookupTable;
+
+ memset(&plutRGBlookupTable, 0, sizeof(plutRGBlookupTable));
+
+ while (!stream.err() && (stream.pos() < streamSize)) {
+ chunkStartPos = stream.pos();
+ chunkTag = stream.readUint32BE();
+ chunkSize = stream.readUint32BE();
+
+ if (stream.eos() || stream.err())
+ break;
+
+ if (chunkSize < 8)
+ error("load3DOCelFile: Invalid chunk size");
+
+ uint32 dataSize = chunkSize - 8;
+
+ switch (chunkTag) {
+ case MKTAG('A', 'N', 'I', 'M'):
+ // animation header
+ assert(dataSize >= 24);
+
+ if (animFound)
+ error("load3DOCelFile: multiple ANIM chunks not supported");
+
+ animFound = true;
+ animVersion = stream.readUint32BE();
+ animType = stream.readUint32BE();
+ animFrameCount = stream.readUint32BE();
+ // UINT32 - framerate (0x2000 in walk.anim???)
+ // UINT32 - starting frame (0 for walk.anim)
+ // UINT32 - number of loops (0 for walk.anim)
+
+ if (animVersion != 0)
+ error("load3DOCelFile: Unsupported animation file version");
+ if (animType != 1)
+ error("load3DOCelFile: Only single CCB animation files are supported");
+ break;
+
+ case MKTAG('C', 'C', 'B', ' '):
+ // CEL control block
+ assert(dataSize >= 72);
+
+ if (ccbFound)
+ error("load3DOCelFile: multiple CCB chunks not supported");
+
+ ccbFound = true;
+ ccbVersion = stream.readUint32BE();
+ ccbFlags = stream.readUint32BE();
+ stream.skip(3 * 4); // skip over 3 pointer fields, which are used in memory only by 3DO hardware
+ stream.skip(8 * 4); // skip over 8 offset fields
+ ccbPPMP0 = stream.readUint16BE();
+ ccbPPMP1 = stream.readUint16BE();
+ ccbPRE0 = stream.readUint32BE();
+ ccbPRE1 = stream.readUint32BE();
+ ccbWidth = stream.readUint32BE();
+ ccbHeight = stream.readUint32BE();
+
+ if (ccbVersion != 0)
+ error("load3DOCelFile: Unsupported CCB version");
+
+ if (ccbFlags & 0x200) // bit 9
+ ccbFlags_compressed = true;
+
+ // bit 5 of ccbFlags defines how RGB-black (0, 0, 0) will get treated
+ // = false -> RGB-black is treated as transparent
+ // = true -> RGB-black is treated as actual black
+ // atm we are always treating it as transparent
+ // it seems this bit is not set for any data of Sherlock Holmes
+
+ // PRE0 first 3 bits define how many bits per encoded pixel are used
+ ccbPRE0_bitsPerPixel = imagefile3DO_cel_bitsPerPixelLookupTable[ccbPRE0 & 0x07];
+ if (!ccbPRE0_bitsPerPixel)
+ error("load3DOCelFile: Invalid CCB PRE0 bits per pixel");
+
+ ccbPRE0_height = ((ccbPRE0 >> 6) & 0x03FF) + 1;
+ ccbPRE1_width = (ccbPRE1 & 0x03FF) + 1;
+ assert(ccbPRE0_height == ccbHeight);
+ assert(ccbPRE1_width == ccbWidth);
+ break;
+
+ case MKTAG('P', 'L', 'U', 'T'):
+ // pixel lookup table
+ // optional, not required for at least 16-bit pixel data
+ assert(dataSize >= 6);
+
+ if (!ccbFound)
+ error("load3DOCelFile: PLUT chunk found without CCB chunk");
+ if (plutFound)
+ error("load3DOCelFile: multiple PLUT chunks currently not supported");
+
+ plutFound = true;
+ plutCount = stream.readUint32BE();
+ // table follows, each entry is 16bit RGB555
+ assert(dataSize >= 4 + (plutCount * 2)); // security check
+ assert(plutCount <= 256); // security check
+
+ assert(plutCount <= 32); // PLUT should never contain more than 32 entries
+
+ for (uint32 plutColorNr = 0; plutColorNr < plutCount; plutColorNr++) {
+ plutRGBlookupTable.pixelColor[plutColorNr] = stream.readUint16BE();
+ }
+
+ if (ccbPRE0_bitsPerPixel == 8) {
+ // In case we are getting 8-bits per pixel, we calculate the shades accordingly
+ // I'm not 100% sure if the calculation is correct. It's difficult to find information
+ // on this topic.
+ // The map uses this type of cel
+ assert(plutCount == 32); // And we expect 32 entries inside PLUT chunk
+
+ uint16 plutColorRGB = 0;
+ for (uint32 plutColorNr = 0; plutColorNr < plutCount; plutColorNr++) {
+ plutColorRGB = plutRGBlookupTable.pixelColor[plutColorNr];
+
+ // Extract RGB values
+ byte plutColorRed = (plutColorRGB >> 10) & 0x1F;
+ byte plutColorGreen = (plutColorRGB >> 5) & 0x1F;
+ byte plutColorBlue = plutColorRGB & 0x1F;
+
+ byte shadeMultiplier = 2;
+ for (uint32 plutShadeNr = 1; plutShadeNr < 8; plutShadeNr++) {
+ uint16 shadedColorRGB;
+ byte shadedColorRed = (plutColorRed * shadeMultiplier) >> 3;
+ byte shadedColorGreen = (plutColorGreen * shadeMultiplier) >> 3;
+ byte shadedColorBlue = (plutColorBlue * shadeMultiplier) >> 3;
+
+ shadedColorRed = CLIP<byte>(shadedColorRed, 0, 0x1F);
+ shadedColorGreen = CLIP<byte>(shadedColorGreen, 0, 0x1F);
+ shadedColorBlue = CLIP<byte>(shadedColorBlue, 0, 0x1F);
+ shadedColorRGB = (shadedColorRed << 10) | (shadedColorGreen << 5) | shadedColorBlue;
+
+ plutRGBlookupTable.pixelColor[plutColorNr + (plutShadeNr << 5)] = shadedColorRGB;
+ shadeMultiplier++;
+ }
+ }
+ }
+ break;
+
+ case MKTAG('X', 'T', 'R', 'A'):
+ // Unknown contents, occurs right before PDAT
+ break;
+
+ case MKTAG('P', 'D', 'A', 'T'): {
+ // pixel data for one frame
+ // may be compressed or uncompressed pixels
+
+ if (ccbPRE0_bitsPerPixel != 16) {
+ // We require a pixel lookup table in case bits-per-pixel is lower than 16
+ if (!plutFound)
+ error("load3DOCelFile: bits per pixel < 16, but no pixel lookup table was found");
+ } else {
+ // But we don't like it in case bits-per-pixel is 16 and we find one
+ if (plutFound)
+ error("load3DOCelFile: bits per pixel == 16, but pixel lookup table was found as well");
+ }
+ // read data into memory
+ chunkDataPtr = new byte[dataSize];
+
+ stream.read(chunkDataPtr, dataSize);
+
+ // Set up frame
+ ImageFrame imageFrame;
+
+ imageFrame._width = ccbWidth;
+ imageFrame._height = ccbHeight;
+ imageFrame._paletteBase = 0;
+ imageFrame._offset.x = 0;
+ imageFrame._offset.y = 0;
+ imageFrame._rleEncoded = ccbFlags_compressed;
+ imageFrame._size = 0;
+
+ // Decompress/copy this frame
+ if (!plutFound) {
+ decompress3DOCelFrame(imageFrame, chunkDataPtr, dataSize, ccbPRE0_bitsPerPixel, NULL);
+ } else {
+ decompress3DOCelFrame(imageFrame, chunkDataPtr, dataSize, ccbPRE0_bitsPerPixel, &plutRGBlookupTable);
+ }
+
+ delete[] chunkDataPtr;
+
+ push_back(imageFrame);
+ break;
+ }
+
+ case MKTAG('O', 'F', 'S', 'T'): // 3DOSplash.cel
+ // unknown contents
+ break;
+
+ default:
+ error("Unsupported '%s' chunk in 3DO cel file", tag2str(chunkTag));
+ }
+
+ // Seek to end of chunk
+ stream.seek(chunkStartPos + chunkSize);
+ }
+
+ // Warning below being used to silence unused variable warnings for now
+ warning("TODO: Remove %d %d %d", animFrameCount, ccbPPMP0, ccbPPMP1);
+}
+
+// Reads 3DO .cel data (room file format)
+void ImageFile3DO::load3DOCelRoomData(Common::SeekableReadStream &stream) {
+ uint32 streamLeft = stream.size() - stream.pos();
+ uint16 roomDataHeader_size = 0;
+ byte roomDataHeader_offsetX = 0;
+ byte roomDataHeader_offsetY = 0;
+
+ // CCB chunk (cel control block)
+ uint32 ccbFlags = 0;
+ bool ccbFlags_compressed = false;
+ uint16 ccbPPMP0 = 0;
+ uint16 ccbPPMP1 = 0;
+ uint32 ccbPRE0 = 0;
+ uint16 ccbPRE0_height = 0;
+ byte ccbPRE0_bitsPerPixel = 0;
+ uint32 ccbPRE1 = 0;
+ uint16 ccbPRE1_width = 0;
+ uint32 ccbWidth = 0;
+ uint32 ccbHeight = 0;
+ // cel data
+ uint32 celDataSize = 0;
+
+ while (streamLeft > 0) {
+ // We expect at least 8 bytes basic header
+ if (streamLeft < 8)
+ error("load3DOCelRoomData: expected room data header, not enough bytes");
+
+ // 3DO sherlock holmes room data header
+ stream.skip(4); // Possibly UINT16 width, UINT16 height?!?!
+ roomDataHeader_size = stream.readUint16BE();
+ roomDataHeader_offsetX = stream.readByte();
+ roomDataHeader_offsetY = stream.readByte();
+ streamLeft -= 8;
+
+ // We expect the header size specified in the basic header to be at least a raw CCB
+ if (roomDataHeader_size < 68)
+ error("load3DOCelRoomData: header size is too small");
+ // Check, that enough bytes for CCB are available
+ if (streamLeft < 68)
+ error("load3DOCelRoomData: expected raw cel control block, not enough bytes");
+
+ // 3DO raw cel control block
+ ccbFlags = stream.readUint32BE();
+ stream.skip(3 * 4); // skip over 3 pointer fields, which are used in memory only by 3DO hardware
+ stream.skip(8 * 4); // skip over 8 offset fields
+ ccbPPMP0 = stream.readUint16BE();
+ ccbPPMP1 = stream.readUint16BE();
+ ccbPRE0 = stream.readUint32BE();
+ ccbPRE1 = stream.readUint32BE();
+ ccbWidth = stream.readUint32BE();
+ ccbHeight = stream.readUint32BE();
+
+ 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)
+ error("load3DOCelRoomData: Invalid CCB PRE0 bits per pixel");
+
+ ccbPRE0_height = ((ccbPRE0 >> 6) & 0x03FF) + 1;
+ ccbPRE1_width = (ccbPRE1 & 0x03FF) + 1;
+ assert(ccbPRE0_height == ccbHeight);
+ assert(ccbPRE1_width == ccbWidth);
+
+ if (ccbPRE0_bitsPerPixel != 16) {
+ // We currently support 16-bits per pixel in here
+ error("load3DOCelRoomData: bits per pixel < 16?!?!?");
+ }
+ // Got the raw CCB
+ streamLeft -= 68;
+
+ // cel data follows
+ // size field does not include the 8 byte header
+ celDataSize = roomDataHeader_size - 68;
+
+ if (streamLeft < celDataSize)
+ error("load3DOCelRoomData: expected cel data, not enough bytes");
+
+ // read data into memory
+ byte *celDataPtr = new byte[celDataSize];
+
+ stream.read(celDataPtr, celDataSize);
+ streamLeft -= celDataSize;
+
+ // Set up frame
+ {
+ ImageFrame imageFrame;
+
+ imageFrame._width = ccbWidth;
+ imageFrame._height = ccbHeight;
+ imageFrame._paletteBase = 0;
+ imageFrame._offset.x = roomDataHeader_offsetX;
+ imageFrame._offset.y = roomDataHeader_offsetY;
+ imageFrame._rleEncoded = ccbFlags_compressed;
+ imageFrame._size = 0;
+
+ // Decompress/copy this frame
+ decompress3DOCelFrame(imageFrame, celDataPtr, celDataSize, ccbPRE0_bitsPerPixel, NULL);
+
+ delete[] celDataPtr;
+
+ push_back(imageFrame);
+ }
+ }
+
+ // Suppress compiler warning
+ warning("ccbPPMP0 = %d, ccbPPMP1 = %d", ccbPPMP0, ccbPPMP1);
+}
+
+static uint16 imagefile3DO_cel_bitsMask[17] = {
+ 0,
+ 0x0001, 0x0003, 0x0007, 0x000F, 0x001F, 0x003F, 0x007F, 0x00FF,
+ 0x01FF, 0x03FF, 0x07FF, 0x0FFF, 0x1FFF, 0x3FFF, 0x7FFF, 0xFFFF
+};
+
+// gets [bitCount] bits from dataPtr, going from MSB to LSB
+inline uint16 ImageFile3DO::celGetBits(const byte *&dataPtr, byte bitCount, byte &dataBitsLeft) {
+ byte resultBitsLeft = bitCount;
+ uint16 result = 0;
+ byte currentByte = *dataPtr;
+
+ // Get bits of current byte
+ while (resultBitsLeft) {
+ if (resultBitsLeft < dataBitsLeft) {
+ // we need less than we have left
+ result |= (currentByte >> (dataBitsLeft - resultBitsLeft)) & imagefile3DO_cel_bitsMask[resultBitsLeft];
+ dataBitsLeft -= resultBitsLeft;
+ resultBitsLeft = 0;
+
+ } else {
+ // we need as much as we have left or more
+ resultBitsLeft -= dataBitsLeft;
+ result |= (currentByte & imagefile3DO_cel_bitsMask[dataBitsLeft]) << resultBitsLeft;
+
+ // Go to next byte
+ dataPtr++;
+ dataBitsLeft = 8;
+ if (resultBitsLeft) {
+ currentByte = *dataPtr;
+ }
+ }
+ }
+ return result;
+}
+
+// decompress/copy 3DO cel data
+void ImageFile3DO::decompress3DOCelFrame(ImageFrame &frame, const byte *dataPtr, uint32 dataSize, byte bitsPerPixel, ImageFile3DOPixelLookupTable *pixelLookupTable) {
+ frame._frame.create(frame._width, frame._height, Graphics::PixelFormat(2, 5, 6, 5, 0, 11, 5, 0, 0));
+ uint16 *dest = (uint16 *)frame._frame.getPixels();
+ Common::fill(dest, dest + frame._width * frame._height, 0);
+
+ int frameHeightLeft = frame._height;
+ int frameWidthLeft = frame._width;
+ uint16 pixelCount = 0;
+ uint16 pixel = 0;
+
+ const byte *srcLineStart = dataPtr;
+ const byte *srcLineData = dataPtr;
+ byte srcLineDataBitsLeft = 0;
+ uint16 lineDWordSize = 0;
+ uint16 lineByteSize = 0;
+
+ if (bitsPerPixel == 16) {
+ // Must not use pixel lookup table on 16-bits-per-pixel data
+ assert(!pixelLookupTable);
+ }
+
+ if (frame._rleEncoded) {
+ // compressed
+ byte compressionType = 0;
+ byte compressionPixels = 0;
+
+ while (frameHeightLeft > 0) {
+ frameWidthLeft = frame._width;
+
+ if (bitsPerPixel >= 8) {
+ lineDWordSize = READ_BE_UINT16(srcLineStart);
+ srcLineData = srcLineStart + 2;
+ } else {
+ lineDWordSize = *srcLineStart;
+ srcLineData = srcLineStart + 1;
+ }
+ srcLineDataBitsLeft = 8;
+
+ lineDWordSize += 2;
+ lineByteSize = lineDWordSize * 4; // calculate compressed data size in bytes for current line
+
+ // debug
+ //warning("offset %d: decoding line, size %d, bytesize %d", srcSeeker - src, dwordSize, lineByteSize);
+
+ while (frameWidthLeft > 0) {
+ // get 2 bits -> compressionType
+ // get 6 bits -> pixel count (0 = 1 pixel)
+ compressionType = celGetBits(srcLineData, 2, srcLineDataBitsLeft);
+ // 6 bits == length (0 = 1 pixel)
+ compressionPixels = celGetBits(srcLineData, 6, srcLineDataBitsLeft) + 1;
+
+ if (!compressionType) // end of line
+ break;
+
+ switch(compressionType) {
+ case 1: // simple copy
+ for (pixelCount = 0; pixelCount < compressionPixels; pixelCount++) {
+ pixel = celGetBits(srcLineData, bitsPerPixel, srcLineDataBitsLeft);
+ if (pixelLookupTable) {
+ pixel = pixelLookupTable->pixelColor[pixel];
+ }
+ *dest++ = convertPixel(pixel);
+ }
+ break;
+ case 2: // transparent
+ for (pixelCount = 0; pixelCount < compressionPixels; pixelCount++) {
+ *dest++ = 0;
+ }
+ break;
+ case 3: // duplicate pixels
+ pixel = celGetBits(srcLineData, bitsPerPixel, srcLineDataBitsLeft);
+ if (pixelLookupTable) {
+ pixel = pixelLookupTable->pixelColor[pixel];
+ }
+ pixel = convertPixel(pixel);
+ for (pixelCount = 0; pixelCount < compressionPixels; pixelCount++) {
+ *dest++ = pixel;
+ }
+ break;
+ default:
+ break;
+ }
+ frameWidthLeft -= compressionPixels;
+ }
+
+ assert(frameWidthLeft >= 0);
+
+ if (frameWidthLeft > 0) {
+ // still pixels left? skip them
+ dest += frameWidthLeft;
+ }
+
+ frameHeightLeft--;
+
+ // Seek to next line start
+ srcLineStart += lineByteSize;
+ }
+ } else {
+ // uncompressed
+ srcLineDataBitsLeft = 8;
+ lineDWordSize = ((frame._width * bitsPerPixel) + 31) >> 5;
+ lineByteSize = lineDWordSize * 4;
+ uint32 totalExpectedSize = lineByteSize * frame._height;
+
+ assert(totalExpectedSize <= dataSize); // security check
+
+ while (frameHeightLeft > 0) {
+ srcLineData = srcLineStart;
+ frameWidthLeft = frame._width;
+
+ while (frameWidthLeft > 0) {
+ pixel = celGetBits(srcLineData, bitsPerPixel, srcLineDataBitsLeft);
+ if (pixelLookupTable) {
+ pixel = pixelLookupTable->pixelColor[pixel];
+ }
+ *dest++ = convertPixel(pixel);
+
+ frameWidthLeft--;
+ }
+ frameHeightLeft--;
+
+ // Seek to next line start
+ srcLineStart += lineByteSize;
+ }
+ }
+}
+
+// Reads Sherlock Holmes 3DO font file
+void ImageFile3DO::loadFont(Common::SeekableReadStream &stream) {
+ uint32 streamSize = stream.size();
+ uint32 header_offsetWidthTable = 0;
+ uint32 header_offsetBitsTable = 0;
+ uint32 header_fontHeight = 0;
+ uint32 header_bytesPerLine = 0;
+ uint32 header_maxChar = 0;
+ uint32 header_charCount = 0;
+
+ byte *widthTablePtr = NULL;
+ uint32 bitsTableSize = 0;
+ byte *bitsTablePtr = NULL;
+
+ stream.skip(2); // Unknown bytes
+ stream.skip(2); // Unknown bytes (0x000E)
+ header_offsetWidthTable = stream.readUint32BE();
+ header_offsetBitsTable = stream.readUint32BE();
+ stream.skip(4); // Unknown bytes (0x00000004)
+ header_fontHeight = stream.readUint32BE();
+ header_bytesPerLine = stream.readUint32BE();
+ header_maxChar = stream.readUint32BE();
+
+ assert(header_maxChar <= 255);
+ header_charCount = header_maxChar + 1;
+
+ // Allocate memory for width table
+ widthTablePtr = new byte[header_charCount];
+
+ stream.seek(header_offsetWidthTable);
+ stream.read(widthTablePtr, header_charCount);
+
+ // Allocate memory for the bits
+ assert(header_offsetBitsTable < streamSize); // Security check
+ bitsTableSize = streamSize - header_offsetBitsTable;
+ bitsTablePtr = new byte[bitsTableSize];
+ stream.read(bitsTablePtr, bitsTableSize);
+
+ // Now extract all characters
+ uint16 curChar = 0;
+ const byte *curBitsLinePtr = bitsTablePtr;
+ const byte *curBitsPtr = NULL;
+ byte curBitsLeft = 0;
+ uint32 curCharHeightLeft = 0;
+ uint32 curCharWidthLeft = 0;
+ byte curBits = 0;
+ byte curBitsReversed = 0;
+ byte curPosX = 0;
+
+ assert(bitsTableSize >= (header_maxChar * header_fontHeight * header_bytesPerLine)); // Security
+
+ // first frame needs to be "!" (33 decimal)
+ // our font code is subtracting 33 from the actual character code
+ curBitsLinePtr += (33 * (header_fontHeight * header_bytesPerLine));
+
+ 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++;
+ }
+
+ curCharHeightLeft--;
+ curBitsLinePtr += header_bytesPerLine;
+ }
+
+ push_back(imageFrame);
+ }
+ }
+
+ // Warning below being used to silence unused variable warnings for now
+ warning("TODO: Remove %d %d", curBitsLeft, curBitsReversed);
+
+ delete[] bitsTablePtr;
+ delete[] widthTablePtr;
+}
+
+/*----------------------------------------------------------------*/
+
+StreamingImageFile::StreamingImageFile() {
+ _frameNumber = 0;
+ _stream = nullptr;
+ _flags = 0;
+ _scaleVal = 0;
+ _zPlacement = 0;
+ _compressed = false;
+ _active = false;
+}
+
+StreamingImageFile::~StreamingImageFile() {
+ close();
+}
+
+void StreamingImageFile::load(Common::SeekableReadStream *stream, bool compressed) {
+ _stream = stream;
+ _compressed = compressed;
+ _frameNumber = -1;
+ _active = true;
+}
+
+void StreamingImageFile::close() {
+ delete _stream;
+ _stream = nullptr;
+ _frameNumber = -1;
+ _active = false;
+}
+
+bool StreamingImageFile::getNextFrame() {
+ // Don't proceed if we're already at the end of the stream
+ if (_stream->pos() >= _stream->size()) {
+ _active = false;
+ return false;
+ }
+
+ // Increment frame number
+ ++_frameNumber;
+
+ // If necessary, decompress the next frame
+ Common::SeekableReadStream *frameStream = _stream;
+ if (_compressed) {
+ uint32 inSize = _stream->readUint32LE();
+ Resources::decompressLZ(*_stream, _buffer, STREAMING_BUFFER_SIZE, inSize);
+ frameStream = new Common::MemoryReadStream(_buffer, 11, DisposeAfterUse::NO);
+ }
+
+ // Load the data for the frame
+ _imageFrame._width = frameStream->readUint16LE() + 1;
+ _imageFrame._height = frameStream->readUint16LE() + 1;
+ _imageFrame._paletteBase = frameStream->readByte();
+ _imageFrame._rleEncoded = frameStream->readByte() == 1;
+ _imageFrame._offset.x = frameStream->readByte();
+ _imageFrame._offset.y = frameStream->readByte();
+ _imageFrame._size = frameStream->readUint16LE() - 11;
+ _imageFrame._rleMarker = frameStream->readByte();
+
+ // Decode the frame
+ if (_compressed) {
+ delete frameStream;
+ _imageFrame.decompressFrame(_buffer + 11, true);
+ } else {
+ byte *data = new byte[_imageFrame._size];
+ _stream->read(data, _imageFrame._size);
+ _imageFrame.decompressFrame(_buffer + 11, true);
+ delete[] data;
+ }
+
+ return true;
+}
+
+} // End of namespace Sherlock
diff --git a/engines/sherlock/image_file.h b/engines/sherlock/image_file.h
new file mode 100644
index 0000000000..da260ab30b
--- /dev/null
+++ b/engines/sherlock/image_file.h
@@ -0,0 +1,208 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public 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_IMAGE_FILE_H
+#define SHERLOCK_IMAGE_FILE_H
+
+#include "common/array.h"
+#include "common/file.h"
+#include "common/hashmap.h"
+#include "common/hash-str.h"
+#include "common/rect.h"
+#include "common/str.h"
+#include "common/stream.h"
+#include "graphics/surface.h"
+
+namespace Sherlock {
+
+class SherlockEngine;
+
+struct ImageFrame {
+ uint32 _size;
+ uint16 _width, _height;
+ int _paletteBase;
+ bool _rleEncoded;
+ Common::Point _offset;
+ byte _rleMarker;
+ Graphics::Surface _frame;
+
+ /**
+ * Decompress a single frame for the sprite
+ */
+ void decompressFrame(const byte *src, bool isRoseTattoo);
+
+ /**
+ * Return the frame width adjusted by a specified scale amount
+ */
+ int sDrawXSize(int scaleVal) const;
+
+ /**
+ * Return the frame height adjusted by a specified scale amount
+ */
+ int sDrawYSize(int scaleVal) const;
+
+ /**
+ * Return the frame offset x adjusted by a specified scale amount
+ */
+ int sDrawXOffset(int scaleVal) const;
+
+ /**
+ * Return the frame offset y adjusted by a specified scale amount
+ */
+ int sDrawYOffset(int scaleVal) const;
+};
+
+class ImageFile : public Common::Array<ImageFrame> {
+private:
+ static SherlockEngine *_vm;
+
+ /**
+ * Load the data of the sprite
+ */
+ void load(Common::SeekableReadStream &stream, bool skipPalette, bool animImages);
+
+ /**
+ * Gets the palette at the start of the sprite file
+ */
+ void loadPalette(Common::SeekableReadStream &stream);
+public:
+ byte _palette[256 * 3];
+public:
+ ImageFile();
+ ImageFile(const Common::String &name, bool skipPal = false, bool animImages = false);
+ ImageFile(Common::SeekableReadStream &stream, bool skipPal = false);
+ ~ImageFile();
+ static void setVm(SherlockEngine *vm);
+};
+
+enum ImageFile3DOType {
+ kImageFile3DOType_Animation = 0,
+ kImageFile3DOType_Cel = 1,
+ kImageFile3DOType_CelAnimation = 2,
+ kImageFile3DOType_RoomFormat = 3,
+ kImageFile3DOType_Font = 4
+};
+
+struct ImageFile3DOPixelLookupTable {
+ uint16 pixelColor[256];
+};
+
+class ImageFile3DO : public ImageFile { // Common::Array<ImageFrame> {
+private:
+ static SherlockEngine *_vm;
+
+ /**
+ * Load the data of the sprite
+ */
+ void load(Common::SeekableReadStream &stream, bool isRoomData);
+
+ /**
+ * convert pixel RGB values from RGB555 to RGB565
+ */
+ inline uint16 convertPixel(uint16 pixel3DO);
+
+ /**
+ * Load 3DO cel file
+ */
+ void load3DOCelFile(Common::SeekableReadStream &stream);
+
+ /**
+ * Load 3DO cel data (room file format)
+ */
+ void load3DOCelRoomData(Common::SeekableReadStream &stream);
+
+ inline uint16 celGetBits(const byte *&dataPtr, byte bitCount, byte &dataBitsLeft);
+
+ /**
+ * Decompress a single frame of a 3DO cel file
+ */
+ void decompress3DOCelFrame(ImageFrame &frame, const byte *dataPtr, uint32 dataSize, byte bitsPerPixel, ImageFile3DOPixelLookupTable *pixelLookupTable);
+
+ /**
+ * Load animation graphics file
+ */
+ void loadAnimationFile(Common::SeekableReadStream &stream);
+
+ /**
+ * Load Sherlock Holmes 3DO font file
+ */
+ void loadFont(Common::SeekableReadStream &stream);
+
+public:
+ ImageFile3DO(const Common::String &name, ImageFile3DOType imageFile3DOType);
+ ImageFile3DO(Common::SeekableReadStream &stream, bool isRoomData = false);
+ ~ImageFile3DO();
+ static void setVm(SherlockEngine *vm);
+};
+
+#define STREAMING_BUFFER_SIZE 65536
+
+class StreamingImageFile {
+private:
+ int _frameNumber;
+ Common::SeekableReadStream *_stream;
+ byte _buffer[STREAMING_BUFFER_SIZE];
+ bool _compressed;
+ bool _active;
+public:
+ ImageFrame _imageFrame;
+
+ Common::Point _position; // Animation position
+ Common::Rect _oldBounds; // Bounds of previous frame
+ Common::Rect _removeBounds; // Remove area for just drawn frame
+
+ int _flags; // Flags
+ int _scaleVal; // Specifies the scale amount
+ int _zPlacement; // Used by doBgAnim for determining Z order
+public:
+ StreamingImageFile();
+ ~StreamingImageFile();
+
+ /**
+ * Initialize reading of the specified stream
+ */
+ void load(Common::SeekableReadStream *stream, bool compressed);
+
+ /**
+ * Close the streamining image file
+ */
+ void close();
+
+ /**
+ * Get the next frame of the file
+ */
+ bool getNextFrame();
+
+ /**
+ * Returns whether there are any remaining frames or not
+ */
+ bool active() const { return _active; }
+
+ /**
+ * Return the current frame number
+ */
+ int frameNumber() const { return _frameNumber; }
+};
+
+} // End of namespace Sherlock
+
+#endif
diff --git a/engines/sherlock/inventory.cpp b/engines/sherlock/inventory.cpp
index a8ecb64102..d0982542f2 100644
--- a/engines/sherlock/inventory.cpp
+++ b/engines/sherlock/inventory.cpp
@@ -22,34 +22,48 @@
#include "sherlock/inventory.h"
#include "sherlock/sherlock.h"
+#include "sherlock/scalpel/scalpel_inventory.h"
#include "sherlock/scalpel/scalpel_user_interface.h"
+#include "sherlock/tattoo/tattoo_inventory.h"
namespace Sherlock {
InventoryItem::InventoryItem(int requiredFlag, const Common::String &name,
const Common::String &description, const Common::String &examine) :
- _requiredFlag(requiredFlag), _name(name), _description(description),
+ _requiredFlag(requiredFlag), _requiredFlag1(0), _name(name), _description(description),
_examine(examine), _lookFlag(0) {
}
-void InventoryItem::synchronize(Common::Serializer &s) {
+InventoryItem::InventoryItem(int requiredFlag, const Common::String &name,
+ const Common::String &description, const Common::String &examine, const Common::String &verbName) :
+ _requiredFlag(requiredFlag), _requiredFlag1(0), _name(name), _description(description),
+ _examine(examine), _lookFlag(0) {
+ _verb._verb = verbName;
+}
+
+void InventoryItem::synchronize(Serializer &s) {
s.syncAsSint16LE(_requiredFlag);
s.syncAsSint16LE(_lookFlag);
s.syncString(_name);
s.syncString(_description);
s.syncString(_examine);
+ _verb.synchronize(s);
}
/*----------------------------------------------------------------*/
+Inventory *Inventory::init(SherlockEngine *vm) {
+ if (vm->getGameID() == GType_SerratedScalpel)
+ return new Scalpel::ScalpelInventory(vm);
+ else
+ return new Tattoo::TattooInventory(vm);
+}
+
Inventory::Inventory(SherlockEngine *vm) : Common::Array<InventoryItem>(), _vm(vm) {
- Common::fill(&_invShapes[0], &_invShapes[MAX_VISIBLE_INVENTORY], (ImageFile *)nullptr);
_invGraphicsLoaded = false;
_invIndex = 0;
_holdings = 0;
_invMode = INVMODE_EXIT;
- for (int i = 0; i < 6; ++i)
- _invShapes[i] = nullptr;
}
Inventory::~Inventory() {
@@ -64,50 +78,31 @@ void Inventory::freeInv() {
}
void Inventory::freeGraphics() {
- for (uint idx = 0; idx < MAX_VISIBLE_INVENTORY; ++idx)
+ int count = _invShapes.size();
+ for (int idx = 0; idx < count; ++idx)
delete _invShapes[idx];
+ _invShapes.clear();
+ _invShapes.resize(count);
- Common::fill(&_invShapes[0], &_invShapes[MAX_VISIBLE_INVENTORY], (ImageFile *)nullptr);
_invGraphicsLoaded = false;
}
-void Inventory::loadInv() {
- // Exit if the inventory names are already loaded
- if (_names.size() > 0)
- return;
-
- // Load the inventory names
- Common::SeekableReadStream *stream = _vm->_res->load("invent.txt");
-
- int streamSize = stream->size();
- while (stream->pos() < streamSize) {
- Common::String name;
- char c;
- while ((c = stream->readByte()) != 0)
- name += c;
-
- _names.push_back(name);
- }
-
- delete stream;
-
- loadGraphics();
-}
-
void Inventory::loadGraphics() {
if (_invGraphicsLoaded)
return;
- // Default all inventory slots to empty
- Common::fill(&_invShapes[0], &_invShapes[MAX_VISIBLE_INVENTORY], (ImageFile *)nullptr);
-
- for (int idx = _invIndex; (idx < _holdings) && (idx - _invIndex) < MAX_VISIBLE_INVENTORY; ++idx) {
+ for (int idx = _invIndex; (idx < _holdings) && (idx - _invIndex) < (int)_invShapes.size(); ++idx) {
// Get the name of the item to be displayed, figure out its accompanying
// .VGS file with its picture, and then load it
int invNum = findInv((*this)[idx]._name);
- Common::String fName = Common::String::format("item%02d.vgs", invNum + 1);
+ Common::String filename = Common::String::format("item%02d.vgs", invNum + 1);
- _invShapes[idx - _invIndex] = new ImageFile(fName);
+ if (!IS_3DO) {
+ // PC
+ _invShapes[idx - _invIndex] = new ImageFile(filename);
+ } else {
+ _invShapes[idx - _invIndex] = new ImageFile3DO(filename, kImageFile3DOType_RoomFormat);
+ }
}
_invGraphicsLoaded = true;
@@ -123,226 +118,6 @@ int Inventory::findInv(const Common::String &name) {
error("Couldn't find inventory item - %s", name.c_str());
}
-void Inventory::putInv(InvSlamMode slamIt) {
- Screen &screen = *_vm->_screen;
- UserInterface &ui = *_vm->_ui;
-
- // If an inventory item has disappeared (due to using it or giving it),
- // a blank space slot may have appeared. If so, adjust the inventory
- if (_invIndex > 0 && _invIndex > (_holdings - 6)) {
- --_invIndex;
- freeGraphics();
- loadGraphics();
- }
-
- if (slamIt != SLAM_SECONDARY_BUFFER) {
- screen.makePanel(Common::Rect(6, 163, 54, 197));
- screen.makePanel(Common::Rect(58, 163, 106, 197));
- screen.makePanel(Common::Rect(110, 163, 158, 197));
- screen.makePanel(Common::Rect(162, 163, 210, 197));
- screen.makePanel(Common::Rect(214, 163, 262, 197));
- screen.makePanel(Common::Rect(266, 163, 314, 197));
- }
-
- // Iterate through displaying up to 6 objects at a time
- for (int idx = _invIndex; idx < _holdings && (idx - _invIndex) < MAX_VISIBLE_INVENTORY; ++idx) {
- int itemNum = idx - _invIndex;
- Surface &bb = slamIt == SLAM_SECONDARY_BUFFER ? screen._backBuffer2 : screen._backBuffer1;
- Common::Rect r(8 + itemNum * 52, 165, 51 + itemNum * 52, 194);
-
- // Draw the background
- if (idx == ui._selector) {
- bb.fillRect(r, 235);
- } else if (slamIt == SLAM_SECONDARY_BUFFER) {
- bb.fillRect(r, BUTTON_MIDDLE);
- }
-
- // Draw the item image
- ImageFrame &frame = (*_invShapes[itemNum])[0];
- bb.transBlitFrom(frame, Common::Point(6 + itemNum * 52 + ((47 - frame._width) / 2),
- 163 + ((33 - frame._height) / 2)));
- }
-
- if (slamIt == SLAM_DISPLAY)
- screen.slamArea(6, 163, 308, 34);
-
- if (slamIt != SLAM_SECONDARY_BUFFER)
- ui.clearInfo();
-
- if (slamIt == 0) {
- invCommands(0);
- } else if (slamIt == SLAM_SECONDARY_BUFFER) {
- screen._backBuffer = &screen._backBuffer2;
- invCommands(0);
- screen._backBuffer = &screen._backBuffer1;
- }
-}
-
-void Inventory::drawInventory(InvNewMode mode) {
- Screen &screen = *_vm->_screen;
- UserInterface &ui = *_vm->_ui;
- InvNewMode tempMode = mode;
-
- loadInv();
-
- if (mode == INVENTORY_DONT_DISPLAY) {
- screen._backBuffer = &screen._backBuffer2;
- }
-
- // Draw the window background
- Surface &bb = *screen._backBuffer;
- 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,
- SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT), BORDER_COLOR);
- bb.fillRect(Common::Rect(0, SHERLOCK_SCREEN_HEIGHT - 2, SHERLOCK_SCREEN_WIDTH,
- SHERLOCK_SCREEN_HEIGHT), BORDER_COLOR);
- bb.fillRect(Common::Rect(2, CONTROLS_Y1 + 10, SHERLOCK_SCREEN_WIDTH - 2, SHERLOCK_SCREEN_HEIGHT - 2),
- INV_BACKGROUND);
-
- // Draw the buttons
- screen.makeButton(Common::Rect(Scalpel::INVENTORY_POINTS[0][0], CONTROLS_Y1, Scalpel::INVENTORY_POINTS[0][1],
- CONTROLS_Y1 + 10), Scalpel::INVENTORY_POINTS[0][2] - screen.stringWidth("Exit") / 2, "Exit");
- screen.makeButton(Common::Rect(Scalpel::INVENTORY_POINTS[1][0], CONTROLS_Y1, Scalpel::INVENTORY_POINTS[1][1],
- CONTROLS_Y1 + 10), Scalpel::INVENTORY_POINTS[1][2] - screen.stringWidth("Look") / 2, "Look");
- screen.makeButton(Common::Rect(Scalpel::INVENTORY_POINTS[2][0], CONTROLS_Y1, Scalpel::INVENTORY_POINTS[2][1],
- CONTROLS_Y1 + 10), Scalpel::INVENTORY_POINTS[2][2] - screen.stringWidth("Use") / 2, "Use");
- screen.makeButton(Common::Rect(Scalpel::INVENTORY_POINTS[3][0], CONTROLS_Y1, Scalpel::INVENTORY_POINTS[3][1],
- CONTROLS_Y1 + 10), Scalpel::INVENTORY_POINTS[3][2] - screen.stringWidth("Give") / 2, "Give");
- screen.makeButton(Common::Rect(Scalpel::INVENTORY_POINTS[4][0], CONTROLS_Y1, Scalpel::INVENTORY_POINTS[4][1],
- CONTROLS_Y1 + 10), Scalpel::INVENTORY_POINTS[4][2], "^^");
- screen.makeButton(Common::Rect(Scalpel::INVENTORY_POINTS[5][0], CONTROLS_Y1, Scalpel::INVENTORY_POINTS[5][1],
- CONTROLS_Y1 + 10), Scalpel::INVENTORY_POINTS[5][2], "^");
- screen.makeButton(Common::Rect(Scalpel::INVENTORY_POINTS[6][0], CONTROLS_Y1, Scalpel::INVENTORY_POINTS[6][1],
- CONTROLS_Y1 + 10), Scalpel::INVENTORY_POINTS[6][2], "_");
- screen.makeButton(Common::Rect(Scalpel::INVENTORY_POINTS[7][0], CONTROLS_Y1, Scalpel::INVENTORY_POINTS[7][1],
- CONTROLS_Y1 + 10), Scalpel::INVENTORY_POINTS[7][2], "__");
-
- if (tempMode == INVENTORY_DONT_DISPLAY)
- mode = LOOK_INVENTORY_MODE;
- _invMode = (InvMode)mode;
-
- if (mode != PLAIN_INVENTORY) {
- ui._oldKey = Scalpel::INVENTORY_COMMANDS[(int)mode];
- } else {
- ui._oldKey = -1;
- }
-
- invCommands(0);
- putInv(SLAM_DONT_DISPLAY);
-
- if (tempMode != INVENTORY_DONT_DISPLAY) {
- if (!ui._slideWindows) {
- screen.slamRect(Common::Rect(0, CONTROLS_Y1, SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT));
- } else {
- ui.summonWindow(false, CONTROLS_Y1);
- }
-
- ui._windowOpen = true;
- } else {
- // Reset the screen back buffer to the first buffer now that drawing is done
- screen._backBuffer = &screen._backBuffer1;
- }
-
- assert(IS_SERRATED_SCALPEL);
- ((Scalpel::ScalpelUserInterface *)_vm->_ui)->_oldUse = -1;
-}
-
-void Inventory::invCommands(bool slamIt) {
- Screen &screen = *_vm->_screen;
- UserInterface &ui = *_vm->_ui;
-
- if (slamIt) {
- screen.buttonPrint(Common::Point(Scalpel::INVENTORY_POINTS[0][2], CONTROLS_Y1),
- _invMode == INVMODE_EXIT ? COMMAND_HIGHLIGHTED :COMMAND_FOREGROUND,
- true, "Exit");
- screen.buttonPrint(Common::Point(Scalpel::INVENTORY_POINTS[1][2], CONTROLS_Y1),
- _invMode == INVMODE_LOOK ? COMMAND_HIGHLIGHTED :COMMAND_FOREGROUND,
- true, "Look");
- screen.buttonPrint(Common::Point(Scalpel::INVENTORY_POINTS[2][2], CONTROLS_Y1),
- _invMode == INVMODE_USE ? COMMAND_HIGHLIGHTED : COMMAND_FOREGROUND,
- true, "Use");
- screen.buttonPrint(Common::Point(Scalpel::INVENTORY_POINTS[3][2], CONTROLS_Y1),
- _invMode == INVMODE_GIVE ? COMMAND_HIGHLIGHTED : COMMAND_FOREGROUND,
- true, "Give");
- screen.print(Common::Point(Scalpel::INVENTORY_POINTS[4][2], CONTROLS_Y1 + 1),
- _invIndex == 0 ? COMMAND_NULL : COMMAND_FOREGROUND,
- "^^");
- screen.print(Common::Point(Scalpel::INVENTORY_POINTS[5][2], CONTROLS_Y1 + 1),
- _invIndex == 0 ? COMMAND_NULL : COMMAND_FOREGROUND,
- "^");
- screen.print(Common::Point(Scalpel::INVENTORY_POINTS[6][2], CONTROLS_Y1 + 1),
- (_holdings - _invIndex <= 6) ? COMMAND_NULL : COMMAND_FOREGROUND,
- "_");
- screen.print(Common::Point(Scalpel::INVENTORY_POINTS[7][2], CONTROLS_Y1 + 1),
- (_holdings - _invIndex <= 6) ? COMMAND_NULL : COMMAND_FOREGROUND,
- "__");
- if (_invMode != INVMODE_LOOK)
- ui.clearInfo();
- } else {
- screen.buttonPrint(Common::Point(Scalpel::INVENTORY_POINTS[0][2], CONTROLS_Y1),
- _invMode == INVMODE_EXIT ? COMMAND_HIGHLIGHTED : COMMAND_FOREGROUND,
- false, "Exit");
- screen.buttonPrint(Common::Point(Scalpel::INVENTORY_POINTS[1][2], CONTROLS_Y1),
- _invMode == INVMODE_LOOK ? COMMAND_HIGHLIGHTED : COMMAND_FOREGROUND,
- false, "Look");
- screen.buttonPrint(Common::Point(Scalpel::INVENTORY_POINTS[2][2], CONTROLS_Y1),
- _invMode == INVMODE_USE ? COMMAND_HIGHLIGHTED : COMMAND_FOREGROUND,
- false, "Use");
- screen.buttonPrint(Common::Point(Scalpel::INVENTORY_POINTS[3][2], CONTROLS_Y1),
- _invMode == INVMODE_GIVE ? COMMAND_HIGHLIGHTED : COMMAND_FOREGROUND,
- false, "Give");
- screen.gPrint(Common::Point(Scalpel::INVENTORY_POINTS[4][2], CONTROLS_Y1),
- _invIndex == 0 ? COMMAND_NULL : COMMAND_FOREGROUND,
- "^^");
- screen.gPrint(Common::Point(Scalpel::INVENTORY_POINTS[5][2], CONTROLS_Y1),
- _invIndex == 0 ? COMMAND_NULL : COMMAND_FOREGROUND,
- "^");
- screen.gPrint(Common::Point(Scalpel::INVENTORY_POINTS[6][2], CONTROLS_Y1),
- (_holdings - _invIndex < 7) ? COMMAND_NULL : COMMAND_FOREGROUND,
- "_");
- screen.gPrint(Common::Point(Scalpel::INVENTORY_POINTS[7][2], CONTROLS_Y1),
- (_holdings - _invIndex < 7) ? COMMAND_NULL : COMMAND_FOREGROUND,
- "__");
- }
-}
-
-void Inventory::highlight(int index, byte color) {
- Screen &screen = *_vm->_screen;
- Surface &bb = *screen._backBuffer;
- 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),
- 163 + ((33 - frame._height) / 2)));
- screen.slamArea(8 + slot * 52, 165, 44, 30);
-}
-
-void Inventory::refreshInv() {
- if (IS_ROSE_TATTOO)
- return;
-
- Screen &screen = *_vm->_screen;
- Talk &talk = *_vm->_talk;
- Scalpel::ScalpelUserInterface &ui = *(Scalpel::ScalpelUserInterface *)_vm->_ui;
-
- ui._invLookFlag = true;
- freeInv();
-
- ui._infoFlag = true;
- ui.clearInfo();
-
- screen._backBuffer2.blitFrom(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));
- loadInv();
- }
-}
-
int Inventory::putNameInInventory(const Common::String &name) {
Scene &scene = *_vm->_scene;
int matches = 0;
@@ -425,7 +200,7 @@ void Inventory::copyToInventory(Object &obj) {
invItem._description = obj._description;
invItem._examine = obj._examine;
invItem._lookFlag = obj._lookFlag;
- invItem._requiredFlag = obj._requiredFlag;
+ invItem._requiredFlag = obj._requiredFlag[0];
insert_at(_holdings, invItem);
++_holdings;
@@ -450,7 +225,7 @@ int Inventory::deleteItemFromInventory(const Common::String &name) {
return 1;
}
-void Inventory::synchronize(Common::Serializer &s) {
+void Inventory::synchronize(Serializer &s) {
s.syncAsSint16LE(_holdings);
uint count = size();
diff --git a/engines/sherlock/inventory.h b/engines/sherlock/inventory.h
index 02f570f5da..057e923e5d 100644
--- a/engines/sherlock/inventory.h
+++ b/engines/sherlock/inventory.h
@@ -25,15 +25,13 @@
#include "common/scummsys.h"
#include "common/array.h"
-#include "common/serializer.h"
#include "common/str-array.h"
#include "sherlock/objects.h"
#include "sherlock/resources.h"
+#include "sherlock/saveload.h"
namespace Sherlock {
-#define MAX_VISIBLE_INVENTORY 6
-
enum InvMode {
INVMODE_EXIT = 0,
INVMODE_LOOK = 1,
@@ -62,18 +60,24 @@ struct InventoryItem {
Common::String _examine;
int _lookFlag;
- InventoryItem() : _requiredFlag(0), _lookFlag(0) {}
+ // Rose Tattoo fields
+ int _requiredFlag1;
+ UseType _verb;
+
+ InventoryItem() : _requiredFlag(0), _lookFlag(0), _requiredFlag1(0) {}
InventoryItem(int requiredFlag, const Common::String &name,
const Common::String &description, const Common::String &examine);
+ InventoryItem(int requiredFlag, const Common::String &name,
+ const Common::String &description, const Common::String &examine, const Common::String &verbName);
/**
* Synchronize the data for an inventory item
*/
- void synchronize(Common::Serializer &s);
+ void synchronize(Serializer &s);
};
class Inventory : public Common::Array<InventoryItem> {
-private:
+protected:
SherlockEngine *_vm;
Common::StringArray _names;
@@ -82,7 +86,7 @@ private:
*/
void copyToInventory(Object &obj);
public:
- ImageFile *_invShapes[MAX_VISIBLE_INVENTORY];
+ Common::Array<ImageFile *> _invShapes;
bool _invGraphicsLoaded;
InvMode _invMode;
int _invIndex;
@@ -93,8 +97,9 @@ public:
*/
void freeGraphics();
public:
+ static Inventory *init(SherlockEngine *vm);
Inventory(SherlockEngine *vm);
- ~Inventory();
+ virtual ~Inventory();
/**
* Free inventory data
@@ -102,12 +107,6 @@ public:
void freeInv();
/**
- * Load the list of names the inventory items correspond to, if not already loaded,
- * and then calls loadGraphics to load the associated graphics
- */
- void loadInv();
-
- /**
* Load the list of names of graphics for the inventory
*/
void loadGraphics();
@@ -119,32 +118,6 @@ public:
int findInv(const Common::String &name);
/**
- * Display the character's inventory. The slamIt parameter specifies:
- */
- void putInv(InvSlamMode slamIt);
-
- /**
- * Put the game into inventory mode and open the interface window.
- */
- void drawInventory(InvNewMode flag);
-
- /**
- * Prints the line of inventory commands at the top of an inventory window with
- * the correct highlighting
- */
- void invCommands(bool slamIt);
-
- /**
- * Set the highlighting color of a given inventory item
- */
- void highlight(int index, byte color);
-
- /**
- * Support method for refreshing the display of the inventory
- */
- void refreshInv();
-
- /**
* Adds a shape from the scene to the player's inventory
*/
int putNameInInventory(const Common::String &name);
@@ -163,7 +136,13 @@ public:
/**
* Synchronize the data for a savegame
*/
- void synchronize(Common::Serializer &s);
+ void synchronize(Serializer &s);
+
+ /**
+ * Load the list of names the inventory items correspond to, if not already loaded,
+ * and then calls loadGraphics to load the associated graphics
+ */
+ virtual void loadInv() = 0;
};
} // End of namespace Sherlock
diff --git a/engines/sherlock/journal.cpp b/engines/sherlock/journal.cpp
index b4b05da991..334cc05abf 100644
--- a/engines/sherlock/journal.cpp
+++ b/engines/sherlock/journal.cpp
@@ -21,113 +21,280 @@
*/
#include "sherlock/journal.h"
-#include "sherlock/sherlock.h"
+#include "sherlock/scalpel/scalpel.h"
+#include "sherlock/scalpel/scalpel_fixed_text.h"
+#include "sherlock/scalpel/scalpel_journal.h"
+#include "sherlock/tattoo/tattoo.h"
+#include "sherlock/tattoo/tattoo_fixed_text.h"
+#include "sherlock/tattoo/tattoo_journal.h"
namespace Sherlock {
-#define JOURNAL_BUTTONS_Y 178
-#define LINES_PER_PAGE 11
-#define JOURNAL_SEARCH_LEFT 15
-#define JOURNAL_SEARCH_TOP 186
-#define JOURNAL_SEARCH_RIGHT 296
-#define JOURNAL_SEACRH_MAX_CHARS 50
-
-// Positioning of buttons in the journal view
-static const int JOURNAL_POINTS[9][3] = {
- { 6, 68, 37 },
- { 69, 131, 100 },
- { 132, 192, 162 },
- { 193, 250, 221 },
- { 251, 313, 281 },
- { 6, 82, 44 },
- { 83, 159, 121 },
- { 160, 236, 198 },
- { 237, 313, 275 }
-};
-
-static const int SEARCH_POINTS[3][3] = {
- { 51, 123, 86 },
- { 124, 196, 159 },
- { 197, 269, 232 }
+static const int TATTOO_LINE_SPACING[17] = {
+ 21, 21, 20, 21, 20, 21, 20, 21, 20, 21, 20, 21, 20, 20, 20, 20, 21
};
/*----------------------------------------------------------------*/
+Journal *Journal::init(SherlockEngine *vm) {
+ if (vm->getGameID() == GType_SerratedScalpel)
+ return new Scalpel::ScalpelJournal(vm);
+ else
+ return new Tattoo::TattooJournal(vm);
+}
+
Journal::Journal(SherlockEngine *vm) : _vm(vm) {
- // Initialize fields
- _maxPage = 0;
- _index = 0;
- _sub = 0;
_up = _down = false;
+ _index = 0;
_page = 1;
-
- if (_vm->_interactiveFl) {
- // Load the journal directory and location names
- loadJournalLocations();
- }
+ _maxPage = 0;
+ _sub = 0;
}
-void Journal::record(int converseNum, int statementNum, bool replyOnly) {
- int saveIndex = _index;
- int saveSub = _sub;
+bool Journal::drawJournal(int direction, int howFar) {
+ Events &events = *_vm->_events;
+ FixedText &fixedText = *_vm->_fixedText;
+ Screen &screen = *_vm->_screen;
+ Talk &talk = *_vm->_talk;
+ int topLineY = IS_SERRATED_SCALPEL ? 37 : 103 - screen.charHeight('A');
+ int yp = topLineY;
+ int startPage = _page;
+ bool endJournal = false;
+ bool firstOccurance = true;
+ bool searchSuccessful = false;
+ bool endFlag = false;
+ int lineNum = 0;
+ int savedIndex;
+ int temp;
+ const char *matchP;
+ int width;
- // Record the entry into the list
- _journal.push_back(JournalEntry(converseNum, statementNum, replyOnly));
- _index = _journal.size() - 1;
+ talk._converseNum = -1;
+ _down = true;
- // Load the text for the new entry to get the number of lines it will have
- loadJournalFile(true);
+ do {
+ // Get the number of lines for the current journal entry
+ loadJournalFile(false);
+ if (_lines.empty()) {
+ // Entry has no text, so it must be a stealth eny. Move onto further journal entries
+ // until an entry with text is found
+ if (++_index == (int)_journal.size()) {
+ endJournal = true;
+ } else {
+ _sub = 0;
+ loadJournalFile(false);
+ }
+ }
+ } while (!endJournal && _lines.empty());
- // Restore old state
- _index = saveIndex;
- _sub = saveSub;
+ // Check if there no further pages with text until the end of the journal
+ if (endJournal) {
+ // If moving forward or backwards, clear the page before printing
+ if (direction)
+ drawFrame();
- // If new lines were added to the ournal, update the total number of lines
- // the journal continues
- if (!_lines.empty()) {
- _maxPage += _lines.size();
- } else {
- // No lines in entry, so remove the new entry from the journal
- _journal.remove_at(_journal.size() - 1);
+ if (IS_SERRATED_SCALPEL)
+ screen.gPrint(Common::Point(235, 21), COL_PEN_COLOR, fixedText.getText(Scalpel::kFixedText_Journal_Page), _page);
+ else
+ screen.gPrint(Common::Point(530, 72), COL_PEN_COLOR, fixedText.getText(Tattoo::kFixedText_Page), _page);
+
+ return false;
}
-}
-void Journal::loadJournalLocations() {
- Resources &res = *_vm->_res;
+ // If the journal page is being changed, set the wait cursor
+ if (direction)
+ events.setCursor(WAIT);
+
+ switch (direction) {
+ case 1:
+ case 4:
+ // Move backwards howFar number of lines unless either the start of the journal is reached,
+ // or a searched for keyword is found
+ do {
+ // Move backwards through the journal file a line at a time
+ if (--_sub < 0) {
+ do {
+ if (--_index < 0) {
+ _index = 0;
+ _sub = 0;
+ endJournal = true;
+ }
+ else {
+ loadJournalFile(false);
+ _sub = _lines.size() - 1;
+ }
+ } while (!endJournal && _lines.empty());
+ }
- _directory.clear();
+ // If it's search mode, check each line for the given keyword
+ if (direction >= 3 && !_lines.empty() && !endJournal && !searchSuccessful) {
+ Common::String line = _lines[_sub];
+ line.toUppercase();
+ if (strstr(line.c_str(), _find.c_str()) != nullptr) {
+ // Found a match. Reset howFar so that the start of page that the match
+ // was found on will be displayed
+ searchSuccessful = true;
+ howFar = ((lineNum / LINES_PER_PAGE) + 1) * LINES_PER_PAGE;
+ }
+ }
- Common::SeekableReadStream *dir = res.load("talk.lib");
- dir->skip(4); // Skip header
+ ++lineNum;
+ } while (lineNum < howFar && !endJournal);
- // Get the numer of entries
- _directory.resize(dir->readUint16LE());
+ if (!_index && !_sub)
+ _page = 1;
+ else
+ _page -= howFar / LINES_PER_PAGE;
+ break;
- // Read in each entry
- char buffer[17];
- for (uint idx = 0; idx < _directory.size(); ++idx) {
- dir->read(buffer, 17);
- buffer[16] = '\0';
+ case 2:
+ case 3:
+ // Move howFar lines ahead unless the end of the journal is reached,
+ // or a searched for keyword is found
+ for (temp = 0; (temp < (howFar / LINES_PER_PAGE)) && !endJournal && !searchSuccessful; ++temp) {
+ // Handle animating mouse cursor
+ events.animateCursorIfNeeded();
- _directory[idx] = Common::String(buffer);
- }
+ lineNum = 0;
+ savedIndex = _index;
+ int savedSub = _sub;
- delete dir;
+ // Move a single page ahead
+ do {
+ // If in search mode, check for keyword
+ if (direction >= 3 && _page != startPage) {
+ Common::String line = _lines[_sub];
+ line.toUppercase();
+ if (strstr(line.c_str(), _find.c_str()) != nullptr)
+ searchSuccessful = true;
+ }
- // Load in the locations stored in journal.txt
- Common::SeekableReadStream *loc = res.load("journal.txt");
+ // Move forwards a line at a time, unless search word was found
+ if (!searchSuccessful) {
+ if (++_sub == (int)_lines.size()) {
+ // Reached end of page
+ do {
+ if (++_index == (int)_journal.size()) {
+ _index = savedIndex;
+ _sub = savedSub;
+ loadJournalFile(false);
+ endJournal = true;
+ } else {
+ _sub = 0;
+ loadJournalFile(false);
+ }
+ } while (!endJournal && _lines.empty());
+ }
- _locations.clear();
- while (loc->pos() < loc->size()) {
- Common::String line;
- char c;
- while ((c = loc->readByte()) != 0)
- line += c;
+ ++lineNum;
+ }
+ } while ((lineNum < LINES_PER_PAGE) && !endJournal && !searchSuccessful);
- _locations.push_back(line);
+ if (!endJournal && !searchSuccessful)
+ // Move to next page
+ ++_page;
+
+ if (searchSuccessful) {
+ // Search found, so show top of the page it was found on
+ _index = savedIndex;
+ _sub = savedSub;
+ loadJournalFile(false);
+ }
+ }
+ break;
+
+ default:
+ break;
}
- delete loc;
+ if (direction) {
+ events.setCursor(ARROW);
+ drawFrame();
+ }
+
+ if (IS_SERRATED_SCALPEL)
+ screen.gPrint(Common::Point(235, 21), COL_PEN_COLOR, fixedText.getText(Scalpel::kFixedText_Journal_Page), _page);
+ else
+ screen.gPrint(Common::Point(530, 72), COL_PEN_COLOR, fixedText.getText(Tattoo::kFixedText_Page), _page);
+
+ temp = _sub;
+ savedIndex = _index;
+ lineNum = 0;
+
+ do {
+ bool inc = true;
+
+ // If there wasn't any line to print at the top of the page, we won't need to
+ // increment the y position
+ if (_lines[temp].empty() && yp == topLineY)
+ inc = false;
+
+ // If there's a searched for keyword in the line, it will need to be highlighted
+ if (searchSuccessful && firstOccurance) {
+ // Check if line has the keyword
+ Common::String line = _lines[temp];
+ line.toUppercase();
+ if ((matchP = strstr(line.c_str(), _find.c_str())) != nullptr) {
+ matchP = _lines[temp].c_str() + (matchP - line.c_str());
+ firstOccurance = false;
+
+ // Print out the start of the line before the matching keyword
+ Common::String lineStart(_lines[temp].c_str(), matchP);
+ if (lineStart.hasPrefix("@")) {
+ width = screen.stringWidth(lineStart.c_str() + 1);
+ screen.gPrint(Common::Point(JOURNAL_LEFT_X, yp), COL_PEN_HIGHLIGHT, "%s", lineStart.c_str() + 1);
+ } else {
+ width = screen.stringWidth(lineStart.c_str());
+ screen.gPrint(Common::Point(JOURNAL_LEFT_X, yp), COL_PEN_COLOR, "%s", lineStart.c_str());
+ }
+
+ // Print out the found keyword
+ Common::String lineMatch(matchP, matchP + _find.size());
+ byte fgColor = IS_SERRATED_SCALPEL ? (byte)Scalpel::INV_FOREGROUND : (byte)Tattoo::INV_FOREGROUND;
+ screen.gPrint(Common::Point(JOURNAL_LEFT_X + width, yp), fgColor, "%s", lineMatch.c_str());
+ width += screen.stringWidth(lineMatch.c_str());
+
+ // Print remainder of line
+ screen.gPrint(Common::Point(JOURNAL_LEFT_X + width, yp), COL_PEN_COLOR, "%s", matchP + _find.size());
+ } else if (_lines[temp].hasPrefix("@")) {
+ screen.gPrint(Common::Point(JOURNAL_LEFT_X, yp), COL_PEN_HIGHLIGHT, "%s", _lines[temp].c_str() + 1);
+ } else {
+ screen.gPrint(Common::Point(JOURNAL_LEFT_X, yp), COL_PEN_COLOR, "%s", _lines[temp].c_str());
+ }
+ } else {
+ if (_lines[temp].hasPrefix("@")) {
+ screen.gPrint(Common::Point(JOURNAL_LEFT_X, yp), COL_PEN_HIGHLIGHT, "%s", _lines[temp].c_str() + 1);
+ } else {
+ screen.gPrint(Common::Point(JOURNAL_LEFT_X, yp), COL_PEN_COLOR, "%s", _lines[temp].c_str());
+ }
+ }
+
+ if (++temp == (int)_lines.size()) {
+ // Move to next page
+ do {
+ if (_index < ((int)_journal.size() - 1) && lineNum < (LINES_PER_PAGE - 1)) {
+ ++_index;
+ loadJournalFile(false);
+ temp = 0;
+ } else {
+ if (_index == ((int)_journal.size() - 1))
+ _down = false;
+ endFlag = true;
+ }
+ } while (!endFlag && _lines.empty());
+ }
+
+ if (inc) {
+ // Move to next line
+ yp += IS_SERRATED_SCALPEL ? 13 : TATTOO_LINE_SPACING[lineNum];
+ ++lineNum;
+ }
+ } while (lineNum < LINES_PER_PAGE && !endFlag);
+
+ _index = savedIndex;
+ _up = _index || _sub;
+
+ return direction >= 3 && searchSuccessful;
}
void Journal::loadJournalFile(bool alreadyLoaded) {
@@ -144,7 +311,7 @@ void Journal::loadJournalFile(bool alreadyLoaded) {
Common::String locStr(dirFilename.c_str() + 4, dirFilename.c_str() + 6);
int newLocation = atoi(locStr.c_str());
- // If not flagged as alrady loaded, load the conversation into script variables
+ // If not flagged as already loaded, load the conversation into script variables
if (!alreadyLoaded) {
// See if the file to be used is already loaded
if (journalEntry._converseNum != talk._converseNum) {
@@ -154,7 +321,7 @@ void Journal::loadJournalFile(bool alreadyLoaded) {
// Find the person being referred to
talk._talkTo = -1;
for (int idx = 0; idx < (int)people._characters.size(); ++idx) {
- Common::String portrait = people[idx]._portrait;
+ Common::String portrait = people._characters[idx]._portrait;
Common::String numStr(portrait.c_str(), portrait.c_str() + 4);
if (locStr == numStr) {
@@ -186,7 +353,10 @@ void Journal::loadJournalFile(bool alreadyLoaded) {
if (newLocation != oldLocation) {
// Add in scene title
- journalString = "@" + _locations[newLocation - 1] + ":";
+ journalString = "@";
+ if (IS_SERRATED_SCALPEL || newLocation - 1 < 100)
+ journalString += _locations[newLocation - 1];
+ journalString += ":";
// See if title can fit into a single line, or requires splitting on 2 lines
int width = screen.stringWidth(journalString.c_str() + 1);
@@ -216,16 +386,12 @@ void Journal::loadJournalFile(bool alreadyLoaded) {
else
journalString += "said to ";
- switch (talk._talkTo) {
- case 1:
+ if (talk._talkTo == 1) {
journalString += "me";
- break;
- case 2:
+ } else if ((talk._talkTo == 2 && IS_SERRATED_SCALPEL) || (talk._talkTo == 18 && IS_ROSE_TATTOO)) {
journalString += "the Inspector";
- break;
- default:
+ } else {
journalString += people._characters[talk._talkTo]._name;
- break;
}
journalString += ", \"";
@@ -239,14 +405,28 @@ void Journal::loadJournalFile(bool alreadyLoaded) {
bool commentFlag = false;
bool commentJustPrinted = false;
const byte *replyP = (const byte *)statement._reply.c_str();
+ const int inspectorId = (IS_SERRATED_SCALPEL) ? 2 : 18;
+ int beforeLastSpeakerChange = journalString.size();
+ bool justChangedSpeaker = true;
while (*replyP) {
byte c = *replyP++;
+ if (IS_ROSE_TATTOO) {
+ // Ignore commented out data
+ if (c == '/' && *(replyP + 1) == '*') {
+ replyP++; // skip *
+ while (*replyP++ != '*') {} // empty loop on purpose
+ replyP++; // skip /
+ c = *replyP;
+ }
+ }
+
// Is it a control character?
if (c < opcodes[0]) {
// Nope. Set flag for allowing control codes to insert spaces
ctrlSpace = true;
+ justChangedSpeaker = false;
assert(c >= ' ');
// Check for embedded comments
@@ -282,7 +462,7 @@ void Journal::loadJournalFile(bool alreadyLoaded) {
} else {
if (talk._talkTo == 1)
journalString += "I";
- else if (talk._talkTo == 2)
+ else if (talk._talkTo == inspectorId)
journalString += "The Inspector";
else
journalString += people._characters[talk._talkTo]._name;
@@ -312,6 +492,15 @@ void Journal::loadJournalFile(bool alreadyLoaded) {
commentJustPrinted = false;
}
} else if (c == opcodes[OP_SWITCH_SPEAKER]) {
+ if (IS_ROSE_TATTOO) {
+ // If the speaker has just changed, then no text has just been added
+ // from the last speaker, so remove the initial "Person said" text
+ if (justChangedSpeaker)
+ journalString = Common::String(journalString.c_str(), journalString.c_str() + beforeLastSpeakerChange);
+
+ justChangedSpeaker = true;
+ }
+
if (!startOfReply) {
if (!commentFlag && !commentJustPrinted)
journalString += "\"\n";
@@ -324,12 +513,14 @@ void Journal::loadJournalFile(bool alreadyLoaded) {
startOfReply = false;
c = *replyP++ - 1;
+ if (IS_ROSE_TATTOO)
+ replyP++;
if (c == 0)
journalString += "Holmes";
else if (c == 1)
journalString += "I";
- else if (c == 2)
+ else if (c == inspectorId)
journalString += "the Inspector";
else
journalString += people._characters[c]._name;
@@ -345,42 +536,119 @@ void Journal::loadJournalFile(bool alreadyLoaded) {
else
journalString += " said, \"";
} else {
- // Control code, so move past it and any parameters
- if (c == opcodes[OP_RUN_CANIMATION] || c == opcodes[OP_ASSIGN_PORTRAIT_LOCATION] ||
- c == opcodes[OP_PAUSE] || c == opcodes[OP_PAUSE_WITHOUT_CONTROL] ||
+ if (IS_SERRATED_SCALPEL) {
+ // Control code, so move past it and any parameters
+ if (c == opcodes[OP_RUN_CANIMATION] ||
+ c == opcodes[OP_ASSIGN_PORTRAIT_LOCATION] ||
+ c == opcodes[OP_PAUSE] ||
+ c == opcodes[OP_PAUSE_WITHOUT_CONTROL] ||
c == opcodes[OP_WALK_TO_CANIMATION]) {
- // These commands have a single parameter
- ++replyP;
-
- } else if (c == opcodes[OP_ADJUST_OBJ_SEQUENCE]) {
- replyP += (replyP[0] & 127) + replyP[1] + 2;
-
- } else if (c == opcodes[OP_WALK_TO_COORDS] || c == opcodes[OP_MOVE_MOUSE]) {
- replyP += 4;
-
- } else if (c == opcodes[OP_SET_FLAG] || c == opcodes[OP_IF_STATEMENT]) {
- replyP += 2;
-
- } else if (c == opcodes[OP_SFX_COMMAND] || c == opcodes[OP_PLAY_PROLOGUE] ||
- c == opcodes[OP_CALL_TALK_FILE]) {
- replyP += 8;
- break;
-
- } else if (c == opcodes[OP_TOGGLE_OBJECT] || c == opcodes[OP_ADD_ITEM_TO_INVENTORY] ||
- c == opcodes[OP_SET_OBJECT] || c == opcodes[OP_DISPLAY_INFO_LINE] ||
- c == opcodes[OP_REMOVE_ITEM_FROM_INVENTORY]) {
- replyP += (*replyP & 127) + 1;
-
- } else if (c == opcodes[OP_GOTO_SCENE]) {
- replyP += 5;
-
- } else if (c == opcodes[OP_CARRIAGE_RETURN]) {
- journalString += "\n";
+ // These commands have a single parameter
+ ++replyP;
+ } else if (c == opcodes[OP_ADJUST_OBJ_SEQUENCE]) {
+ replyP += (replyP[0] & 127) + replyP[1] + 2;
+ } else if (c == opcodes[OP_WALK_TO_COORDS] || c == opcodes[OP_MOVE_MOUSE]) {
+ replyP += 4;
+ } else if (c == opcodes[OP_SET_FLAG] || c == opcodes[OP_IF_STATEMENT]) {
+ replyP += 2;
+ } else if (c == opcodes[OP_SFX_COMMAND] || c == opcodes[OP_PLAY_PROLOGUE] ||
+ c == opcodes[OP_CALL_TALK_FILE]) {
+ replyP += 8;
+ break;
+ } else if (
+ c == opcodes[OP_TOGGLE_OBJECT] ||
+ c == opcodes[OP_ADD_ITEM_TO_INVENTORY] ||
+ c == opcodes[OP_SET_OBJECT] ||
+ c == opcodes[OP_DISPLAY_INFO_LINE] ||
+ c == opcodes[OP_REMOVE_ITEM_FROM_INVENTORY]) {
+ replyP += (*replyP & 127) + 1;
+ } else if (c == opcodes[OP_GOTO_SCENE]) {
+ replyP += 5;
+ } else if (c == opcodes[OP_END_TEXT_WINDOW]) {
+ journalString += "\n";
+ }
+ } else {
+ if (c == opcodes[OP_RUN_CANIMATION] ||
+ c == opcodes[OP_PAUSE] ||
+ c == opcodes[OP_MOUSE_OFF_ON] ||
+ c == opcodes[OP_SET_WALK_CONTROL] ||
+ c == opcodes[OP_PAUSE_WITHOUT_CONTROL] ||
+ c == opcodes[OP_WALK_TO_CANIMATION] ||
+ c == opcodes[OP_TURN_NPC_OFF] ||
+ c == opcodes[OP_TURN_NPC_ON] ||
+ c == opcodes[OP_RESTORE_PEOPLE_SEQUENCE])
+ ++replyP;
+ else if (
+ c == opcodes[OP_SET_TALK_SEQUENCE] ||
+ c == opcodes[OP_SET_FLAG] ||
+ c == opcodes[OP_WALK_NPC_TO_CANIM] ||
+ c == opcodes[OP_WALK_HOLMES_AND_NPC_TO_CANIM] ||
+ c == opcodes[OP_NPC_PATH_LABEL] ||
+ c == opcodes[OP_PATH_GOTO_LABEL])
+ replyP += 2;
+ else if (
+ c == opcodes[OP_SET_NPC_PATH_PAUSE] ||
+ c == opcodes[OP_NPC_PATH_PAUSE_TAKING_NOTES] ||
+ c == opcodes[OP_NPC_PATH_PAUSE_LOOKING_HOLMES] ||
+ c == opcodes[OP_NPC_VERB_CANIM])
+ replyP += 3;
+ else if (
+ c == opcodes[OP_SET_SCENE_ENTRY_FLAG] ||
+ c == opcodes[OP_PATH_IF_FLAG_GOTO_LABEL])
+ replyP += 4;
+ else if (
+ c == opcodes[OP_WALK_TO_COORDS])
+ replyP += 5;
+ else if (
+ c == opcodes[OP_WALK_NPC_TO_COORDS] ||
+ c == opcodes[OP_GOTO_SCENE] ||
+ c == opcodes[OP_SET_NPC_PATH_DEST] ||
+ c == opcodes[OP_SET_NPC_POSITION])
+ replyP += 6;
+ else if (
+ c == opcodes[OP_PLAY_SONG] ||
+ c == opcodes[OP_NEXT_SONG])
+ replyP += 8;
+ else if (
+ c == opcodes[OP_CALL_TALK_FILE] ||
+ c == opcodes[OP_SET_NPC_TALK_FILE] ||
+ c == opcodes[OP_NPC_WALK_GRAPHICS])
+ replyP += 9;
+ else if (
+ c == opcodes[OP_NPC_VERB_SCRIPT])
+ replyP += 10;
+ else if (
+ c == opcodes[OP_WALK_HOLMES_AND_NPC_TO_COORDS])
+ replyP += 11;
+ else if (
+ c == opcodes[OP_NPC_VERB] ||
+ c == opcodes[OP_NPC_VERB_TARGET])
+ replyP += 14;
+ else if (
+ c == opcodes[OP_ADJUST_OBJ_SEQUENCE])
+ replyP += (replyP[0] & 127) + replyP[1] + 2;
+ else if (
+ c == opcodes[OP_TOGGLE_OBJECT] ||
+ c == opcodes[OP_ADD_ITEM_TO_INVENTORY] ||
+ c == opcodes[OP_SET_OBJECT] ||
+ c == opcodes[OP_REMOVE_ITEM_FROM_INVENTORY])
+ replyP += (*replyP & 127) + 1;
+ else if (
+ c == opcodes[OP_END_TEXT_WINDOW]) {
+ journalString += '\n';
+ } else if (
+ c == opcodes[OP_NPC_DESC_ON_OFF]) {
+ replyP++;
+ while (replyP[0] && replyP[0] != opcodes[OP_NPC_DESC_ON_OFF])
+ replyP++;
+ } else if (
+ c == opcodes[OP_SET_NPC_INFO_LINE])
+ replyP += replyP[1] + 2;
}
// Put a space in the output for a control character, unless it's
// immediately coming after another control character
- if (ctrlSpace && c != opcodes[OP_ASSIGN_PORTRAIT_LOCATION] && c != opcodes[OP_CARRIAGE_RETURN] &&
+ if (ctrlSpace && c != opcodes[OP_ASSIGN_PORTRAIT_LOCATION] && c != opcodes[OP_END_TEXT_WINDOW] &&
!commentJustPrinted) {
journalString += " ";
ctrlSpace = false;
@@ -391,6 +659,9 @@ void Journal::loadJournalFile(bool alreadyLoaded) {
if (!startOfReply && !commentJustPrinted)
journalString += '"';
+ if (IS_ROSE_TATTOO && justChangedSpeaker)
+ journalString = Common::String(journalString.c_str(), journalString.c_str() + beforeLastSpeakerChange);
+
// Finally finished building the journal text. Need to process the text to
// word wrap it to fit on-screen. The resulting lines are stored in the
// _lines array
@@ -431,727 +702,38 @@ void Journal::loadJournalFile(bool alreadyLoaded) {
}
}
-void Journal::drawJournalFrame() {
- Resources &res = *_vm->_res;
- Screen &screen = *_vm->_screen;
- byte palette[PALETTE_SIZE];
-
- // Load in the journal background
- Common::SeekableReadStream *bg = res.load("journal.lbv");
- bg->read(screen._backBuffer1.getPixels(), SHERLOCK_SCREEN_WIDTH * SHERLOCK_SCREEN_HEIGHT);
- bg->read(palette, PALETTE_SIZE);
- delete bg;
-
- // Translate the palette for display
- for (int idx = 0; idx < PALETTE_SIZE; ++idx)
- palette[idx] = VGA_COLOR_TRANS(palette[idx]);
-
- // Set the palette and print the title
- screen.setPalette(palette);
- screen.gPrint(Common::Point(111, 18), BUTTON_BOTTOM, "Watson's Journal");
- screen.gPrint(Common::Point(110, 17), INV_FOREGROUND, "Watson's Journal");
-
- // 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("Exit") / 2, "Exit");
- 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("Back 10") / 2, "Back 10");
- 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("Up") / 2, "Up");
- 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("Down") / 2, "Down");
- 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("Ahead 10") / 2, "Ahead 10");
- 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("Search") / 2, "Search");
- 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("First Page") / 2, "First Page");
- 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("Last Page") / 2, "Last Page");
-
- // 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("Print Text") / 2, "Print Text");
- screen.buttonPrint(Common::Point(JOURNAL_POINTS[8][2], JOURNAL_BUTTONS_Y + 11),
- COMMAND_NULL, false, "Print Text");
-}
-
-void Journal::drawInterface() {
- Screen &screen = *_vm->_screen;
-
- drawJournalFrame();
-
- if (_journal.empty()) {
- _up = _down = 0;
- } else {
- drawJournal(0, 0);
- }
-
- doArrows();
-
- // Show the entire screen
- screen.slamArea(0, 0, SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT);
-}
-
-void Journal::doArrows() {
- Screen &screen = *_vm->_screen;
- byte color;
-
- color = (_page > 1) ? COMMAND_FOREGROUND : COMMAND_NULL;
- screen.buttonPrint(Common::Point(JOURNAL_POINTS[1][2], JOURNAL_BUTTONS_Y), color, false, "Back 10");
- screen.buttonPrint(Common::Point(JOURNAL_POINTS[2][2], JOURNAL_BUTTONS_Y), color, false, "Up");
-
- color = _down ? COMMAND_FOREGROUND : COMMAND_NULL;
- screen.buttonPrint(Common::Point(JOURNAL_POINTS[3][2], JOURNAL_BUTTONS_Y), color, false, "Down");
- screen.buttonPrint(Common::Point(JOURNAL_POINTS[4][2], JOURNAL_BUTTONS_Y), color, false, "Ahead 10");
- screen.buttonPrint(Common::Point(JOURNAL_POINTS[7][2], JOURNAL_BUTTONS_Y + 11), color, false, "Last Page");
-
- color = _journal.size() > 0 ? COMMAND_FOREGROUND : COMMAND_NULL;
- screen.buttonPrint(Common::Point(JOURNAL_POINTS[5][2], JOURNAL_BUTTONS_Y + 11), color, false, "Search");
- screen.buttonPrint(Common::Point(JOURNAL_POINTS[8][2], JOURNAL_BUTTONS_Y + 11), COMMAND_NULL, false, "Print Text");
-
- color = _page > 1 ? COMMAND_FOREGROUND : COMMAND_NULL;
- screen.buttonPrint(Common::Point(JOURNAL_POINTS[6][2], JOURNAL_BUTTONS_Y + 11), color, false, "First Page");
-}
-
-bool Journal::drawJournal(int direction, int howFar) {
- Events &events = *_vm->_events;
- Screen &screen = *_vm->_screen;
- Talk &talk = *_vm->_talk;
- int yp = 37;
- int startPage = _page;
- bool endJournal = false;
- bool firstOccurance = true;
- bool searchSuccessful = false;
- bool endFlag = false;
- int lineNum = 0;
- int savedIndex;
- int temp;
- const char *matchP;
- int width;
-
- talk._converseNum = -1;
- _down = true;
-
- do {
- // Get the number of lines for the current journal entry
- loadJournalFile(false);
- if (_lines.empty()) {
- // Entry has no text, so it must be a stealth eny. Move onto further journal entries
- // until an entry with text is found
- if (++_index == (int)_journal.size()) {
- endJournal = true;
- } else {
- _sub = 0;
- loadJournalFile(false);
- }
- }
- } while (!endJournal && _lines.empty());
-
- // Check if there no further pages with text until the end of the journal
- if (endJournal) {
- // If moving forward or backwards, clear the page before printing
- if (direction)
- drawJournalFrame();
-
- screen.gPrint(Common::Point(235, 21), PEN_COLOR, "Page %d", _page);
- return false;
- }
-
- // If the journal page is being changed, set the wait cursor
- if (direction)
- events.setCursor(WAIT);
-
- switch (direction) {
- case 1:
- case 4:
- // Move backwards howFar number of lines unless either the start of the journal is reached,
- // or a searched for keyword is found
- do {
- // Animate the glass mouse cursor
- int cursorNum = (int)events.getCursor() + 1;
- if (cursorNum > (WAIT + 2))
- cursorNum = WAIT;
- events.setCursor((CursorId)cursorNum);
-
- // Move backwards through the journal file a line at a time
- if (--_sub < 0) {
- do {
- if (--_index < 0) {
- _index = 0;
- _sub = 0;
- endJournal = true;
- }
- else {
- loadJournalFile(false);
- _sub = _lines.size() - 1;
- }
- } while (!endJournal && _lines.empty());
- }
-
- // If it's search mode, check each line for the given keyword
- if (direction >= 3 && !_lines.empty() && !endJournal && !searchSuccessful) {
- Common::String line = _lines[_sub];
- line.toUppercase();
- if (strstr(line.c_str(), _find.c_str()) != nullptr) {
- // Found a match. Reset howFar so that the start of page that the match
- // was found on will be displayed
- searchSuccessful = true;
- howFar = ((lineNum / LINES_PER_PAGE) + 1) * LINES_PER_PAGE;
- }
- }
-
- ++lineNum;
- } while (lineNum < howFar && !endJournal);
-
- if (!_index && !_sub)
- _page = 1;
- else
- _page -= howFar / LINES_PER_PAGE;
- break;
-
- case 2:
- case 3:
- // Move howFar lines ahead unless the end of the journal is reached,
- // or a searched for keyword is found
- for (temp = 0; (temp < (howFar / LINES_PER_PAGE)) && !endJournal && !searchSuccessful; ++temp) {
- // Handle animating mouse cursor
- int cursorNum = (int)events.getCursor() + 1;
- if (cursorNum >(WAIT + 2))
- cursorNum = WAIT;
- events.setCursor((CursorId)cursorNum);
-
- lineNum = 0;
- savedIndex = _index;
- int savedSub = _sub;
-
- // Move a single page ahead
- do {
- // If in search mode, check for keyword
- if (direction >= 3 && _page != startPage) {
- Common::String line = _lines[_sub];
- line.toUppercase();
- if (strstr(line.c_str(), _find.c_str()) != nullptr)
- searchSuccessful = true;
- }
-
- // Move forwards a line at a time, unless search word was found
- if (!searchSuccessful) {
- if (++_sub == (int)_lines.size()) {
- // Reached end of page
- do {
- if (++_index == (int)_journal.size()) {
- _index = savedIndex;
- _sub = savedSub;
- loadJournalFile(false);
- endJournal = true;
- } else {
- _sub = 0;
- loadJournalFile(false);
- }
- } while (!endJournal && _lines.empty());
- }
-
- ++lineNum;
- }
- } while ((lineNum < LINES_PER_PAGE) && !endJournal && !searchSuccessful);
-
- if (!endJournal && !searchSuccessful)
- // Move to next page
- ++_page;
-
- if (searchSuccessful) {
- // Search found, so show top of the page it was found on
- _index = savedIndex;
- _sub = savedSub;
- loadJournalFile(false);
- }
- }
- break;
-
- default:
- break;
- }
-
- if (direction) {
- events.setCursor(ARROW);
- drawJournalFrame();
- }
-
- screen.gPrint(Common::Point(235, 21), PEN_COLOR, "Page %d", _page);
-
- temp = _sub;
- savedIndex = _index;
- lineNum = 0;
-
- do {
- bool inc = true;
-
- // If there wasn't any line to print at the top of the page, we won't need to
- // increment the y position
- if (_lines[temp].empty() && yp == 37)
- inc = false;
-
- // If there's a searched for keyword in the line, it will need to be highlighted
- if (searchSuccessful && firstOccurance) {
- // Check if line has the keyword
- Common::String line = _lines[temp];
- line.toUppercase();
- if ((matchP = strstr(line.c_str(), _find.c_str())) != nullptr) {
- matchP = _lines[temp].c_str() + (matchP - line.c_str());
- firstOccurance = false;
-
- // Print out the start of the line before the matching keyword
- Common::String lineStart(_lines[temp].c_str(), matchP);
- if (lineStart.hasPrefix("@")) {
- width = screen.stringWidth(lineStart.c_str() + 1);
- screen.gPrint(Common::Point(53, yp), 15, "%s", lineStart.c_str() + 1);
- } else {
- width = screen.stringWidth(lineStart.c_str());
- screen.gPrint(Common::Point(53, yp), PEN_COLOR, "%s", lineStart.c_str());
- }
-
- // Print out the found keyword
- Common::String lineMatch(matchP, matchP + _find.size());
- screen.gPrint(Common::Point(53 + width, yp), INV_FOREGROUND, "%s", lineMatch.c_str());
- width += screen.stringWidth(lineMatch.c_str());
-
- // Print remainder of line
- screen.gPrint(Common::Point(53 + width, yp), PEN_COLOR, "%s", matchP + _find.size());
- } else if (_lines[temp].hasPrefix("@")) {
- screen.gPrint(Common::Point(53, yp), 15, "%s", _lines[temp].c_str() + 1);
- } else {
- screen.gPrint(Common::Point(53, yp), PEN_COLOR, "%s", _lines[temp].c_str());
- }
- } else {
- if (_lines[temp].hasPrefix("@")) {
- screen.gPrint(Common::Point(53, yp), 15, "%s", _lines[temp].c_str() + 1);
- } else {
- screen.gPrint(Common::Point(53, yp), PEN_COLOR, "%s", _lines[temp].c_str());
- }
- }
-
- if (++temp == (int)_lines.size()) {
- // Move to next page
- do {
- if (_index < ((int)_journal.size() - 1) && lineNum < (LINES_PER_PAGE - 1)) {
- ++_index;
- loadJournalFile(false);
- temp = 0;
- } else {
- if (_index == ((int)_journal.size() - 1))
- _down = false;
- endFlag = true;
- }
- } while (!endFlag && _lines.empty());
- }
-
- if (inc) {
- // Move to next line
- ++lineNum;
- yp += 13;
- }
- } while (lineNum < LINES_PER_PAGE && !endFlag);
-
- _index = savedIndex;
- _up = _index || _sub;
-
- return direction >= 3 && searchSuccessful;
-}
-
-JournalButton Journal::getHighlightedButton(const Common::Point &pt) {
- if (pt.x > JOURNAL_POINTS[0][0] && pt.x < JOURNAL_POINTS[0][1] && pt.y >= JOURNAL_BUTTONS_Y &&
- pt.y < (JOURNAL_BUTTONS_Y + 10))
- return BTN_EXIT;
-
- if (pt.x > JOURNAL_POINTS[1][0] && pt.x < JOURNAL_POINTS[1][1] && pt.y >= JOURNAL_BUTTONS_Y &&
- pt.y < (JOURNAL_BUTTONS_Y + 10) && _page > 1)
- return BTN_BACK10;
-
- if (pt.x > JOURNAL_POINTS[2][0] && pt.x < JOURNAL_POINTS[2][1] && pt.y >= JOURNAL_BUTTONS_Y &&
- pt.y < (JOURNAL_BUTTONS_Y + 10) && _up)
- return BTN_UP;
-
- if (pt.x > JOURNAL_POINTS[3][0] && pt.x < JOURNAL_POINTS[3][1] && pt.y >= JOURNAL_BUTTONS_Y &&
- pt.y < (JOURNAL_BUTTONS_Y + 10) && _down)
- return BTN_DOWN;
-
- if (pt.x > JOURNAL_POINTS[4][0] && pt.x < JOURNAL_POINTS[4][1] && pt.y >= JOURNAL_BUTTONS_Y &&
- pt.y < (JOURNAL_BUTTONS_Y + 10) && _down)
- return BTN_AHEAD110;
-
- if (pt.x > JOURNAL_POINTS[5][0] && pt.x < JOURNAL_POINTS[5][1] && pt.y >= (JOURNAL_BUTTONS_Y + 11) &&
- pt.y < (JOURNAL_BUTTONS_Y + 20) && !_journal.empty())
- return BTN_SEARCH;
-
- if (pt.x > JOURNAL_POINTS[6][0] && pt.x < JOURNAL_POINTS[6][1] && pt.y >= (JOURNAL_BUTTONS_Y + 11) &&
- pt.y < (JOURNAL_BUTTONS_Y + 20) && _up)
- return BTN_FIRST_PAGE;
-
- if (pt.x > JOURNAL_POINTS[7][0] && pt.x < JOURNAL_POINTS[7][1] && pt.y >= (JOURNAL_BUTTONS_Y + 11) &&
- pt.y < (JOURNAL_BUTTONS_Y + 20) && _down)
- return BTN_LAST_PAGE;
-
- if (pt.x > JOURNAL_POINTS[8][0] && pt.x < JOURNAL_POINTS[8][1] && pt.y >= (JOURNAL_BUTTONS_Y + 11) &&
- pt.y < (JOURNAL_BUTTONS_Y + 20) && !_journal.empty())
- return BTN_PRINT_TEXT;
-
- return BTN_NONE;
-}
-
-bool Journal::handleEvents(int key) {
- Events &events = *_vm->_events;
- Screen &screen = *_vm->_screen;
- bool doneFlag = false;
-
- Common::Point pt = events.mousePos();
- JournalButton btn = getHighlightedButton(pt);
- byte color;
-
- if (events._pressed || events._released) {
- // Exit button
- color = (btn == BTN_EXIT) ? COMMAND_HIGHLIGHTED : COMMAND_FOREGROUND;
- screen.buttonPrint(Common::Point(JOURNAL_POINTS[0][2], JOURNAL_BUTTONS_Y), color, true, "Exit");
-
- // Back 10 button
- if (btn == BTN_BACK10) {
- screen.buttonPrint(Common::Point(JOURNAL_POINTS[1][2], JOURNAL_BUTTONS_Y), COMMAND_HIGHLIGHTED, true, "Back 10");
- } else if (_page > 1) {
- screen.buttonPrint(Common::Point(JOURNAL_POINTS[1][2], JOURNAL_BUTTONS_Y), COMMAND_FOREGROUND, true, "Back 10");
- }
-
- // Up button
- if (btn == BTN_UP) {
- screen.buttonPrint(Common::Point(JOURNAL_POINTS[2][2], JOURNAL_BUTTONS_Y), COMMAND_HIGHLIGHTED, true, "Up");
- } else if (_up) {
- screen.buttonPrint(Common::Point(JOURNAL_POINTS[2][2], JOURNAL_BUTTONS_Y), COMMAND_FOREGROUND, true, "Up");
- }
-
- // Down button
- if (btn == BTN_DOWN) {
- screen.buttonPrint(Common::Point(JOURNAL_POINTS[3][2], JOURNAL_BUTTONS_Y), COMMAND_HIGHLIGHTED, true, "Down");
- } else if (_down) {
- screen.buttonPrint(Common::Point(JOURNAL_POINTS[3][2], JOURNAL_BUTTONS_Y), COMMAND_FOREGROUND, true, "Down");
- }
-
- // Ahead 10 button
- if (btn == BTN_AHEAD110) {
- screen.buttonPrint(Common::Point(JOURNAL_POINTS[4][2], JOURNAL_BUTTONS_Y), COMMAND_HIGHLIGHTED, true, "Ahead 10");
- } else if (_down) {
- screen.buttonPrint(Common::Point(JOURNAL_POINTS[4][2], JOURNAL_BUTTONS_Y), COMMAND_FOREGROUND, true, "Ahead 10");
- }
-
- // Search button
- if (btn == BTN_SEARCH) {
- color = COMMAND_HIGHLIGHTED;
- } else if (_journal.empty()) {
- color = COMMAND_NULL;
- } else {
- color = COMMAND_FOREGROUND;
- }
- screen.buttonPrint(Common::Point(JOURNAL_POINTS[5][2], JOURNAL_BUTTONS_Y + 11), color, true, "Search");
-
- // First Page button
- if (btn == BTN_FIRST_PAGE) {
- color = COMMAND_HIGHLIGHTED;
- } else if (_up) {
- color = COMMAND_FOREGROUND;
- } else {
- color = COMMAND_NULL;
- }
- screen.buttonPrint(Common::Point(JOURNAL_POINTS[6][2], JOURNAL_BUTTONS_Y + 11), color, true, "First Page");
-
- // Last Page button
- if (btn == BTN_LAST_PAGE) {
- color = COMMAND_HIGHLIGHTED;
- } else if (_down) {
- color = COMMAND_FOREGROUND;
- } else {
- color = COMMAND_NULL;
- }
- screen.buttonPrint(Common::Point(JOURNAL_POINTS[7][2], JOURNAL_BUTTONS_Y + 11), color, true, "Last Page");
-
- // Print Text button
- screen.buttonPrint(Common::Point(JOURNAL_POINTS[8][2], JOURNAL_BUTTONS_Y + 11), COMMAND_NULL, true, "Print Text");
- }
-
- if (btn == BTN_EXIT && events._released) {
- // Exit button pressed
- doneFlag = true;
-
- } else if (((btn == BTN_BACK10 && events._released) || key == 'B') && (_page > 1)) {
- // Scrolll up 10 pages
- if (_page < 11)
- drawJournal(1, (_page - 1) * LINES_PER_PAGE);
- else
- drawJournal(1, 10 * LINES_PER_PAGE);
-
- doArrows();
- screen.slamArea(0, 0, SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT);
-
- } else if (((btn == BTN_UP && events._released) || key == 'U') && _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) {
- // 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) {
- // Scroll down 10 pages
- if ((_page + 10) > _maxPage)
- drawJournal(2, (_maxPage - _page) * LINES_PER_PAGE);
- else
- drawJournal(2, 10 * LINES_PER_PAGE);
-
- 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");
- bool notFound = false;
-
- do {
- int dir;
- if ((dir = getSearchString(notFound)) != 0) {
- int savedIndex = _index;
- int savedSub = _sub;
- int savedPage = _page;
-
- if (drawJournal(dir + 2, 1000 * LINES_PER_PAGE) == 0) {
- _index = savedIndex;
- _sub = savedSub;
- _page = savedPage;
-
- drawJournalFrame();
- drawJournal(0, 0);
- notFound = true;
- } else {
- doneFlag = true;
- }
-
- doArrows();
- screen.slamArea(0, 0, SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT);
- } else {
- doneFlag = true;
- }
- } while (!doneFlag);
- doneFlag = false;
-
- } else if (((btn == BTN_FIRST_PAGE && events._released) || key == 'F') && _up) {
- // First page
- _index = _sub = 0;
- _up = _down = false;
- _page = 1;
-
- drawJournalFrame();
- drawJournal(0, 0);
- doArrows();
- screen.slamArea(0, 0, SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT);
-
- } else if (((btn == BTN_LAST_PAGE && events._released) || key == 'L') && _down) {
- // Last page
- if ((_page + 10) > _maxPage)
- drawJournal(2, (_maxPage - _page) * LINES_PER_PAGE);
- else
- drawJournal(2, 1000 * LINES_PER_PAGE);
-
- doArrows();
- screen.slamArea(0, 0, SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT);
- }
-
- events.wait(2);
-
- return doneFlag;
-}
-
-int Journal::getSearchString(bool printError) {
- enum Button { BTN_NONE, BTN_EXIT, BTN_BACKWARD, BTN_FORWARD };
-
- Events &events = *_vm->_events;
- Screen &screen = *_vm->_screen;
- Talk &talk = *_vm->_talk;
- int xp;
- int yp = 174;
- bool flag = false;
- Common::String name;
- int done = 0;
- byte color;
-
- // 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("Exit") / 2, "Exit");
- screen.makeButton(Common::Rect(SEARCH_POINTS[1][0], yp, SEARCH_POINTS[1][1], yp + 10),
- SEARCH_POINTS[1][2] - screen.stringWidth("Backward") / 2, "Backward");
- screen.makeButton(Common::Rect(SEARCH_POINTS[2][0], yp, SEARCH_POINTS[2][1], yp + 10),
- SEARCH_POINTS[2][2] - screen.stringWidth("Forward") / 2, "Forward");
- screen.gPrint(Common::Point(SEARCH_POINTS[0][2] - screen.stringWidth("Exit") / 2, yp),
- COMMAND_FOREGROUND, "E");
- screen.gPrint(Common::Point(SEARCH_POINTS[1][2] - screen.stringWidth("Backward") / 2, yp),
- COMMAND_FOREGROUND, "B");
- screen.gPrint(Common::Point(SEARCH_POINTS[2][2] - screen.stringWidth("Forward") / 2, yp),
- COMMAND_FOREGROUND, "F");
-
- 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("Text Not Found !")) / 2, 185),
- INV_FOREGROUND, "Text Not Found !");
- } 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());
- name = _find;
- }
-
- screen.slamArea(6, 171, 307, 28);
-
- if (printError) {
- // Give time for user to see the message
- events.setButtonState();
- for (int idx = 0; idx < 40 && !_vm->shouldQuit() && !events.kbHit() && !events._released; ++idx) {
- events.pollEvents();
- events.setButtonState();
- events.wait(2);
- }
-
- events.clearKeyboard();
- screen._backBuffer1.fillRect(Common::Rect(13, 186, 306, 195), BUTTON_MIDDLE);
-
- if (!_find.empty()) {
- screen.gPrint(Common::Point(15, 185), TALK_FOREGROUND, "%s", _find.c_str());
- name = _find;
- }
+void Journal::record(int converseNum, int statementNum, bool replyOnly) {
+ int saveIndex = _index;
+ int saveSub = _sub;
- screen.slamArea(0, 0, SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT);
+ if (IS_3DO) {
+ // there seems to be no journal in the 3DO version
+ return;
}
- xp = JOURNAL_SEARCH_LEFT + screen.stringWidth(name);
- yp = JOURNAL_SEARCH_TOP;
-
- do {
- events._released = false;
- Button found = BTN_NONE;
-
- while (!_vm->shouldQuit() && !events.kbHit() && !events._released) {
- found = BTN_NONE;
- if (talk._talkToAbort)
- return 0;
-
- // Check if key or mouse button press has occurred
- events.setButtonState();
- Common::Point pt = events.mousePos();
-
- flag = !flag;
- screen.vgaBar(Common::Rect(xp, yp, xp + 8, yp + 9), flag ? INV_FOREGROUND : BUTTON_MIDDLE);
-
- if (events._pressed || events._released) {
- if (pt.x > SEARCH_POINTS[0][0] && pt.x < SEARCH_POINTS[0][1] && pt.y > 174 && pt.y < 183) {
- found = BTN_EXIT;
- color = COMMAND_HIGHLIGHTED;
- } else {
- color = COMMAND_FOREGROUND;
- }
- screen.print(Common::Point(SEARCH_POINTS[0][2] - screen.stringWidth("Exit") / 2, 175), color, "Exit");
-
- if (pt.x > SEARCH_POINTS[1][0] && pt.x < SEARCH_POINTS[1][1] && pt.y > 174 && pt.y < 183) {
- found = BTN_BACKWARD;
- color = COMMAND_HIGHLIGHTED;
- } else {
- color = COMMAND_FOREGROUND;
- }
- screen.print(Common::Point(SEARCH_POINTS[1][2] - screen.stringWidth("Backward") / 2, 175), color, "Backward");
-
- if (pt.x > SEARCH_POINTS[2][0] && pt.x < SEARCH_POINTS[2][1] && pt.y > 174 && pt.y < 183) {
- found = BTN_FORWARD;
- color = COMMAND_HIGHLIGHTED;
- } else {
- color = COMMAND_FOREGROUND;
- }
- screen.print(Common::Point(SEARCH_POINTS[2][2] - screen.stringWidth("Forward") / 2, 175), color, "Forward");
- }
-
- events.wait(2);
- }
+ // Record the entry into the list
+ _journal.push_back(JournalEntry(converseNum, statementNum, replyOnly));
+ _index = _journal.size() - 1;
- if (events.kbHit()) {
- Common::KeyState keyState = events.getKey();
-
- if ((keyState.keycode == Common::KEYCODE_BACKSPACE) && (name.size() > 0)) {
- screen.vgaBar(Common::Rect(xp - screen.charWidth(name.lastChar()), yp, xp + 8, yp + 9), BUTTON_MIDDLE);
- xp -= screen.charWidth(name.lastChar());
- screen.vgaBar(Common::Rect(xp, yp, xp + 8, yp + 9), INV_FOREGROUND);
- name.deleteLastChar();
-
- } else if (keyState.keycode == Common::KEYCODE_RETURN) {
- done = 1;
-
- } else if (keyState.keycode == Common::KEYCODE_ESCAPE) {
- screen.vgaBar(Common::Rect(xp, yp, xp + 8, yp + 9), BUTTON_MIDDLE);
- done = -1;
-
- } else if (keyState.ascii >= ' ' && keyState.ascii <= 'z' && keyState.keycode != Common::KEYCODE_AT &&
- name.size() < JOURNAL_SEACRH_MAX_CHARS && (xp + screen.charWidth(keyState.ascii)) < JOURNAL_SEARCH_RIGHT) {
- char ch = toupper(keyState.ascii);
- screen.vgaBar(Common::Rect(xp, yp, xp + 8, yp + 9), BUTTON_MIDDLE);
- screen.print(Common::Point(xp, yp), TALK_FOREGROUND, "%c", ch);
- xp += screen.charWidth(ch);
- name += ch;
- }
- }
+ // Load the text for the new entry to get the number of lines it will have
+ loadJournalFile(true);
- if (events._released) {
- switch (found) {
- case BTN_EXIT:
- done = -1; break;
- case BTN_BACKWARD:
- done = 2; break;
- case BTN_FORWARD:
- done = 1; break;
- default:
- break;
- }
- }
- } while (!done && !_vm->shouldQuit());
+ // Restore old state
+ _index = saveIndex;
+ _sub = saveSub;
- if (done != -1) {
- _find = name;
+ // If new lines were added to the ournal, update the total number of lines
+ // the journal continues
+ if (!_lines.empty()) {
+ _maxPage += _lines.size();
} else {
- done = 0;
+ // No lines in entry, so remove the new entry from the journal
+ _journal.remove_at(_journal.size() - 1);
}
-
- // Redisplay the journal screen
- drawJournalFrame();
- drawJournal(0, 0);
- screen.slamArea(0, 0, SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT);
-
- return done;
}
-void Journal::resetPosition() {
- _index = _sub = _up = _down = 0;
- _page = 1;
-}
-void Journal::synchronize(Common::Serializer &s) {
+void Journal::synchronize(Serializer &s) {
s.syncAsSint16LE(_index);
s.syncAsSint16LE(_sub);
s.syncAsSint16LE(_page);
diff --git a/engines/sherlock/journal.h b/engines/sherlock/journal.h
index d62b8338c0..a8fec104f4 100644
--- a/engines/sherlock/journal.h
+++ b/engines/sherlock/journal.h
@@ -26,20 +26,18 @@
#include "common/scummsys.h"
#include "common/array.h"
#include "common/rect.h"
-#include "common/serializer.h"
#include "common/str-array.h"
#include "common/stream.h"
+#include "sherlock/saveload.h"
namespace Sherlock {
-#define JOURNAL_MAX_WIDTH 230
+#define LINES_PER_PAGE (IS_SERRATED_SCALPEL ? 11 : 17)
+#define JOURNAL_MAX_WIDTH (IS_SERRATED_SCALPEL ? 230 : 422)
#define JOURNAL_MAX_CHARS 80
+#define JOURNAL_LEFT_X (IS_SERRATED_SCALPEL ? 53 : 156)
-enum JournalButton {
- BTN_NONE, BTN_EXIT, BTN_BACK10, BTN_UP, BTN_DOWN, BTN_AHEAD110, BTN_SEARCH,
- BTN_FIRST_PAGE, BTN_LAST_PAGE, BTN_PRINT_TEXT
-};
-
+class SherlockEngine;
struct JournalEntry {
int _converseNum;
@@ -51,26 +49,21 @@ struct JournalEntry {
_converseNum(converseNum), _statementNum(statementNum), _replyOnly(replyOnly) {}
};
-class SherlockEngine;
-
class Journal {
-private:
+protected:
SherlockEngine *_vm;
- Common::Array<JournalEntry> _journal;
Common::StringArray _directory;
Common::StringArray _locations;
+ Common::Array<JournalEntry> _journal;
Common::StringArray _lines;
- int _maxPage;
- int _index;
- int _sub;
bool _up, _down;
+ int _index;
int _page;
+ int _maxPage;
+ int _sub;
Common::String _find;
- /**
- * Load the list of location names that the journal will make reference to
- */
- void loadJournalLocations();
+ Journal(SherlockEngine *vm);
/**
* Loads the description for the current display index in the journal, and then
@@ -79,59 +72,35 @@ private:
* first time, or being reloaded
*/
void loadJournalFile(bool alreadyLoaded);
+public:
+ static Journal *init(SherlockEngine *vm);
+ virtual ~Journal() {}
/**
- * Display the arrows that can be used to scroll up and down pages
- */
- void doArrows();
-
- /**
- * Displays a page of the journal at the current index
- */
+ * Displays a page of the journal at the current index
+ */
bool drawJournal(int direction, int howFar);
/**
- * Show the search submenu and allow the player to enter a search string
+ * Synchronize the data for a savegame
*/
- int getSearchString(bool printError);
-
+ void synchronize(Serializer &s);
+public:
/**
* Draw the journal background, frame, and interface buttons
*/
- void drawJournalFrame();
+ virtual void drawFrame() = 0;
/**
- * Returns the button, if any, that is under the specified position
+ * Reset viewing position to the start of the journal
*/
- JournalButton getHighlightedButton(const Common::Point &pt);
-public:
- Journal(SherlockEngine *vm);
+ virtual void resetPosition() {}
/**
* Records statements that are said, in the order which they are said. The player
* can then read the journal to review them
*/
- void record(int converseNum, int statementNum, bool replyOnly = false);
-
- /**
- * Display the journal
- */
- void drawInterface();
-
- /**
- * Handle events whilst the journal is being displayed
- */
- bool handleEvents(int key);
-
- /**
- * Reset viewing position to the start of the journal
- */
- void resetPosition();
-
- /**
- * Synchronize the data for a savegame
- */
- void synchronize(Common::Serializer &s);
+ virtual void record(int converseNum, int statementNum, bool replyOnly = false);
};
} // End of namespace Sherlock
diff --git a/engines/sherlock/map.cpp b/engines/sherlock/map.cpp
index ffbca3fb42..fbccaf244f 100644
--- a/engines/sherlock/map.cpp
+++ b/engines/sherlock/map.cpp
@@ -20,546 +20,33 @@
*
*/
+#include "common/system.h"
#include "sherlock/map.h"
#include "sherlock/sherlock.h"
-#include "common/system.h"
+#include "sherlock/scalpel/scalpel_map.h"
+#include "sherlock/tattoo/tattoo_map.h"
namespace Sherlock {
-MapPaths::MapPaths() {
- _numLocations = 0;
-}
-
-void MapPaths::load(int numLocations, Common::SeekableReadStream &s) {
- _numLocations = numLocations;
- _paths.resize(_numLocations * _numLocations);
-
- for (int idx = 0; idx < (numLocations * numLocations); ++idx) {
- Common::Array<byte> &path = _paths[idx];
- int v;
-
- do {
- v = s.readByte();
- path.push_back(v);
- } while (v && v < 254);
- }
-}
-
-const byte *MapPaths::getPath(int srcLocation, int destLocation) {
- return &_paths[srcLocation * _numLocations + destLocation][0];
-}
-
-/*----------------------------------------------------------------*/
-
-Map::Map(SherlockEngine *vm): _vm(vm), _topLine(g_system->getWidth(), 12) {
- _active = false;
- _mapCursors = nullptr;
- _shapes = nullptr;
- _iconShapes = nullptr;
- _point = 0;
- _placesShown = false;
- _cursorIndex = -1;
- _drawMap = false;
- _overPos = Common::Point(13000, 12600);
- _charPoint = 0;
- _oldCharPoint = 0;
- _frameChangeFlag = false;
-
- // Initialise the initial walk sequence set
- _walkSequences.resize(MAX_HOLMES_SEQUENCE);
- for (int idx = 0; idx < MAX_HOLMES_SEQUENCE; ++idx) {
- _walkSequences[idx]._sequences.resize(MAX_FRAME);
- Common::fill(&_walkSequences[idx]._sequences[0], &_walkSequences[idx]._sequences[0] + MAX_FRAME, 0);
- }
-
- if (!_vm->isDemo())
- loadData();
-}
-
-void Map::loadPoints(int count, const int *xList, const int *yList, const int *transList) {
- for (int idx = 0; idx < count; ++idx, ++xList, ++yList, ++transList) {
- _points.push_back(MapEntry(*xList, *yList, *transList));
- }
-}
-
-void Map::loadSequences(int count, const byte *seq) {
- for (int idx = 0; idx < count; ++idx, seq += MAX_FRAME)
- Common::copy(seq, seq + MAX_FRAME, &_walkSequences[idx]._sequences[0]);
-}
-
-void Map::loadData() {
- // TODO: Remove this
- if (_vm->getGameID() == GType_RoseTattoo)
- return;
-
- // Load the list of location names
- Common::SeekableReadStream *txtStream = _vm->_res->load(
- _vm->getGameID() == GType_SerratedScalpel ? "chess.txt" : "map.txt");
-
- int streamSize = txtStream->size();
- while (txtStream->pos() < streamSize) {
- Common::String line;
- char c;
- while ((c = txtStream->readByte()) != '\0')
- line += c;
-
- _locationNames.push_back(line);
- }
-
- delete txtStream;
-
- // Load the path data
- Common::SeekableReadStream *pathStream = _vm->_res->load("chess.pth");
-
- // Get routes between different locations on the map
- _paths.load(31, *pathStream);
-
- // Load in the co-ordinates that the paths refer to
- _pathPoints.resize(208);
- for (uint idx = 0; idx < _pathPoints.size(); ++idx) {
- _pathPoints[idx].x = pathStream->readSint16LE();
- _pathPoints[idx].y = pathStream->readSint16LE();
- }
-
- delete pathStream;
-}
-
-int Map::show() {
- Events &events = *_vm->_events;
- People &people = *_vm->_people;
- Screen &screen = *_vm->_screen;
- Common::Point lDrawn(-1, -1);
- bool changed = false, exitFlag = false;
- _active = true;
-
- // Set font and custom cursor for the map
- int oldFont = screen.fontNumber();
- screen.setFont(0);
-
- // Initial screen clear
- screen._backBuffer1.clear();
- screen.clear();
-
- // Load the entire map
- ImageFile bigMap("bigmap.vgs");
- screen.setPalette(bigMap._palette);
-
- // Load need sprites
- setupSprites();
-
- 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));
-
- _drawMap = true;
- _charPoint = -1;
- _point = -1;
- people[AL]._position = _lDrawnPos = _overPos;
-
- // Show place icons
- showPlaces();
- saveTopLine();
- _placesShown = true;
-
- // Keep looping until either a location is picked, or the game is ended
- while (!_vm->shouldQuit() && !exitFlag) {
- events.pollEventsAndWait();
- events.setButtonState();
-
- // Keyboard handling
- if (events.kbHit()) {
- Common::KeyState keyState = events.getKey();
-
- if (keyState.keycode == Common::KEYCODE_RETURN || keyState.keycode == Common::KEYCODE_SPACE) {
- // Both space and enter simulate a mouse release
- events._pressed = false;
- events._released = true;
- events._oldButtons = 0;
- }
- }
-
- // Ignore scrolling attempts until the screen is drawn
- if (!_drawMap) {
- Common::Point pt = events.mousePos();
-
- // Check for vertical map scrolling
- if ((pt.y > (SHERLOCK_SCREEN_HEIGHT - 10) && _bigPos.y < 200) || (pt.y < 10 && _bigPos.y > 0)) {
- if (pt.y > (SHERLOCK_SCREEN_HEIGHT - 10))
- _bigPos.y += 10;
- else
- _bigPos.y -= 10;
-
- changed = true;
- }
-
- // Check for horizontal map scrolling
- if ((pt.x > (SHERLOCK_SCREEN_WIDTH - 10) && _bigPos.x < 315) || (pt.x < 10 && _bigPos.x > 0)) {
- if (pt.x > (SHERLOCK_SCREEN_WIDTH - 10))
- _bigPos.x += 15;
- else
- _bigPos.x -= 15;
-
- changed = true;
- }
- }
-
- if (changed) {
- // Map has scrolled, so redraw new map view
- changed = false;
-
- 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));
-
- showPlaces();
- _placesShown = false;
-
- saveTopLine();
- _savedPos.x = -1;
- updateMap(true);
- } else if (!_drawMap) {
- if (!_placesShown) {
- showPlaces();
- _placesShown = true;
- }
-
- if (_cursorIndex == 0) {
- Common::Point pt = events.mousePos();
- highlightIcon(Common::Point(pt.x - 4 + _bigPos.x, pt.y + _bigPos.y));
- }
- updateMap(false);
- }
-
- if ((events._released || events._rightReleased) && _point != -1) {
- if (people[AL]._walkCount == 0) {
- people._walkDest = _points[_point] + Common::Point(4, 9);
- _charPoint = _point;
-
- // Start walking to selected location
- walkTheStreets();
-
- // Show wait cursor
- _cursorIndex = 1;
- events.setCursor((*_mapCursors)[_cursorIndex]._frame);
- }
- }
-
- // Check if a scene has beeen selected and we've finished "moving" to it
- if (people[AL]._walkCount == 0) {
- if (_charPoint >= 1 && _charPoint < (int)_points.size())
- exitFlag = true;
- }
-
- if (_drawMap) {
- _drawMap = false;
-
- if (screen._fadeStyle)
- screen.randomTransition();
- else
- screen.slamArea(0, 0, SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT);
- }
-
- // Wait for a frame
- events.wait(1);
- }
-
- freeSprites();
- _overPos = people[AL]._position;
-
- // Reset font
- screen.setFont(oldFont);
-
- _active = false;
- return _charPoint;
-}
-
-void Map::setupSprites() {
- Events &events = *_vm->_events;
- People &people = *_vm->_people;
- Scene &scene = *_vm->_scene;
- _savedPos.x = -1;
-
- _mapCursors = new ImageFile("omouse.vgs");
- _cursorIndex = 0;
- events.setCursor((*_mapCursors)[_cursorIndex]._frame);
-
- _shapes = new ImageFile("mapicon.vgs");
- _iconShapes = new ImageFile("overicon.vgs");
- _iconSave.create((*_shapes)[4]._width, (*_shapes)[4]._height);
- Person &p = people[AL];
- p._description = " ";
- p._type = CHARACTER;
- p._position = Common::Point(12400, 5000);
- p._sequenceNumber = 0;
- p._images = _shapes;
- p._imageFrame = nullptr;
- p._frameNumber = 0;
- p._delta = Common::Point(0, 0);
- p._oldSize = Common::Point(0, 0);
- p._oldSize = Common::Point(0, 0);
- p._misc = 0;
- p._walkCount = 0;
- p._allow = 0;
- p._noShapeSize = Common::Point(0, 0);
- p._goto = Common::Point(28000, 15000);
- p._status = 0;
- p._walkSequences = _walkSequences;
- p.setImageFrame();
- scene._bgShapes.clear();
-}
-
-void Map::freeSprites() {
- delete _mapCursors;
- delete _shapes;
- delete _iconShapes;
- _iconSave.free();
-}
-
-void Map::showPlaces() {
- Screen &screen = *_vm->_screen;
-
- for (uint idx = 0; idx < _points.size(); ++idx) {
- const MapEntry &pt = _points[idx];
-
- if (pt.x != 0 && pt.y != 0) {
- 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],
- Common::Point(pt.x - _bigPos.x - 6, pt.y - _bigPos.y - 12));
- }
- }
- }
- }
-}
-
-void Map::saveTopLine() {
- _topLine.blitFrom(_vm->_screen->_backBuffer1, Common::Point(0, 0), Common::Rect(0, 0, SHERLOCK_SCREEN_WIDTH, 12));
-}
-
-void Map::eraseTopLine() {
- Screen &screen = *_vm->_screen;
- screen._backBuffer1.blitFrom(_topLine, Common::Point(0, 0));
- screen.slamArea(0, 0, SHERLOCK_SCREEN_WIDTH, _topLine.h());
-}
-
-void Map::showPlaceName(int idx, bool highlighted) {
- People &people = *_vm->_people;
- Screen &screen = *_vm->_screen;
-
- Common::String name = _locationNames[idx];
- int width = screen.stringWidth(name);
-
- if (!_cursorIndex) {
- saveIcon(people[AL]._imageFrame, _lDrawnPos);
-
- bool flipped = people[AL]._sequenceNumber == MAP_DOWNLEFT || people[AL]._sequenceNumber == MAP_LEFT
- || people[AL]._sequenceNumber == MAP_UPLEFT;
- screen._backBuffer1.transBlitFrom(*people[AL]._imageFrame, _lDrawnPos, flipped);
- }
-
- if (highlighted) {
- int xp = (SHERLOCK_SCREEN_WIDTH - screen.stringWidth(name)) / 2;
- screen.gPrint(Common::Point(xp + 2, 2), 0, "%s", name.c_str());
- screen.gPrint(Common::Point(xp + 1, 1), 0, "%s", name.c_str());
- screen.gPrint(Common::Point(xp, 0), 12, "%s", name.c_str());
-
- screen.slamArea(xp, 0, width + 2, 15);
- }
-}
-
-void Map::updateMap(bool flushScreen) {
- Events &events = *_vm->_events;
- People &people = *_vm->_people;
- Screen &screen = *_vm->_screen;
- Common::Point osPos = _savedPos;
- Common::Point osSize = _savedSize;
- Common::Point hPos;
-
- if (_cursorIndex >= 1) {
- if (++_cursorIndex > (1 + 8))
- _cursorIndex = 1;
-
- events.setCursor((*_mapCursors)[(_cursorIndex + 1) / 2]._frame);
- }
-
- if (!_drawMap && !flushScreen)
- restoreIcon();
+Map *Map::init(SherlockEngine *vm) {
+ if (vm->getGameID() == GType_SerratedScalpel)
+ return new Scalpel::ScalpelMap(vm);
else
- _savedPos.x = -1;
-
- people[AL].adjustSprite();
-
- _lDrawnPos.x = hPos.x = people[AL]._position.x / 100 - _bigPos.x;
- _lDrawnPos.y = hPos.y = people[AL]._position.y / 100 - people[AL].frameHeight() - _bigPos.y;
-
- // Draw the person icon
- saveIcon(people[AL]._imageFrame, hPos);
- if (people[AL]._sequenceNumber == MAP_DOWNLEFT || people[AL]._sequenceNumber == MAP_LEFT
- || people[AL]._sequenceNumber == MAP_UPLEFT)
- screen._backBuffer1.transBlitFrom(*people[AL]._imageFrame, hPos, true);
- else
- screen._backBuffer1.transBlitFrom(*people[AL]._imageFrame, hPos, false);
-
- if (flushScreen) {
- screen.slamArea(0, 0, SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT);
- } else if (!_drawMap) {
- if (hPos.x > 0 && hPos.y >= 0 && hPos.x < SHERLOCK_SCREEN_WIDTH && hPos.y < SHERLOCK_SCREEN_HEIGHT)
- screen.flushImage(people[AL]._imageFrame, Common::Point(people[AL]._position.x / 100 - _bigPos.x,
- people[AL]._position.y / 100 - people[AL].frameHeight() - _bigPos.y),
- &people[AL]._oldPosition.x, &people[AL]._oldPosition.y, &people[AL]._oldSize.x, &people[AL]._oldSize.y);
-
- if (osPos.x != -1)
- screen.slamArea(osPos.x, osPos.y, osSize.x, osSize.y);
- }
+ return new Tattoo::TattooMap(vm);
}
-void Map::walkTheStreets() {
- People &people = *_vm->_people;
- Common::Array<Common::Point> tempPath;
-
- // Get indexes into the path lists for the start and destination scenes
- int start = _points[_oldCharPoint]._translate;
- int dest = _points[_charPoint]._translate;
-
- // Get pointer to start of path
- const byte *path = _paths.getPath(start, dest);
-
- // Add in destination position
- people._walkTo.clear();
- Common::Point destPos = people._walkDest;
-
- // Check for any intermediate points between the two locations
- if (path[0] || _charPoint > 50 || _oldCharPoint > 50) {
- people[AL]._sequenceNumber = -1;
-
- if (_charPoint == 51 || _oldCharPoint == 51) {
- people.setWalking();
- } else {
- bool reversePath = false;
-
- // Check for moving the path backwards or forwards
- if (path[0] == 255) {
- reversePath = true;
- SWAP(start, dest);
- path = _paths.getPath(start, dest);
- }
-
- do {
- int idx = *path++;
- tempPath.push_back(_pathPoints[idx - 1] + Common::Point(4, 4));
- } while (*path != 254);
-
- // Load up the path to use
- people._walkTo.clear();
-
- if (reversePath) {
- for (int idx = (int)tempPath.size() - 1; idx >= 0; --idx)
- people._walkTo.push(tempPath[idx]);
- } else {
- for (int idx = 0; idx < (int)tempPath.size(); ++idx)
- people._walkTo.push(tempPath[idx]);
- }
-
- people._walkDest = people._walkTo.pop() + Common::Point(12, 6);
- people.setWalking();
- }
- } else {
- people[AL]._walkCount = 0;
- }
-
- // Store the final destination icon position
- people._walkTo.push(destPos);
-}
-
-void Map::saveIcon(ImageFrame *src, const Common::Point &pt) {
- Screen &screen = *_vm->_screen;
- Common::Point size(src->_width, src->_height);
- Common::Point pos = pt;
-
- if (pos.x < 0) {
- size.x += pos.x;
- pos.x = 0;
- }
-
- if (pos.y < 0) {
- size.y += pos.y;
- pos.y = 0;
- }
-
- if ((pos.x + size.x) > SHERLOCK_SCREEN_WIDTH)
- size.x -= (pos.x + size.x) - SHERLOCK_SCREEN_WIDTH;
-
- if ((pos.y + size.y) > SHERLOCK_SCREEN_HEIGHT)
- size.y -= (pos.y + size.y) - SHERLOCK_SCREEN_HEIGHT;
-
- if (size.x < 1 || size.y < 1 || pos.x >= SHERLOCK_SCREEN_WIDTH || pos.y >= SHERLOCK_SCREEN_HEIGHT || _drawMap) {
- // Flag as the area not needing to be saved
- _savedPos.x = -1;
- return;
- }
-
- assert(size.x <= _iconSave.w() && size.y <= _iconSave.h());
- _iconSave.blitFrom(screen._backBuffer1, Common::Point(0, 0),
- Common::Rect(pos.x, pos.y, pos.x + size.x, pos.y + size.y));
- _savedPos = pos;
- _savedSize = size;
+Map::Map(SherlockEngine *vm) : _vm(vm) {
+ _charPoint = _oldCharPoint = 0;
+ _active = _frameChangeFlag = false;
}
-void Map::restoreIcon() {
- Screen &screen = *_vm->_screen;
-
- 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));
-}
-
-void Map::highlightIcon(const Common::Point &pt) {
- int oldPoint = _point;
-
- // Iterate through the icon list
- bool done = false;
- for (int idx = 0; idx < (int)_points.size(); ++idx) {
- const MapEntry &entry = _points[idx];
-
- // Check whether the mouse is over a given icon
- if (entry.x != 0 && entry.y != 0) {
- if (Common::Rect(entry.x - 8, entry.y - 8, entry.x + 9, entry.y + 9).contains(pt)) {
- done = true;
-
- if (_point != idx && _vm->readFlags(idx)) {
- // Changed to a new valid (visible) location
- eraseTopLine();
- showPlaceName(idx, true);
- _point = idx;
- }
- }
- }
- }
-
- if (!done) {
- // No icon was highlighted
- if (_point != -1) {
- // No longer highlighting previously highlighted icon, so erase it
- showPlaceName(_point, false);
- eraseTopLine();
- }
-
- _point = -1;
- } else if (oldPoint != -1 && oldPoint != _point) {
- showPlaceName(oldPoint, false);
- eraseTopLine();
- }
-}
-
-void Map::synchronize(Common::Serializer &s) {
- s.syncAsSint16LE(_bigPos.x);
- s.syncAsSint16LE(_bigPos.y);
- s.syncAsSint16LE(_overPos.x);
+void Map::synchronize(Serializer &s) {
+ s.syncAsSint32LE(_bigPos.x);
+ s.syncAsSint32LE(_bigPos.y);
+ s.syncAsSint32LE(_overPos.x);
s.syncAsSint16LE(_overPos.y);
s.syncAsSint16LE(_oldCharPoint);
}
+
} // End of namespace Sherlock
diff --git a/engines/sherlock/map.h b/engines/sherlock/map.h
index e0c7d038c4..104f5e9c8a 100644
--- a/engines/sherlock/map.h
+++ b/engines/sherlock/map.h
@@ -23,156 +23,37 @@
#ifndef SHERLOCK_MAP_H
#define SHERLOCK_MAP_H
-#include "common/scummsys.h"
-#include "common/array.h"
-#include "common/rect.h"
-#include "common/serializer.h"
-#include "common/str.h"
-#include "common/str-array.h"
-#include "sherlock/surface.h"
#include "sherlock/objects.h"
+#include "sherlock/saveload.h"
namespace Sherlock {
class SherlockEngine;
-struct MapEntry : Common::Point {
- int _translate;
-
- MapEntry() : Common::Point(), _translate(-1) {}
-
- MapEntry(int posX, int posY, int translate) : Common::Point(posX, posY), _translate(translate) {}
-};
-
-class MapPaths {
-private:
- int _numLocations;
- Common::Array< Common::Array<byte> > _paths;
-
-public:
- MapPaths();
-
- /**
- * Load the data for the paths between locations on the map
- */
- void load(int numLocations, Common::SeekableReadStream &s);
-
- /**
- * Get the path between two locations on the map
- */
- const byte *getPath(int srcLocation, int destLocation);
-};
-
class Map {
-private:
+protected:
SherlockEngine *_vm;
- Common::Array<MapEntry> _points; // Map locations for each scene
- Common::StringArray _locationNames;
- MapPaths _paths;
- Common::Array<Common::Point> _pathPoints;
- Common::Point _savedPos;
- Common::Point _savedSize;
- Surface _topLine;
- ImageFile *_mapCursors;
- ImageFile *_shapes;
- ImageFile *_iconShapes;
- WalkSequences _walkSequences;
- Point32 _lDrawnPos;
- int _point;
- bool _placesShown;
- int _cursorIndex;
- bool _drawMap;
- Surface _iconSave;
-private:
- /**
- * Load data needed for the map
- */
- void loadData();
-
- /**
- * Load and initialize all the sprites that are needed for the map display
- */
- void setupSprites();
- /**
- * Free the sprites and data used by the map
- */
- void freeSprites();
-
- /**
- * Draws an icon for every place that's currently known
- */
- void showPlaces();
-
- /**
- * Makes a copy of the top rows of the screen that are used to display location names
- */
- void saveTopLine();
-
- /**
- * Erases anything shown in the top line by restoring the previously saved original map background
- */
- void eraseTopLine();
-
- /**
- * Prints the name of the specified icon
- */
- void showPlaceName(int idx, bool highlighted);
-
- /**
- * Update all on-screen sprites to account for any scrolling of the map
- */
- void updateMap(bool flushScreen);
-
- /**
- * Handle moving icon for player from their previous location on the map to a destination location
- */
- void walkTheStreets();
-
- /**
- * Save the area under the player's icon
- */
- void saveIcon(ImageFrame *src, const Common::Point &pt);
-
- /**
- * Restore the area under the player's icon
- */
- void restoreIcon();
-
- /**
- * Handles highlighting map icons, showing their names
- */
- void highlightIcon(const Common::Point &pt);
+ Map(SherlockEngine *vm);
public:
- bool _active;
Point32 _overPos;
Point32 _bigPos;
int _charPoint, _oldCharPoint;
+ bool _active;
bool _frameChangeFlag;
public:
- Map(SherlockEngine *vm);
-
- const MapEntry &operator[](int idx) { return _points[idx]; }
-
- /**
- * Loads the list of points for locations on the map for each scene
- */
- void loadPoints(int count, const int *xList, const int *yList, const int *transList);
-
- /**
- * Load the sequence data for player icon animations
- */
- void loadSequences(int count, const byte *seq);
+ static Map *init(SherlockEngine *vm);
+ virtual ~Map() {}
/**
* Show the map
*/
- int show();
+ virtual int show() = 0;
/**
* Synchronize the data for a savegame
*/
- void synchronize(Common::Serializer &s);
+ void synchronize(Serializer &s);
};
} // End of namespace Sherlock
diff --git a/engines/sherlock/module.mk b/engines/sherlock/module.mk
index 1a38d56511..7fa7896691 100644
--- a/engines/sherlock/module.mk
+++ b/engines/sherlock/module.mk
@@ -1,21 +1,57 @@
MODULE := engines/sherlock
MODULE_OBJS = \
- scalpel/darts.o \
scalpel/scalpel.o \
+ scalpel/3do/movie_decoder.o \
scalpel/drivers/adlib.o \
+ scalpel/drivers/mt32.o \
scalpel/tsage/logo.o \
scalpel/tsage/resources.o \
+ scalpel/scalpel_darts.o \
+ scalpel/scalpel_debugger.o \
+ scalpel/scalpel_fixed_text.o \
+ scalpel/scalpel_inventory.o \
+ scalpel/scalpel_journal.o \
+ scalpel/scalpel_map.o \
+ scalpel/scalpel_people.o \
+ scalpel/scalpel_saveload.o \
scalpel/scalpel_scene.o \
+ scalpel/scalpel_screen.o \
+ scalpel/scalpel_talk.o \
scalpel/scalpel_user_interface.o \
scalpel/settings.o \
tattoo/tattoo.o \
+ tattoo/tattoo_darts.o \
+ tattoo/tattoo_debugger.o \
+ tattoo/tattoo_fixed_text.o \
+ tattoo/tattoo_inventory.o \
+ tattoo/tattoo_journal.o \
+ tattoo/tattoo_map.o \
+ tattoo/tattoo_people.o \
+ tattoo/tattoo_resources.o \
tattoo/tattoo_scene.o \
+ tattoo/tattoo_talk.o \
tattoo/tattoo_user_interface.o \
+ tattoo/widget_base.o \
+ tattoo/widget_credits.o \
+ tattoo/widget_files.o \
+ tattoo/widget_foolscap.o \
+ tattoo/widget_inventory.o \
+ tattoo/widget_lab.o \
+ tattoo/widget_options.o \
+ tattoo/widget_password.o \
+ tattoo/widget_quit.o \
+ tattoo/widget_talk.o \
+ tattoo/widget_text.o \
+ tattoo/widget_tooltip.o \
+ tattoo/widget_verbs.o \
animation.o \
debugger.o \
detection.o \
events.o \
+ fixed_text.o \
+ fonts.o \
+ image_file.o \
inventory.o \
journal.o \
map.o \
diff --git a/engines/sherlock/music.cpp b/engines/sherlock/music.cpp
index 0735f41d9a..7802bf5eeb 100644
--- a/engines/sherlock/music.cpp
+++ b/engines/sherlock/music.cpp
@@ -20,10 +20,16 @@
*
*/
+#include "common/algorithm.h"
#include "common/config-manager.h"
+#include "common/mutex.h"
#include "sherlock/sherlock.h"
#include "sherlock/music.h"
#include "sherlock/scalpel/drivers/mididriver.h"
+// for Miles Audio (Sherlock Holmes 2)
+#include "audio/miles.h"
+// for 3DO digital music
+#include "audio/decoders/aiff.h"
namespace Sherlock {
@@ -57,32 +63,21 @@ MidiParser_SH::MidiParser_SH() {
_beats = 0;
_lastEvent = 0;
_trackEnd = nullptr;
+
+ _musData = nullptr;
+ _musDataSize = 0;
+}
+
+MidiParser_SH::~MidiParser_SH() {
+ Common::StackLock lock(_mutex);
+ unloadMusic();
+ _driver = NULL;
}
void MidiParser_SH::parseNextEvent(EventInfo &info) {
-// warning("parseNextEvent");
+ Common::StackLock lock(_mutex);
- // An attempt to remap MT32 instruments to GMIDI. Only partially successful, it still
- // does not sound even close to the real MT32. Oddly enough, on the actual hardware MT32
- // and SB sound very differently.
- static const byte mt32Map[128] = {
- 0, 1, 0, 2, 4, 4, 5, 3, /* 0-7 */
- 16, 17, 18, 16, 16, 19, 20, 21, /* 8-15 */
- 6, 6, 6, 7, 7, 7, 8, 112, /* 16-23 */
- 62, 62, 63, 63 , 38, 38, 39, 39, /* 24-31 */
- 88, 95, 52, 98, 97, 99, 14, 54, /* 32-39 */
- 102, 96, 53, 102, 81, 100, 14, 80, /* 40-47 */
- 48, 48, 49, 45, 41, 40, 42, 42, /* 48-55 */
- 43, 46, 45, 24, 25, 28, 27, 104, /* 56-63 */
- 32, 32, 34, 33, 36, 37, 35, 35, /* 64-71 */
- 79, 73, 72, 72, 74, 75, 64, 65, /* 72-79 */
- 66, 67, 71, 71, 68, 69, 70, 22, /* 80-87 */
- 56, 59, 57, 57, 60, 60, 58, 61, /* 88-95 */
- 61, 11, 11, 98, 14, 9, 14, 13, /* 96-103 */
- 12, 107, 107, 77, 78, 78, 76, 76, /* 104-111 */
- 47, 117, 127, 118, 118, 116, 115, 119, /* 112-119 */
- 115, 112, 55, 124, 123, 0, 14, 117 /* 120-127 */
- };
+// warning("parseNextEvent");
// there is no delta right at the start of the music data
// this order is essential, otherwise notes will get delayed or even go missing
@@ -102,8 +97,6 @@ void MidiParser_SH::parseNextEvent(EventInfo &info) {
case 0xC: { // program change
int idx = *_position._playPos++;
info.basic.param1 = idx & 0x7f;
- // don't do this here, it breaks adlib
- //info.basic.param1 = mt32Map[idx & 0x7f]; // remap MT32 to GM
info.basic.param2 = 0;
}
break;
@@ -151,16 +144,16 @@ void MidiParser_SH::parseNextEvent(EventInfo &info) {
}
} else if (info.event == 0xFC) {
// Official End-Of-Track signal
- warning("System META event 0xFC");
+ debugC(kDebugLevelMusic, "Music: System META event 0xFC");
byte type = *(_position._playPos++);
switch (type) {
case 0x80: // end of track, triggers looping
- warning("META event triggered looping");
+ debugC(kDebugLevelMusic, "Music: META event triggered looping");
jumpToTick(0, true, true, false);
break;
case 0x81: // end of track, stop playing
- warning("META event triggered music stop");
+ debugC(kDebugLevelMusic, "Music: META event triggered music stop");
stopPlaying();
unloadMusic();
break;
@@ -179,20 +172,26 @@ void MidiParser_SH::parseNextEvent(EventInfo &info) {
}// switch (info.command())
}
-bool MidiParser_SH::loadMusic(byte *data, uint32 size) {
- warning("loadMusic");
+bool MidiParser_SH::loadMusic(byte *musData, uint32 musDataSize) {
+ Common::StackLock lock(_mutex);
+
+ debugC(kDebugLevelMusic, "Music: loadMusic()");
unloadMusic();
- byte *headerPtr = data;
- byte *pos = data;
+ _musData = musData;
+ _musDataSize = musDataSize;
+
+ byte *headerPtr = _musData + 12; // skip over the already checked SPACE header
+ byte *pos = headerPtr;
+
uint16 headerSize = READ_LE_UINT16(headerPtr);
- assert(headerSize == 0x7F);
+ assert(headerSize == 0x7F); // Security check
// Skip over header
pos += headerSize;
_lastEvent = 0;
- _trackEnd = data + size;
+ _trackEnd = _musData + _musDataSize;
_numTracks = 1;
_tracks[0] = pos;
@@ -204,45 +203,152 @@ bool MidiParser_SH::loadMusic(byte *data, uint32 size) {
return true;
}
+void MidiParser_SH::unloadMusic() {
+ Common::StackLock lock(_mutex);
+
+ if (_musData) {
+ delete[] _musData;
+ _musData = NULL;
+ _musDataSize = 0;
+ }
+
+ MidiParser::unloadMusic();
+}
+
/*----------------------------------------------------------------*/
Music::Music(SherlockEngine *vm, Audio::Mixer *mixer) : _vm(vm), _mixer(mixer) {
+ _midiDriver = NULL;
+ _midiParser = NULL;
+ _musicType = MT_NULL;
+ _musicPlaying = false;
+ _musicOn = false;
+ _midiOption = false;
+ _musicVolume = 0;
+
+ if (IS_3DO) {
+ // 3DO - uses digital samples for music
+ _musicOn = true;
+ return;
+ }
+
if (_vm->_interactiveFl)
_vm->_res->addToCache("MUSIC.LIB");
- MidiDriver::DeviceHandle dev = MidiDriver::detectDevice(MDT_MIDI | MDT_ADLIB | MDT_PREFER_GM);
+ MidiDriver::DeviceHandle dev;
- _musicType = MidiDriver::getMusicType(dev);
+ if (IS_SERRATED_SCALPEL) {
+ // Serrated Scalpel: used an internal Electronic Arts .MUS music engine
+ _midiParser = new MidiParser_SH();
+ dev = MidiDriver::detectDevice(MDT_MIDI | MDT_ADLIB | MDT_PREFER_MT32);
+ _musicType = MidiDriver::getMusicType(dev);
- _driver = NULL;
-
- switch (_musicType) {
- case MT_ADLIB:
- _driver = MidiDriver_AdLib_create();
- break;
- default:
- _driver = MidiDriver::createMidi(dev);
- break;
+ switch (_musicType) {
+ case MT_ADLIB:
+ _midiDriver = MidiDriver_SH_AdLib_create();
+ break;
+ case MT_MT32:
+ _midiDriver = MidiDriver_MT32_create();
+ break;
+ case MT_GM:
+ if (ConfMan.getBool("native_mt32")) {
+ _midiDriver = MidiDriver_MT32_create();
+ _musicType = MT_MT32;
+ }
+ break;
+ default:
+ // Create default one
+ // I guess we shouldn't do this anymore
+ //_midiDriver = MidiDriver::createMidi(dev);
+ break;
+ }
+ } else {
+ // Rose Tattooo: seems to use Miles Audio 3
+ _midiParser = MidiParser::createParser_XMIDI();
+ dev = MidiDriver::detectDevice(MDT_MIDI | MDT_ADLIB | MDT_PREFER_GM);
+ _musicType = MidiDriver::getMusicType(dev);
+
+ switch (_musicType) {
+ case MT_ADLIB:
+ // SAMPLE.AD -> regular AdLib instrument data
+ // SAMPLE.OPL -> OPL-3 instrument data
+ // although in case of Rose Tattoo both files are exactly the same
+ _midiDriver = Audio::MidiDriver_Miles_AdLib_create("SAMPLE.AD", "SAMPLE.OPL");
+ break;
+ case MT_MT32:
+ // Sherlock Holmes 2 does not have a MT32 timbre file
+ _midiDriver = Audio::MidiDriver_Miles_MT32_create("");
+ break;
+ case MT_GM:
+ if (ConfMan.getBool("native_mt32")) {
+ _midiDriver = Audio::MidiDriver_Miles_MT32_create("");
+ _musicType = MT_MT32;
+ } else {
+ _midiDriver = MidiDriver::createMidi(dev);
+ _musicType = MT_GM;
+ }
+ break;
+ default:
+ // Do not create anything
+ break;
+ }
}
- if (_driver) {
- assert(_driver);
-
- int ret = _driver->open();
+ if (_midiDriver) {
+ int ret = _midiDriver->open();
if (ret == 0) {
- _driver->sendGMReset();
- _driver->setTimerCallback(&_midiParser, &_midiParser.timerCallback);
+ // Reset is done inside our MIDI driver
+ _midiDriver->setTimerCallback(_midiParser, &_midiParser->timerCallback);
+ }
+ _midiParser->setMidiDriver(_midiDriver);
+ _midiParser->setTimerRate(_midiDriver->getBaseTempo());
+
+ if (IS_SERRATED_SCALPEL) {
+ if (_musicType == MT_MT32) {
+ // Upload patches
+ Common::SeekableReadStream *MT32driverStream = _vm->_res->load("MTHOM.DRV", "MUSIC.LIB");
+
+ if (!MT32driverStream)
+ error("Music: could not load MTHOM.DRV, critical");
+
+ byte *MT32driverData = new byte[MT32driverStream->size()];
+ int32 MT32driverDataSize = MT32driverStream->size();
+ assert(MT32driverData);
+
+ MT32driverStream->read(MT32driverData, MT32driverDataSize);
+ delete MT32driverStream;
+
+ assert(MT32driverDataSize > 12);
+ byte *MT32driverDataPtr = MT32driverData + 12;
+ MT32driverDataSize -= 12;
+
+ MidiDriver_MT32_uploadPatches(_midiDriver, MT32driverDataPtr, MT32driverDataSize);
+ delete[] MT32driverData;
+ }
}
- _midiParser.setMidiDriver(_driver);
- _midiParser.setTimerRate(_driver->getBaseTempo());
+
+ _musicOn = true;
}
+}
- _musicPlaying = false;
- _musicOn = true;
+Music::~Music() {
+ stopMusic();
+ if (_midiDriver) {
+ _midiDriver->setTimerCallback(this, NULL);
+ }
+ if (_midiParser) {
+ _midiParser->stopPlaying();
+ delete _midiParser;
+ _midiParser = nullptr;
+ }
+ if (_midiDriver) {
+ _midiDriver->close();
+ delete _midiDriver;
+ }
}
bool Music::loadSong(int songNumber) {
- warning("loadSong");
+ debugC(kDebugLevelMusic, "Music: loadSong()");
if(songNumber == 100)
songNumber = 55;
@@ -260,21 +366,27 @@ bool Music::loadSong(int songNumber) {
if((songNumber > NUM_SONGS) || (songNumber < 1))
return false;
- Common::String songName = Common::String(SONG_NAMES[songNumber - 1]) + ".MUS";
+ Common::String songName = Common::String(SONG_NAMES[songNumber - 1]);
freeSong(); // free any song that is currently loaded
-
+ stopMusic();
+
if (!playMusic(songName))
return false;
- stopMusic();
startSong();
return true;
}
bool Music::loadSong(const Common::String &songName) {
- warning("TODO: Music::loadSong");
- return false;
+ freeSong(); // free any song that is currently loaded
+ stopMusic();
+
+ if (!playMusic(songName))
+ return false;
+
+ startSong();
+ return true;
}
void Music::syncMusicSettings() {
@@ -285,76 +397,220 @@ bool Music::playMusic(const Common::String &name) {
if (!_musicOn)
return false;
- warning("Sound::playMusic %s", name.c_str());
- Common::SeekableReadStream *stream = _vm->_res->load(name, "MUSIC.LIB");
+ debugC(kDebugLevelMusic, "Music: playMusic('%s')", name.c_str());
- byte *data = new byte[stream->size()];
- int32 dataSize = stream->size();
- assert(data);
+ if (!IS_3DO) {
+ // MIDI based
+ if (!_midiDriver)
+ return false;
- stream->read(data, dataSize);
- delete stream;
+ Common::String midiMusicName = (IS_SERRATED_SCALPEL) ? name + ".MUS" : name + ".XMI";
+ Common::SeekableReadStream *stream = _vm->_res->load(midiMusicName, "MUSIC.LIB");
- // for dumping the music tracks
-#if 0
- Common::DumpFile outFile;
- outFile.open(name + ".RAW");
- outFile.write(data, stream->size());
- outFile.flush();
- outFile.close();
-#endif
+ byte *midiMusicData = new byte[stream->size()];
+ int32 midiMusicDataSize = stream->size();
- if (dataSize < 14) {
- warning("not enough data in music file");
- return false;
- }
+ stream->read(midiMusicData, midiMusicDataSize);
+ delete stream;
- byte *dataPos = data;
- if (memcmp(" ", dataPos, 12)) {
- warning("Expected header not found in music file");
- return false;
- }
- dataPos += 12;
- dataSize -= 12;
+ if (midiMusicDataSize < 14) {
+ warning("Music: not enough data in music file");
+ delete[] midiMusicData;
+ return false;
+ }
- uint16 headerSize = READ_LE_UINT16(dataPos);
- if (headerSize != 0x7F) {
- warning("music header is not as expected");
- return false;
- }
+ byte *dataPos = midiMusicData;
+ uint32 dataSize = midiMusicDataSize;
+
+ if (IS_SERRATED_SCALPEL) {
+ if (memcmp(" ", dataPos, 12)) {
+ warning("Music: expected header not found in music file");
+ delete[] midiMusicData;
+ return false;
+ }
+ dataPos += 12;
+ dataSize -= 12;
+
+ if (dataSize < 0x7F) {
+ warning("Music: expected music header not found in music file");
+ delete[] midiMusicData;
+ return false;
+ }
+
+ uint16 headerSize = READ_LE_UINT16(dataPos);
+ if (headerSize != 0x7F) {
+ warning("Music: header is not as expected");
+ delete[] midiMusicData;
+ return false;
+ }
+ } else {
+ if (memcmp("FORM", dataPos, 4)) {
+ warning("Music: expected header not found in music file");
+ delete[] midiMusicData;
+ return false;
+ }
+ }
+
+ if (IS_SERRATED_SCALPEL) {
+ // Pass the music data to the driver as well
+ // because channel mapping and a few other things inside the header
+ switch (_musicType) {
+ case MT_ADLIB:
+ MidiDriver_SH_AdLib_newMusicData(_midiDriver, dataPos, dataSize);
+ break;
- if (_musicType == MT_ADLIB) {
- if (_driver)
- MidiDriver_AdLib_newMusicData(_driver, dataPos, dataSize);
+ case MT_MT32:
+ MidiDriver_MT32_newMusicData(_midiDriver, dataPos, dataSize);
+ break;
+
+ default:
+ // should never happen
+ break;
+ }
+ }
+
+ _midiParser->loadMusic(midiMusicData, midiMusicDataSize);
+
+ } else {
+ // 3DO: sample based
+ Audio::AudioStream *musicStream;
+ Common::String digitalMusicName = "music/" + name + "_MW22.aifc";
+
+ if (isPlaying()) {
+ _mixer->stopHandle(_digitalMusicHandle);
+ }
+
+ Common::File *digitalMusicFile = new Common::File();
+ if (!digitalMusicFile->open(digitalMusicName)) {
+ warning("playMusic: can not open 3DO music '%s'", digitalMusicName.c_str());
+ return false;
+ }
+
+ // Try to load the given file as AIFF/AIFC
+ musicStream = Audio::makeAIFFStream(digitalMusicFile, DisposeAfterUse::YES);
+ if (!musicStream) {
+ warning("playMusic: can not load 3DO music '%s'", digitalMusicName.c_str());
+ return false;
+ }
+ _mixer->playStream(Audio::Mixer::kMusicSoundType, &_digitalMusicHandle, musicStream);
}
- _midiParser.loadMusic(dataPos, dataSize);
+ _musicPlaying = true;
return true;
}
void Music::stopMusic() {
- // TODO
- warning("TODO: Sound::stopMusic");
+ freeSong();
+}
+
+void Music::startSong() {
+ // No implementation needed for ScummVM
+}
+
+void Music::freeSong() {
+ if (!IS_3DO) {
+ if (_midiParser->isPlaying())
+ _midiParser->stopPlaying();
+
+ // Free the MIDI MUS data buffer
+ _midiParser->unloadMusic();
+ }
_musicPlaying = false;
}
-void Music::startSong() {
- if (!_musicOn)
- return;
+bool Music::isPlaying() {
+ if (!IS_3DO) {
+ // MIDI based
+ return _midiParser->isPlaying();
+ } else {
+ // 3DO: sample based
+ return _mixer->isSoundHandleActive(_digitalMusicHandle);
+ }
+}
- // TODO
- warning("TODO: Sound::startSong");
- _musicPlaying = true;
+// Returns the current music position in milliseconds
+uint32 Music::getCurrentPosition() {
+ if (!IS_3DO) {
+ // MIDI based
+ return (_midiParser->getTick() * 1000) / 60; // translate tick to millisecond
+ } else {
+ // 3DO: sample based
+ return _mixer->getSoundElapsedTime(_digitalMusicHandle);
+ }
}
-void Music::freeSong() {
- // TODO
- warning("TODO: Sound::freeSong");
+// This is used to wait for the music in certain situations like especially the intro
+// Note: the original game didn't do this, instead it just waited for certain amounts of time
+// We do this, so that the intro graphics + music work together even on faster/slower hardware.
+bool Music::waitUntilMSec(uint32 msecTarget, uint32 msecMax, uint32 additionalDelay, uint32 noMusicDelay) {
+ uint32 msecCurrent = 0;
+
+ if (!isPlaying()) {
+ return _vm->_events->delay(noMusicDelay, true);
+ }
+ while (1) {
+ if (!isPlaying()) { // Music is not playing anymore -> we are done
+ if (additionalDelay > 0) {
+ if (!_vm->_events->delay(additionalDelay, true))
+ return false;
+ }
+ return true;
+ }
+
+ msecCurrent = getCurrentPosition();
+ //warning("waitUntilMSec: %lx", msecCurrent);
+
+ if ((!msecMax) || (msecCurrent <= msecMax)) {
+ if (msecCurrent >= msecTarget) {
+ if (additionalDelay > 0) {
+ if (!_vm->_events->delay(additionalDelay, true))
+ return false;
+ }
+ return true;
+ }
+ }
+ if (!_vm->_events->delay(10, true))
+ return false;
+ }
}
-void Music::waitTimerRoland(uint time) {
- // TODO
- warning("TODO: Sound::waitTimerRoland");
-}} // End of namespace Sherlock
+void Music::setMusicVolume(int volume) {
+ _musicVolume = volume;
+ _vm->_mixer->setVolumeForSoundType(Audio::Mixer::kMusicSoundType, volume);
+}
+
+void Music::getSongNames(Common::StringArray &songs) {
+ songs.clear();
+ if (IS_SERRATED_SCALPEL) {
+ if (IS_3DO) {
+ Common::FSDirectory gameDirectory(ConfMan.get("path"));
+ Common::FSDirectory *musicDirectory = gameDirectory.getSubDirectory("music");
+ Common::ArchiveMemberList files;
+
+ musicDirectory->listMatchingMembers(files, "*_mw22.aifc");
+
+ for (Common::ArchiveMemberList::iterator i = files.begin(); i != files.end(); ++i) {
+ Common::String name = (*i)->getName();
+ name.erase(name.size() - 10);
+ songs.push_back(name);
+ }
+ } else {
+ for (int i = 0; i < ARRAYSIZE(SONG_NAMES); i++) {
+ songs.push_back(SONG_NAMES[i]);
+ }
+ }
+ } else {
+ Common::StringArray fileList;
+ _vm->_res->getResourceNames("music.lib", fileList);
+ for (Common::StringArray::iterator i = fileList.begin(); i != fileList.end(); ++i) {
+ if ((*i).matchString("*.XMI", true)) {
+ (*i).erase((*i).size() - 4);
+ songs.push_back(*i);
+ }
+ }
+ }
+ Common::sort(songs.begin(), songs.end());
+}
+} // End of namespace Sherlock
diff --git a/engines/sherlock/music.h b/engines/sherlock/music.h
index 0ebc3e94e2..afd3a429be 100644
--- a/engines/sherlock/music.h
+++ b/engines/sherlock/music.h
@@ -27,40 +27,61 @@
#include "audio/midiparser.h"
//#include "audio/mididrv.h"
#include "sherlock/scalpel/drivers/mididriver.h"
+// for 3DO digital music
+#include "audio/audiostream.h"
+#include "audio/mixer.h"
+#include "common/mutex.h"
+#include "common/str-array.h"
namespace Sherlock {
class SherlockEngine;
class MidiParser_SH : public MidiParser {
+public:
+ MidiParser_SH();
+ ~MidiParser_SH();
+
protected:
- virtual void parseNextEvent(EventInfo &info);
+ Common::Mutex _mutex;
+ void parseNextEvent(EventInfo &info);
uint8 _beats;
uint8 _lastEvent;
byte *_data;
byte *_trackEnd;
+
public:
- MidiParser_SH();
- virtual bool loadMusic(byte *data, uint32 size);
+ bool loadMusic(byte *musData, uint32 musSize);
+ virtual void unloadMusic();
+
+private:
+ byte *_musData;
+ uint32 _musDataSize;
};
class Music {
private:
SherlockEngine *_vm;
Audio::Mixer *_mixer;
- MidiParser_SH _midiParser;
- MidiDriver *_driver;
-
+ MidiParser *_midiParser;
+ MidiDriver *_midiDriver;
+ Audio::SoundHandle _digitalMusicHandle;
+ MusicType _musicType;
+
+ /**
+ * Play the specified music resource
+ */
+ bool playMusic(const Common::String &name);
public:
bool _musicPlaying;
bool _musicOn;
-
-private:
- MusicType _musicType;
-
+ int _musicVolume;
+ bool _midiOption;
+ Common::String _currentSongName, _nextSongName;
public:
Music(SherlockEngine *vm, Audio::Mixer *mixer);
+ ~Music();
/**
* Saves sound-related settings
@@ -86,21 +107,28 @@ public:
* Free any currently loaded song
*/
void freeSong();
-
- /**
- * Play the specified music resource
- */
- bool playMusic(const Common::String &name);
/**
* Stop playing the music
*/
void stopMusic();
- void waitTimerRoland(uint time);
+ bool isPlaying();
+ uint32 getCurrentPosition();
+
+ bool waitUntilMSec(uint32 msecTarget, uint32 maxMSec, uint32 additionalDelay, uint32 noMusicDelay);
+
+ /**
+ * Sets the volume of the MIDI music with a value ranging from 0 to 127
+ */
+ void setMusicVolume(int volume);
+
+ /**
+ * Gets the names of all the songs in the game. Used by the debugger.
+ */
+ void getSongNames(Common::StringArray &songs);
};
} // End of namespace Sherlock
#endif
-
diff --git a/engines/sherlock/objects.cpp b/engines/sherlock/objects.cpp
index 8818f805a5..093f666a46 100644
--- a/engines/sherlock/objects.cpp
+++ b/engines/sherlock/objects.cpp
@@ -20,608 +20,135 @@
*
*/
+#include "common/util.h"
#include "sherlock/objects.h"
-#include "sherlock/sherlock.h"
#include "sherlock/people.h"
#include "sherlock/scene.h"
-#include "common/util.h"
+#include "sherlock/scalpel/scalpel.h"
+#include "sherlock/scalpel/scalpel_map.h"
+#include "sherlock/scalpel/scalpel_people.h"
+#include "sherlock/tattoo/tattoo.h"
namespace Sherlock {
#define START_FRAME 0
-#define UPPER_LIMIT 0
-#define LOWER_LIMIT CONTROLS_Y
-#define LEFT_LIMIT 0
-#define RIGHT_LIMIT SHERLOCK_SCREEN_WIDTH
+#define NUM_ADJUSTED_WALKS 21
// Distance to walk around WALK_AROUND boxes
#define CLEAR_DIST_X 5
#define CLEAR_DIST_Y 0
-SherlockEngine *Sprite::_vm;
-
-void Sprite::clear() {
- _name = "";
- _description = "";
- _examine.clear();
- _pickUp = "";
- _walkSequences.clear();
- _images = nullptr;
- _imageFrame = nullptr;
- _walkCount = 0;
- _allow = 0;
- _frameNumber = _sequenceNumber = 0;
- _position.x = _position.y = 0;
- _delta.x = _delta.y = 0;
- _oldPosition.x = _oldPosition.y = 0;
- _oldSize.x = _oldSize.y = 0;
- _goto.x = _goto.y = 0;
- _type = INVALID;
- _pickUp.clear();
- _noShapeSize.x = _noShapeSize.y = 0;
- _status = 0;
- _misc = 0;
- _numFrames = 0;
- _altImages = nullptr;
- _altSequences = false;
- Common::fill(&_stopFrames[0], &_stopFrames[8], (ImageFrame *)nullptr);
-}
-
-void Sprite::setImageFrame() {
- int frameNum = MAX(_frameNumber, 0);
- int imageNumber = _walkSequences[_sequenceNumber][frameNum];
-
- if (IS_SERRATED_SCALPEL)
- imageNumber = imageNumber + _walkSequences[_sequenceNumber][0] - 2;
- else if (imageNumber > _numFrames)
- imageNumber = 1;
-
- // Get the images to use
- ImageFile *images = _altSequences ? _altImages : _images;
- assert(images);
-
- // Set the frame pointer
- _imageFrame = &(*images)[imageNumber];
-}
-
-void Sprite::adjustSprite() {
- Map &map = *_vm->_map;
- People &people = *_vm->_people;
- Scene &scene = *_vm->_scene;
- Talk &talk = *_vm->_talk;
-
- if (_type == INVALID || (_type == CHARACTER && scene._animating))
- return;
-
- if (!talk._talkCounter && _type == CHARACTER && _walkCount) {
- // Handle active movement for the sprite
- _position += _delta;
- --_walkCount;
-
- if (!_walkCount) {
- // If there any points left for the character to walk to along the
- // route to a destination, then move to the next point
- if (!people._walkTo.empty()) {
- people._walkDest = people._walkTo.pop();
- people.setWalking();
- } else {
- people.gotoStand(*this);
- }
- }
- }
-
- if (_type == CHARACTER && !map._active) {
- if ((_position.y / 100) > LOWER_LIMIT) {
- _position.y = LOWER_LIMIT * 100;
- people.gotoStand(*this);
- }
-
- if ((_position.y / 100) < UPPER_LIMIT) {
- _position.y = UPPER_LIMIT * 100;
- people.gotoStand(*this);
- }
-
- if ((_position.x / 100) < LEFT_LIMIT) {
- _position.x = LEFT_LIMIT * 100;
- people.gotoStand(*this);
- }
- } else if (!map._active) {
- _position.y = CLIP((int)_position.y, (int)UPPER_LIMIT, (int)LOWER_LIMIT);
- _position.x = CLIP((int)_position.x, (int)LEFT_LIMIT, (int)RIGHT_LIMIT);
- }
-
- if (!map._active || (map._frameChangeFlag = !map._frameChangeFlag))
- ++_frameNumber;
-
- if (_walkSequences[_sequenceNumber][_frameNumber] == 0) {
- switch (_sequenceNumber) {
- case STOP_UP:
- case STOP_DOWN:
- case STOP_LEFT:
- case STOP_RIGHT:
- case STOP_UPRIGHT:
- case STOP_UPLEFT:
- case STOP_DOWNRIGHT:
- case STOP_DOWNLEFT:
- // We're in a stop sequence, so reset back to the last frame, so
- // the character is shown as standing still
- --_frameNumber;
- break;
-
- default:
- // Move 1 past the first frame - we need to compensate, since we
- // already passed the frame increment
- _frameNumber = 1;
- break;
- }
- }
-
- // Update the _imageFrame to point to the new frame's image
- setImageFrame();
+#define ADJUST_COORD(COORD) \
+ if (COORD.x != -1) \
+ COORD.x *= FIXED_INT_MULTIPLIER; \
+ if (COORD.y != -1) \
+ COORD.y *= FIXED_INT_MULTIPLIER
- // Check to see if character has entered an exit zone
- if (!_walkCount && scene._walkedInScene && scene._goToScene == -1) {
- Common::Rect charRect(_position.x / 100 - 5, _position.y / 100 - 2,
- _position.x / 100 + 5, _position.y / 100 + 2);
- Exit *exit = scene.checkForExit(charRect);
-
- if (exit) {
- scene._goToScene = exit->_scene;
-
- if (exit->_people.x != 0) {
- people._hSavedPos = exit->_people;
- people._hSavedFacing = exit->_peopleDir;
-
- if (people._hSavedFacing > 100 && people._hSavedPos.x < 1)
- people._hSavedPos.x = 100;
- }
- }
- }
-}
-
-void Sprite::checkSprite() {
- Events &events = *_vm->_events;
- People &people = *_vm->_people;
- Scene &scene = *_vm->_scene;
- Screen &screen = *_vm->_screen;
- Talk &talk = *_vm->_talk;
- Point32 pt;
- Common::Rect objBounds;
- Common::Point spritePt(_position.x / 100, _position.y / 100);
-
- if (!talk._talkCounter && _type == CHARACTER) {
- pt = _walkCount ? _position + _delta : _position;
- pt.x /= 100;
- pt.y /= 100;
-
- for (uint idx = 0; idx < scene._bgShapes.size() && !talk._talkToAbort; ++idx) {
- Object &obj = scene._bgShapes[idx];
- if (obj._aType <= PERSON || obj._type == INVALID || obj._type == HIDDEN)
- continue;
-
- if (obj._type == NO_SHAPE) {
- objBounds = Common::Rect(obj._position.x, obj._position.y,
- obj._position.x + obj._noShapeSize.x + 1, obj._position.y + obj._noShapeSize.y + 1);
- } else {
- int xp = obj._position.x + obj._imageFrame->_offset.x;
- int yp = obj._position.y + obj._imageFrame->_offset.y;
- objBounds = Common::Rect(xp, yp,
- xp + obj._imageFrame->_frame.w + 1, yp + obj._imageFrame->_frame.h + 1);
- }
-
- if (objBounds.contains(pt)) {
- if (objBounds.contains(spritePt)) {
- // Current point is already inside the the bounds, so impact occurred
- // on a previous call. So simply do nothing until we're clear of the box
- switch (obj._aType) {
- case TALK_MOVE:
- if (_walkCount) {
- // Holmes is moving
- obj._type = HIDDEN;
- obj.setFlagsAndToggles();
- talk.talkTo(obj._use[0]._target);
- }
- break;
-
- case PAL_CHANGE:
- case PAL_CHANGE2:
- if (_walkCount) {
- int palStart = atoi(obj._use[0]._names[0].c_str()) * 3;
- int palLength = atoi(obj._use[0]._names[1].c_str()) * 3;
- int templ = atoi(obj._use[0]._names[2].c_str()) * 3;
- if (templ == 0)
- templ = 100;
-
- // Ensure only valid palette change data found
- if (palLength > 0) {
- // Figure out how far into the shape Holmes is so that we
- // can figure out what percentage of the original palette
- // to set the current palette to
- int palPercent = (pt.x - objBounds.left) * 100 / objBounds.width();
- palPercent = palPercent * templ / 100;
- if (obj._aType == PAL_CHANGE)
- // Invert percentage
- palPercent = 100 - palPercent;
-
- for (int i = palStart; i < (palStart + palLength); ++i)
- screen._sMap[i] = screen._cMap[i] * palPercent / 100;
-
- events.pollEvents();
- screen.setPalette(screen._sMap);
- }
- }
- break;
-
- case TALK:
- case TALK_EVERY:
- obj._type = HIDDEN;
- obj.setFlagsAndToggles();
- talk.talkTo(obj._use[0]._target);
- break;
-
- default:
- break;
- }
- } else {
- // New impact just occurred
- switch (obj._aType) {
- case BLANK_ZONE:
- // A blank zone masks out all other remaining zones underneath it.
- // If this zone is hit, exit the outer loop so we do not check anymore
- return;
-
- case SOLID:
- case TALK:
- // Stop walking
- if (obj._aType == TALK) {
- obj.setFlagsAndToggles();
- talk.talkTo(obj._use[0]._target);
- } else {
- people.gotoStand(*this);
- }
- break;
-
- case TALK_EVERY:
- if (obj._aType == TALK_EVERY) {
- obj._type = HIDDEN;
- obj.setFlagsAndToggles();
- talk.talkTo(obj._use[0]._target);
- } else {
- people.gotoStand(*this);
- }
- break;
-
- case FLAG_SET:
- obj.setFlagsAndToggles();
- obj._type = HIDDEN;
- break;
-
- case WALK_AROUND:
- if (objBounds.contains(people._walkTo.front())) {
- // Reached zone
- people.gotoStand(*this);
- } else {
- // Destination not within box, walk to best corner
- Common::Point walkPos;
-
- if (spritePt.x >= objBounds.left && spritePt.x < objBounds.right) {
- // Impact occurred due to vertical movement. Determine whether to
- // travel to the left or right side
- if (_delta.x > 0)
- // Go to right side
- walkPos.x = objBounds.right + CLEAR_DIST_X;
- else if (_delta.x < 0) {
- // Go to left side
- walkPos.x = objBounds.left - CLEAR_DIST_X;
- } else {
- // Going straight up or down. So choose best side
- if (spritePt.x >= (objBounds.left + objBounds.width() / 2))
- walkPos.x = objBounds.right + CLEAR_DIST_X;
- else
- walkPos.x = objBounds.left - CLEAR_DIST_X;
- }
-
- walkPos.y = (_delta.y >= 0) ? objBounds.top - CLEAR_DIST_Y :
- objBounds.bottom + CLEAR_DIST_Y;
- } else {
- // Impact occurred due to horizontal movement
- if (_delta.y > 0)
- // Go to bottom of box
- walkPos.y = objBounds.bottom + CLEAR_DIST_Y;
- else if (_delta.y < 0)
- // Go to top of box
- walkPos.y = objBounds.top - CLEAR_DIST_Y;
- else {
- // Going straight horizontal, so choose best side
- if (spritePt.y >= (objBounds.top + objBounds.height() / 2))
- walkPos.y = objBounds.bottom + CLEAR_DIST_Y;
- else
- walkPos.y = objBounds.top - CLEAR_DIST_Y;
- }
-
- walkPos.x = (_delta.x >= 0) ? objBounds.left - CLEAR_DIST_X :
- objBounds.right + CLEAR_DIST_X;
- }
-
- walkPos.x += people[AL]._imageFrame->_frame.w / 2;
- people._walkDest = walkPos;
- people._walkTo.push(walkPos);
- people.setWalking();
- }
- break;
-
- case DELTA:
- _position.x += 200;
- break;
-
- default:
- break;
- }
- }
- }
- }
- }
-}
+SherlockEngine *BaseObject::_vm;
+bool BaseObject::_countCAnimFrames;
/*----------------------------------------------------------------*/
-void WalkSequence::load(Common::SeekableReadStream &s) {
- char buffer[9];
- s.read(buffer, 9);
- _vgsName = Common::String(buffer);
- _horizFlip = s.readByte() != 0;
-
- _sequences.resize(s.readUint16LE());
- s.read(&_sequences[0], _sequences.size());
-}
-
-/*----------------------------------------------------------------*/
-
-WalkSequences &WalkSequences::operator=(const WalkSequences &src) {
- resize(src.size());
- for (uint idx = 0; idx < size(); ++idx) {
- const WalkSequence &wSrc = src[idx];
- WalkSequence &wDest = (*this)[idx];
- wDest._horizFlip = wSrc._horizFlip;
-
- wDest._sequences.resize(wSrc._sequences.size());
- Common::copy(&wSrc._sequences[0], &wSrc._sequences[0] + wSrc._sequences.size(), &wDest._sequences[0]);
- }
-
- return *this;
-}
-
-/*----------------------------------------------------------------*/
-
-void ActionType::load(Common::SeekableReadStream &s) {
- char buffer[12];
-
- _cAnimNum = s.readByte();
- _cAnimSpeed = s.readByte();
- if (_cAnimSpeed & 0x80)
- _cAnimSpeed = -(_cAnimSpeed & 0x7f);
-
- for (int idx = 0; idx < NAMES_COUNT; ++idx) {
- s.read(buffer, 12);
- _names[idx] = Common::String(buffer);
- }
-}
-
-/*----------------------------------------------------------------*/
-
-UseType::UseType() {
- _cAnimNum = _cAnimSpeed = 0;
- _useFlag = 0;
-}
-
-void UseType::load(Common::SeekableReadStream &s, bool isRoseTattoo) {
- char buffer[12];
-
- if (isRoseTattoo) {
- s.read(buffer, 12);
- _verb = Common::String(buffer);
- }
-
- _cAnimNum = s.readByte();
- _cAnimSpeed = s.readByte();
- if (_cAnimSpeed & 0x80)
- _cAnimSpeed = -(_cAnimSpeed & 0x7f);
-
- for (int idx = 0; idx < NAMES_COUNT; ++idx) {
- s.read(buffer, 12);
- _names[idx] = Common::String(buffer);
- }
-
- _useFlag = s.readSint16LE();
-
- if (!isRoseTattoo)
- s.skip(6);
-
- s.read(buffer, 12);
- _target = Common::String(buffer);
-}
-
-/*----------------------------------------------------------------*/
-
-SherlockEngine *Object::_vm;
-bool Object::_countCAnimFrames;
-
-void Object::setVm(SherlockEngine *vm) {
+void BaseObject::setVm(SherlockEngine *vm) {
_vm = vm;
_countCAnimFrames = false;
}
-Object::Object() {
- _sequenceOffset = 0;
+BaseObject::BaseObject() {
+ _type = INVALID;
_sequences = nullptr;
_images = nullptr;
_imageFrame = nullptr;
+ _sequenceNumber = 0;
+ _startSeq = 0;
_walkCount = 0;
_allow = 0;
_frameNumber = 0;
- _sequenceNumber = 0;
- _type = INVALID;
- _pickup = 0;
- _defaultCommand = 0;
_lookFlag = 0;
- _pickupFlag = 0;
- _requiredFlag = 0;
+ _requiredFlag[0] = _requiredFlag[1] = 0;
_status = 0;
_misc = 0;
_maxFrames = 0;
_flags = 0;
- _aOpen._cAnimNum = 0;
- _aOpen._cAnimSpeed = 0;
_aType = OBJECT;
_lookFrames = 0;
_seqCounter = 0;
- _lookFacing = 0;
_lookcAnim = 0;
_seqStack = 0;
_seqTo = 0;
_descOffset = 0;
_seqCounter2 = 0;
_seqSize = 0;
-
_quickDraw = 0;
_scaleVal = 0;
- _requiredFlag1 = 0;
_gotoSeq = 0;
_talkSeq = 0;
_restoreSlot = 0;
}
-void Object::load(Common::SeekableReadStream &s, bool isRoseTattoo) {
- char buffer[41];
- s.read(buffer, 12);
- _name = Common::String(buffer);
- s.read(buffer, 41);
- _description = Common::String(buffer);
+bool BaseObject::hasAborts() const {
+ int seqNum = _talkSeq;
- _examine.clear();
- _sequences = nullptr;
- _images = nullptr;
- _imageFrame = nullptr;
-
- s.skip(4);
- _sequenceOffset = s.readUint16LE();
- s.seek(10, SEEK_CUR);
-
- _walkCount = s.readByte();
- _allow = s.readByte();
- _frameNumber = s.readSint16LE();
- _sequenceNumber = s.readSint16LE();
- _position.x = s.readSint16LE();
- _position.y = s.readSint16LE();
- _delta.x = s.readSint16LE();
- _delta.y = s.readSint16LE();
- _type = (SpriteType)s.readUint16LE();
- _oldPosition.x = s.readSint16LE();
- _oldPosition.y = s.readSint16LE();
- _oldSize.x = s.readUint16LE();
- _oldSize.y = s.readUint16LE();
- _goto.x = s.readSint16LE();
- _goto.y = s.readSint16LE();
+ // See if the object is in its regular sequence
+ bool startChecking = !seqNum || _type == CHARACTER;
- _pickup = isRoseTattoo ? 0 : s.readByte();
- _defaultCommand = isRoseTattoo ? 0 : s.readByte();
- _lookFlag = s.readSint16LE();
- _pickupFlag = isRoseTattoo ? 0 : s.readSint16LE();
- _requiredFlag = s.readSint16LE();
- _noShapeSize.x = s.readUint16LE();
- _noShapeSize.y = s.readUint16LE();
- _status = s.readUint16LE();
- _misc = s.readByte();
- _maxFrames = s.readUint16LE();
- _flags = s.readByte();
-
- if (!isRoseTattoo)
- _aOpen.load(s);
-
- _aType = (AType)s.readByte();
- _lookFrames = s.readByte();
- _seqCounter = s.readByte();
- _lookPosition.x = s.readUint16LE();
- _lookPosition.y = isRoseTattoo ? s.readSint16LE() : s.readByte();
- _lookFacing = s.readByte();
- _lookcAnim = s.readByte();
-
- if (!isRoseTattoo)
- _aClose.load(s);
-
- _seqStack = s.readByte();
- _seqTo = s.readByte();
- _descOffset = s.readUint16LE();
- _seqCounter2 = s.readByte();
- _seqSize = s.readUint16LE();
-
- if (isRoseTattoo) {
- for (int idx = 0; idx < 6; ++idx)
- _use[idx].load(s, true);
-
- _quickDraw = s.readByte();
- _scaleVal = s.readUint16LE();
- _requiredFlag1 = s.readSint16LE();
- _gotoSeq = s.readByte();
- _talkSeq = s.readByte();
- _restoreSlot = s.readByte();
- } else {
- s.skip(1);
- _aMove.load(s);
- s.skip(8);
-
- for (int idx = 0; idx < 4; ++idx)
- _use[idx].load(s, false);
- }
-}
-
-void Object::toggleHidden() {
- if (_type != HIDDEN && _type != HIDE_SHAPE && _type != INVALID) {
- if (_seqTo != 0)
- _sequences[_frameNumber] = _seqTo + SEQ_TO_CODE + 128;
- _seqTo = 0;
+ uint idx = 0;
+ do
+ {
+ // Get the Frame value
+ int v = _sequences[idx++];
- if (_images == nullptr || _images->size() == 0)
- // No shape to erase, so flag as hidden
- _type = HIDDEN;
- else
- // Otherwise, flag it to be hidden after it gets erased
- _type = HIDE_SHAPE;
- } else if (_type != INVALID) {
- if (_seqTo != 0)
- _sequences[_frameNumber] = _seqTo + SEQ_TO_CODE + 128;
- _seqTo = 0;
+ // See if we found an Allow Talk Interrupt Code
+ if (startChecking && v == ALLOW_TALK_CODE)
+ return true;
- _seqCounter = _seqCounter2 = 0;
- _seqStack = 0;
- _frameNumber = -1;
+ // If we've started checking and we've encountered another Talk or Listen Sequence Code,
+ // then we're done checking this sequence because this is where it would repeat
+ if (startChecking && (v == TALK_SEQ_CODE || v == TALK_LISTEN_CODE))
+ break;
- if (_images == nullptr || _images->size() == 0) {
- _type = NO_SHAPE;
+ // See if we've found the beginning of a Talk Sequence
+ if ((v == TALK_SEQ_CODE && seqNum < 128) || (v == TALK_LISTEN_CODE && seqNum >= 128)) {
+ // If checking was already on and we came across one of these codes, then there couldn't
+ // have been an Allow Talk Interrupt code in the sequence we were checking, so we're done.
+ if (startChecking)
+ break;
+
+ seqNum--;
+ // See if we're at the correct Talk Sequence Number
+ if (!(seqNum & 127))
+ {
+ // Correct Sequence, Start Checking Now
+ startChecking = true;
+ }
} else {
- _type = ACTIVE_BG_SHAPE;
- int idx = _sequences[0];
- if (idx >= _maxFrames)
- // Turn on: set up first frame
- idx = 0;
-
- _imageFrame = &(*_images)[idx];
+ // Move ahead any extra because of special control codes
+ switch (v) {
+ case 0: idx++; break;
+ case MOVE_CODE:
+ case TELEPORT_CODE: idx += 4; break;
+ case CALL_TALK_CODE:idx += 8; break;
+ case HIDE_CODE: idx += 2; break;
+ }
}
- }
+ } while (idx < _seqSize);
+
+ return false;
}
-void Object::checkObject() {
+void BaseObject::checkObject() {
Scene &scene = *_vm->_scene;
Sound &sound = *_vm->_sound;
+ Talk &talk = *_vm->_talk;
int checkFrame = _allow ? MAX_FRAME : FRAMES_END;
bool codeFound;
if (_seqTo) {
byte *ptr = &_sequences[_frameNumber];
if (*ptr == _seqTo) {
- // The sequence is completed
- *ptr = _seqTo + SEQ_TO_CODE + 128; // Reset to normal
+ // The sequence is completed. Reset to normal
+ *ptr = _seqTo + (IS_ROSE_TATTOO ? 0 : SEQ_TO_CODE + 128);
_seqTo = 0;
} else {
// Continue doing sequence
@@ -637,6 +164,11 @@ void Object::checkObject() {
++_frameNumber;
do {
+ if (!_sequences) {
+ warning("checkObject: _sequences is not set");
+ break;
+ }
+
// Check for end of sequence
codeFound = checkEndOfSequence();
@@ -644,20 +176,33 @@ void Object::checkObject() {
codeFound = true;
int v = _sequences[_frameNumber];
- if (v >= 228) {
+ // Check for a Talk or Listen Sequence
+ if (IS_ROSE_TATTOO && v == ALLOW_TALK_CODE) {
+ if (_gotoSeq) {
+ setObjTalkSequence(_gotoSeq);
+ _gotoSeq = 0;
+ } else {
+ ++_frameNumber;
+ }
+ } else if (IS_ROSE_TATTOO && (v == TALK_SEQ_CODE || v == TALK_LISTEN_CODE)) {
+ if (_talkSeq)
+ setObjTalkSequence(_talkSeq);
+ else
+ setObjSequence(0, false);
+ } else if (v >= GOTO_CODE) {
// Goto code found
- v -= 228;
+ v -= GOTO_CODE;
_seqCounter2 = _seqCounter;
_seqStack = _frameNumber + 1;
setObjSequence(v, false);
} else if (v >= SOUND_CODE && (v < (SOUND_CODE + 30))) {
codeFound = true;
++_frameNumber;
- v -= SOUND_CODE;
+ v -= SOUND_CODE + (IS_SERRATED_SCALPEL ? 1 : 0);
if (sound._soundOn && !_countCAnimFrames) {
- if (!scene._sounds[v - 1]._name.empty() && sound._digitized)
- sound.playLoadedSound(v - 1, WAIT_RETURN_IMMEDIATELY);
+ if (!scene._sounds[v]._name.empty() && sound._digitized)
+ sound.playLoadedSound(v, WAIT_RETURN_IMMEDIATELY);
}
} else if (v >= FLIP_CODE && v < (FLIP_CODE + 3)) {
// Flip code
@@ -682,28 +227,90 @@ void Object::checkObject() {
default:
break;
}
+ } else if (IS_ROSE_TATTOO && v == TELEPORT_CODE) {
+ _position.x = READ_LE_UINT16(&_sequences[_frameNumber + 1]);
+ _position.y = READ_LE_UINT16(&_sequences[_frameNumber + 3]);
+
+ _frameNumber += 5;
+ } else if (IS_ROSE_TATTOO && v == CALL_TALK_CODE) {
+ Common::String filename;
+ for (int idx = 0; idx < 8; ++idx) {
+ if (_sequences[_frameNumber + 1 + idx] != 1)
+ filename += (char)_sequences[_frameNumber + 1 + idx];
+ else
+ break;
+ }
+
+ _frameNumber += 8;
+ talk.talkTo(filename);
+
+ } else if (IS_ROSE_TATTOO && v == HIDE_CODE) {
+ switch (_sequences[_frameNumber + 2]) {
+ case 1:
+ // Hide Object
+ if (scene._bgShapes[_sequences[_frameNumber + 1] - 1]._type != HIDDEN)
+ scene._bgShapes[_sequences[_frameNumber + 1] - 1].toggleHidden();
+ break;
+
+ case 2:
+ // Activate Object
+ if (scene._bgShapes[_sequences[_frameNumber + 1] - 1]._type == HIDDEN)
+ scene._bgShapes[_sequences[_frameNumber + 1] - 1].toggleHidden();
+ break;
+
+ case 3:
+ // Toggle Object
+ scene._bgShapes[_sequences[_frameNumber + 1] - 1].toggleHidden();
+ break;
+
+ default:
+ break;
+ }
+ _frameNumber += 3;
+
} else {
v -= 128;
- // 68-99 is a squence code
+ // 68-99 is a sequence code
if (v > SEQ_TO_CODE) {
- byte *p = &_sequences[_frameNumber];
- v -= SEQ_TO_CODE; // # from 1-32
- _seqTo = v;
- *p = *(p - 1);
-
- if (*p > 128)
- // If the high bit is set, convert to a real frame
- *p -= (byte)(SEQ_TO_CODE - 128);
-
- if (*p > _seqTo)
- *p -= 1;
- else
- *p += 1;
+ if (IS_ROSE_TATTOO) {
+ ++_frameNumber;
+ byte *p = &_sequences[_frameNumber];
+ _seqTo = *p;
+ *p = *(p - 2);
+
+ if (*p > _seqTo)
+ *p -= 1;
+ else
+ *p += 1;
+
+ --_frameNumber;
+ } else {
+ byte *p = &_sequences[_frameNumber];
+ v -= SEQ_TO_CODE; // # from 1-32
+ _seqTo = v;
+ *p = *(p - 1);
+
+ if (*p > 128)
+ // If the high bit is set, convert to a real frame
+ *p -= (byte)(SEQ_TO_CODE - 128);
+
+ if (*p > _seqTo)
+ *p -= 1;
+ else
+ *p += 1;
+
+ // Will be incremented below to return back to original value
+ --_frameNumber;
+ v = 0;
+ }
+ } else if (IS_ROSE_TATTOO && v == 10) {
+ // Set delta for objects
+ _delta = Common::Point(READ_LE_UINT16(&_sequences[_frameNumber + 1]),
+ READ_LE_UINT16(&_sequences[_frameNumber + 3]));
+ _noShapeSize = Common::Point(0, 0);
+ _frameNumber += 4;
- // Will be incremented below to return back to original value
- --_frameNumber;
- v = 0;
} else if (v == 10) {
// Set delta for objects
Common::Point pt(_sequences[_frameNumber + 1], _sequences[_frameNumber + 2]);
@@ -719,9 +326,10 @@ void Object::checkObject() {
_delta = pt;
_frameNumber += 2;
+
} else if (v < USE_COUNT) {
for (int idx = 0; idx < NAMES_COUNT; ++idx) {
- checkNameForCodes(_use[v]._names[idx], nullptr);
+ checkNameForCodes(_use[v]._names[idx]);
}
if (_use[v]._useFlag)
@@ -734,7 +342,7 @@ void Object::checkObject() {
} while (codeFound);
}
-bool Object::checkEndOfSequence() {
+bool BaseObject::checkEndOfSequence() {
Screen &screen = *_vm->_screen;
int checkFrame = _allow ? MAX_FRAME : FRAMES_END;
bool result = false;
@@ -742,20 +350,26 @@ bool Object::checkEndOfSequence() {
if (_type == REMOVE || _type == INVALID)
return false;
- if (_sequences[_frameNumber] == 0 || _frameNumber >= checkFrame) {
+ if (_frameNumber < 0 || _frameNumber >= checkFrame || _sequences[_frameNumber] == 0) {
result = true;
- if (_frameNumber >= (checkFrame - 1)) {
+ if (_frameNumber < 0 || _frameNumber >= (checkFrame - 1)) {
_frameNumber = START_FRAME;
} else {
// Determine next sequence to use
int seq = _sequences[_frameNumber + 1];
+ // If the object has been turned off, we're going nowhere
+ if (IS_ROSE_TATTOO && (_type == HIDE_SHAPE || _type == HIDDEN || _type == REMOVE))
+ return false;
+
if (seq == 99) {
--_frameNumber;
screen._backBuffer1.transBlitFrom(*_imageFrame, _position);
screen._backBuffer2.transBlitFrom(*_imageFrame, _position);
_type = INVALID;
+ } else if (IS_ROSE_TATTOO && _talkSeq && seq == 0) {
+ setObjTalkSequence(_talkSeq);
} else {
setObjSequence(seq, false);
}
@@ -786,10 +400,14 @@ bool Object::checkEndOfSequence() {
return result;
}
-void Object::setObjSequence(int seq, bool wait) {
+void BaseObject::setObjSequence(int seq, bool wait) {
Scene &scene = *_vm->_scene;
int checkFrame = _allow ? MAX_FRAME : FRAMES_END;
+ if (IS_ROSE_TATTOO && (seq == -1 || seq == 255))
+ // This means goto beginning
+ seq = 0;
+
if (seq >= 128) {
// Loop the sequence until the count exceeded
seq -= 128;
@@ -812,6 +430,10 @@ void Object::setObjSequence(int seq, bool wait) {
if (_frameNumber >= checkFrame)
_frameNumber = 0;
+ // For Rose Tattoo, save the starting frame for new sequences
+ if (IS_ROSE_TATTOO)
+ _startSeq = _frameNumber;
+
_seqCounter = 0;
if (_sequences[_frameNumber] == 0)
seq = _sequences[_frameNumber + 1];
@@ -819,12 +441,18 @@ void Object::setObjSequence(int seq, bool wait) {
return;
} else {
// Find beginning of sequence
- do {
- --_frameNumber;
- } while (_frameNumber > 0 && _sequences[_frameNumber] != 0);
+ if (IS_ROSE_TATTOO) {
+ // Use the saved start of the sequence to reset the frame
+ _frameNumber = _startSeq;
+ } else {
+ // For Scalpel, scan backwards from the end of the sequence to find its start
+ do {
+ --_frameNumber;
+ } while (_frameNumber > 0 && _sequences[_frameNumber] != 0);
- if (_frameNumber != 0)
- _frameNumber += 2;
+ if (_frameNumber != 0)
+ _frameNumber += 2;
+ }
return;
}
@@ -837,16 +465,35 @@ void Object::setObjSequence(int seq, bool wait) {
int seqCc = 0;
while (seqCc < seq && idx < checkFrame) {
- ++idx;
- if (_sequences[idx] == 0) {
- ++seqCc;
- idx += 2;
+ if (IS_SERRATED_SCALPEL) {
+ ++idx;
+
+ if (_sequences[idx] == 0) {
+ ++seqCc;
+ idx += 2;
+ }
+ } else {
+ byte s = _sequences[idx];
+
+ if (s == 0) {
+ ++seqCc;
+ ++idx;
+ } else if (s == MOVE_CODE || s == TELEPORT_CODE) {
+ idx += 4;
+ } else if (s == CALL_TALK_CODE) {
+ idx += 8;
+ } else if (s == HIDE_CODE) {
+ idx += 2;
+ }
+
+ ++idx;
}
}
if (idx >= checkFrame)
idx = 0;
_frameNumber = idx;
+ _startSeq = idx;
if (wait) {
seqCc = idx;
@@ -859,8 +506,8 @@ void Object::setObjSequence(int seq, bool wait) {
}
}
-int Object::checkNameForCodes(const Common::String &name, const char *const messages[]) {
- Map &map = *_vm->_map;
+int BaseObject::checkNameForCodes(const Common::String &name, FixedTextActionId fixedTextActionId) {
+ FixedText &fixedText = *_vm->_fixedText;
People &people = *_vm->_people;
Scene &scene = *_vm->_scene;
Screen &screen = *_vm->_screen;
@@ -901,13 +548,20 @@ int Object::checkNameForCodes(const Common::String &name, const char *const mess
break;
}
+ case 'V':
+ // Do nothing for Verb codes. This is only a flag for Inventory syntax
+ break;
+
default:
if (ch >= '0' && ch <= '9') {
scene._goToScene = atoi(name.c_str() + 1);
- if (scene._goToScene < 97 && map[scene._goToScene].x) {
- map._overPos.x = map[scene._goToScene].x * 100 - 600;
- map._overPos.y = map[scene._goToScene].y * 100 + 900;
+ if (IS_SERRATED_SCALPEL && scene._goToScene < 97) {
+ Scalpel::ScalpelMap &map = *(Scalpel::ScalpelMap *)_vm->_map;
+ if (map[scene._goToScene].x) {
+ map._overPos.x = (map[scene._goToScene].x - 6) * FIXED_INT_MULTIPLIER;
+ map._overPos.y = (map[scene._goToScene].y + 9) * FIXED_INT_MULTIPLIER;
+ }
}
const char *p;
@@ -915,24 +569,23 @@ int Object::checkNameForCodes(const Common::String &name, const char *const mess
++p;
Common::String s(p, p + 3);
- people._hSavedPos.x = atoi(s.c_str());
+ people._savedPos.x = atoi(s.c_str());
s = Common::String(p + 3, p + 6);
- people._hSavedPos.y = atoi(s.c_str());
+ people._savedPos.y = atoi(s.c_str());
s = Common::String(p + 6, p + 9);
- people._hSavedFacing = atoi(s.c_str());
- if (people._hSavedFacing == 0)
- people._hSavedFacing = 10;
+ people._savedPos._facing = atoi(s.c_str());
+ if (people._savedPos._facing == 0)
+ people._savedPos._facing = 10;
} else if ((p = strchr(name.c_str(), '/')) != nullptr) {
- people._hSavedPos = Common::Point(1, 0);
- people._hSavedFacing = 100 + atoi(p + 1);
+ people._savedPos = PositionFacing(1, 0, 100 + atoi(p + 1));
}
} else {
scene._goToScene = 100;
}
- people[AL]._position = Common::Point(0, 0);
+ people[HOLMES]._position = Point32(0, 0);
break;
}
} else if (name.hasPrefix("!")) {
@@ -940,13 +593,14 @@ int Object::checkNameForCodes(const Common::String &name, const char *const mess
int messageNum = atoi(name.c_str() + 1);
ui._infoFlag = true;
ui.clearInfo();
- screen.print(Common::Point(0, INFO_LINE + 1), INFO_FOREGROUND, "%s", messages[messageNum]);
+ Common::String errorMessage = fixedText.getActionMessage(fixedTextActionId, messageNum);
+ screen.print(Common::Point(0, INFO_LINE + 1), COL_INFO_FOREGROUND, "%s", errorMessage.c_str());
ui._menuCounter = 25;
} else if (name.hasPrefix("@")) {
// Message attached to canimation
ui._infoFlag = true;
ui.clearInfo();
- screen.print(Common::Point(0, INFO_LINE + 1), INFO_FOREGROUND, "%s", name.c_str() + 1);
+ screen.print(Common::Point(0, INFO_LINE + 1), COL_INFO_FOREGROUND, "%s", name.c_str() + 1);
printed = true;
ui._menuCounter = 25;
}
@@ -954,6 +608,679 @@ int Object::checkNameForCodes(const Common::String &name, const char *const mess
return printed;
}
+/*----------------------------------------------------------------*/
+
+void Sprite::clear() {
+ _name = "";
+ _description = "";
+ _examine.clear();
+ _pickUp = "";
+ _walkSequences.clear();
+ _sequences = nullptr;
+ _images = nullptr;
+ _imageFrame = nullptr;
+ _walkCount = 0;
+ _allow = 0;
+ _frameNumber = 0;
+ _position.x = _position.y = 0;
+ _delta.x = _delta.y = 0;
+ _oldPosition.x = _oldPosition.y = 0;
+ _oldSize.x = _oldSize.y = 0;
+ _goto.x = _goto.y = 0;
+ _type = INVALID;
+ _pickUp.clear();
+ _noShapeSize.x = _noShapeSize.y = 0;
+ _status = 0;
+ _misc = 0;
+ _altImages = nullptr;
+ _altSeq = 0;
+ Common::fill(&_stopFrames[0], &_stopFrames[8], (ImageFrame *)nullptr);
+}
+
+void Sprite::setImageFrame() {
+ int frameNum = MAX(_frameNumber, 0);
+ int imageNumber = _walkSequences[_sequenceNumber][frameNum];
+
+ if (IS_SERRATED_SCALPEL)
+ imageNumber = imageNumber + _walkSequences[_sequenceNumber][0] - 2;
+ else if (imageNumber > _maxFrames)
+ imageNumber = 1;
+
+ // Get the images to use
+ ImageFile *images = _altSeq ? _altImages : _images;
+ assert(images);
+
+ if (IS_3DO) {
+ // only do this to the image-array with 110 entries
+ // map uses another image-array and this code
+ if (images->size() == 110) {
+ // 3DO has 110 animation frames inside walk.anim
+ // PC has 55
+ // this adjusts the framenumber accordingly
+ // sort of HACK
+ imageNumber *= 2;
+ }
+ } else if (IS_ROSE_TATTOO) {
+ --imageNumber;
+ }
+
+ // Set the frame pointer
+ _imageFrame = &(*images)[imageNumber];
+}
+
+void Sprite::checkSprite() {
+ Events &events = *_vm->_events;
+ People &people = *_vm->_people;
+ Scene &scene = *_vm->_scene;
+ Screen &screen = *_vm->_screen;
+ Talk &talk = *_vm->_talk;
+ Point32 pt;
+ Common::Rect objBounds;
+ Common::Point spritePt(_position.x / FIXED_INT_MULTIPLIER, _position.y / FIXED_INT_MULTIPLIER);
+
+ if (_type != CHARACTER || (IS_SERRATED_SCALPEL && talk._talkCounter))
+ return;
+
+ pt = _walkCount ? _position + _delta : _position;
+ pt.x /= FIXED_INT_MULTIPLIER;
+ pt.y /= FIXED_INT_MULTIPLIER;
+
+ if (IS_ROSE_TATTOO) {
+ checkObject();
+
+ // For Rose Tattoo, we only do the further processing for Sherlock
+ if (this != &people[HOLMES])
+ return;
+ }
+
+ for (uint idx = 0; idx < scene._bgShapes.size() && !talk._talkToAbort; ++idx) {
+ Object &obj = scene._bgShapes[idx];
+ if (obj._aType <= PERSON || obj._type == INVALID || obj._type == HIDDEN)
+ continue;
+
+ if (obj._type == NO_SHAPE) {
+ objBounds = Common::Rect(obj._position.x, obj._position.y,
+ obj._position.x + obj._noShapeSize.x + 1, obj._position.y + obj._noShapeSize.y + 1);
+ } else {
+ int xp = obj._position.x + obj._imageFrame->_offset.x;
+ int yp = obj._position.y + obj._imageFrame->_offset.y;
+ objBounds = Common::Rect(xp, yp,
+ xp + obj._imageFrame->_frame.w + 1, yp + obj._imageFrame->_frame.h + 1);
+ }
+
+ if (objBounds.contains(pt)) {
+ if (objBounds.contains(spritePt)) {
+ // Current point is already inside the the bounds, so impact occurred
+ // on a previous call. So simply do nothing until we're clear of the box
+ switch (obj._aType) {
+ case TALK_MOVE:
+ if (_walkCount) {
+ // Holmes is moving
+ obj._type = HIDDEN;
+ obj.setFlagsAndToggles();
+ talk.talkTo(obj._use[0]._target);
+ }
+ break;
+
+ case PAL_CHANGE:
+ case PAL_CHANGE2:
+ if (_walkCount) {
+ int palStart = atoi(obj._use[0]._names[0].c_str()) * 3;
+ int palLength = atoi(obj._use[0]._names[1].c_str()) * 3;
+ int templ = atoi(obj._use[0]._names[2].c_str()) * 3;
+ if (templ == 0)
+ templ = 100;
+
+ // Ensure only valid palette change data found
+ if (palLength > 0) {
+ // Figure out how far into the shape Holmes is so that we
+ // can figure out what percentage of the original palette
+ // to set the current palette to
+ int palPercent = (pt.x - objBounds.left) * 100 / objBounds.width();
+ palPercent = palPercent * templ / 100;
+ if (obj._aType == PAL_CHANGE)
+ // Invert percentage
+ palPercent = 100 - palPercent;
+
+ for (int i = palStart; i < (palStart + palLength); ++i)
+ screen._sMap[i] = screen._cMap[i] * palPercent / 100;
+
+ events.pollEvents();
+ screen.setPalette(screen._sMap);
+ }
+ }
+ break;
+
+ case TALK:
+ case TALK_EVERY:
+ obj._type = HIDDEN;
+ obj.setFlagsAndToggles();
+ talk.talkTo(obj._use[0]._target);
+ break;
+
+ default:
+ break;
+ }
+ } else {
+ // New impact just occurred
+ switch (obj._aType) {
+ case BLANK_ZONE:
+ // A blank zone masks out all other remaining zones underneath it.
+ // If this zone is hit, exit the outer loop so we do not check anymore
+ return;
+
+ case SOLID:
+ case TALK:
+ // Stop walking
+ if (obj._aType == TALK) {
+ obj.setFlagsAndToggles();
+ talk.talkTo(obj._use[0]._target);
+ } else {
+ gotoStand();
+ }
+ break;
+
+ case TALK_EVERY:
+ if (obj._aType == TALK_EVERY) {
+ obj._type = HIDDEN;
+ obj.setFlagsAndToggles();
+ talk.talkTo(obj._use[0]._target);
+ } else {
+ gotoStand();
+ }
+ break;
+
+ case FLAG_SET:
+ obj.setFlagsAndToggles();
+ obj._type = HIDDEN;
+ break;
+
+ case WALK_AROUND:
+ if (objBounds.contains(people[HOLMES]._walkTo.front())) {
+ // Reached zone
+ gotoStand();
+ } else {
+ // Destination not within box, walk to best corner
+ Common::Point walkPos;
+
+ if (spritePt.x >= objBounds.left && spritePt.x < objBounds.right) {
+ // Impact occurred due to vertical movement. Determine whether to
+ // travel to the left or right side
+ if (_delta.x > 0)
+ // Go to right side
+ walkPos.x = objBounds.right + CLEAR_DIST_X;
+ else if (_delta.x < 0) {
+ // Go to left side
+ walkPos.x = objBounds.left - CLEAR_DIST_X;
+ } else {
+ // Going straight up or down. So choose best side
+ if (spritePt.x >= (objBounds.left + objBounds.width() / 2))
+ walkPos.x = objBounds.right + CLEAR_DIST_X;
+ else
+ walkPos.x = objBounds.left - CLEAR_DIST_X;
+ }
+
+ walkPos.y = (_delta.y >= 0) ? objBounds.top - CLEAR_DIST_Y :
+ objBounds.bottom + CLEAR_DIST_Y;
+ } else {
+ // Impact occurred due to horizontal movement
+ if (_delta.y > 0)
+ // Go to bottom of box
+ walkPos.y = objBounds.bottom + CLEAR_DIST_Y;
+ else if (_delta.y < 0)
+ // Go to top of box
+ walkPos.y = objBounds.top - CLEAR_DIST_Y;
+ else {
+ // Going straight horizontal, so choose best side
+ if (spritePt.y >= (objBounds.top + objBounds.height() / 2))
+ walkPos.y = objBounds.bottom + CLEAR_DIST_Y;
+ else
+ walkPos.y = objBounds.top - CLEAR_DIST_Y;
+ }
+
+ walkPos.x = (_delta.x >= 0) ? objBounds.left - CLEAR_DIST_X :
+ objBounds.right + CLEAR_DIST_X;
+ }
+
+ walkPos.x += people[HOLMES]._imageFrame->_frame.w / 2;
+ people[HOLMES]._walkDest = walkPos;
+ people[HOLMES]._walkTo.push(walkPos);
+ people[HOLMES].setWalking();
+ }
+ break;
+
+ case DELTA:
+ _position.x += 200;
+ break;
+
+ default:
+ break;
+ }
+ }
+ }
+ }
+}
+
+const Common::Rect Sprite::getOldBounds() const {
+ return Common::Rect(_oldPosition.x, _oldPosition.y, _oldPosition.x + _oldSize.x, _oldPosition.y + _oldSize.y);
+}
+
+/*----------------------------------------------------------------*/
+
+void WalkSequence::load(Common::SeekableReadStream &s) {
+ char buffer[9];
+ s.read(buffer, 9);
+ _vgsName = Common::String(buffer);
+ _horizFlip = s.readByte() != 0;
+
+ _sequences.resize(s.readUint16LE());
+ s.skip(4); // Skip over pointer field of structure
+
+ s.read(&_sequences[0], _sequences.size());
+}
+
+/*----------------------------------------------------------------*/
+
+WalkSequences &WalkSequences::operator=(const WalkSequences &src) {
+ resize(src.size());
+ for (uint idx = 0; idx < size(); ++idx) {
+ const WalkSequence &wSrc = src[idx];
+ WalkSequence &wDest = (*this)[idx];
+ wDest._horizFlip = wSrc._horizFlip;
+
+ wDest._sequences.resize(wSrc._sequences.size());
+ Common::copy(&wSrc._sequences[0], &wSrc._sequences[0] + wSrc._sequences.size(), &wDest._sequences[0]);
+ }
+
+ return *this;
+}
+
+/*----------------------------------------------------------------*/
+
+ActionType::ActionType() {
+ _cAnimNum = _cAnimSpeed = 0;
+ _useFlag = 0;
+}
+
+void ActionType::load(Common::SeekableReadStream &s) {
+ char buffer[12];
+
+ _cAnimNum = s.readByte();
+ _cAnimSpeed = s.readByte();
+ if (_cAnimSpeed & 0x80)
+ _cAnimSpeed = -(_cAnimSpeed & 0x7f);
+
+ for (int idx = 0; idx < NAMES_COUNT; ++idx) {
+ s.read(buffer, 12);
+ _names[idx] = Common::String(buffer);
+ }
+}
+
+/*----------------------------------------------------------------*/
+
+UseType::UseType(): ActionType() {
+}
+
+void UseType::load(Common::SeekableReadStream &s, bool isRoseTattoo) {
+ char buffer[12];
+
+ if (isRoseTattoo) {
+ s.read(buffer, 12);
+ _verb = Common::String(buffer);
+ }
+
+ ActionType::load(s);
+
+ _useFlag = s.readSint16LE();
+
+ if (!isRoseTattoo)
+ s.skip(6);
+
+ s.read(buffer, 12);
+ _target = Common::String(buffer);
+}
+
+void UseType::load3DO(Common::SeekableReadStream &s) {
+ char buffer[12];
+
+ _cAnimNum = s.readByte();
+ _cAnimSpeed = s.readByte();
+ if (_cAnimSpeed & 0x80)
+ _cAnimSpeed = -(_cAnimSpeed & 0x7f);
+
+ for (int idx = 0; idx < NAMES_COUNT; ++idx) {
+ s.read(buffer, 12);
+ _names[idx] = Common::String(buffer);
+ }
+
+ _useFlag = s.readSint16BE();
+
+ s.skip(6);
+
+ s.read(buffer, 12);
+ _target = Common::String(buffer);
+}
+
+void UseType::synchronize(Serializer &s) {
+ s.syncString(_verb);
+ s.syncAsSint16LE(_cAnimNum);
+ s.syncAsSint16LE(_cAnimSpeed);
+ s.syncAsSint16LE(_useFlag);
+
+ for (int idx = 0; idx < 4; ++idx)
+ s.syncString(_names[idx]);
+ s.syncString(_target);
+}
+
+/*----------------------------------------------------------------*/
+
+Object::Object(): BaseObject() {
+ _sequenceOffset = 0;
+ _pickup = 0;
+ _defaultCommand = 0;
+ _pickupFlag = 0;
+}
+
+void Object::load(Common::SeekableReadStream &s, bool isRoseTattoo) {
+ char buffer[41];
+ s.read(buffer, 12);
+ _name = Common::String(buffer);
+ s.read(buffer, 41);
+ _description = Common::String(buffer);
+
+ _examine.clear();
+ _sequences = nullptr;
+ _images = nullptr;
+ _imageFrame = nullptr;
+
+ s.skip(4);
+ _sequenceOffset = s.readUint16LE();
+ s.seek(10, SEEK_CUR);
+
+ _walkCount = s.readByte();
+ _allow = s.readByte();
+ _frameNumber = s.readSint16LE();
+ _sequenceNumber = s.readSint16LE();
+ _position.x = s.readSint16LE();
+ _position.y = s.readSint16LE();
+ _delta.x = s.readSint16LE();
+ _delta.y = s.readSint16LE();
+ _type = (SpriteType)s.readUint16LE();
+ _oldPosition.x = s.readSint16LE();
+ _oldPosition.y = s.readSint16LE();
+ _oldSize.x = s.readUint16LE();
+ _oldSize.y = s.readUint16LE();
+
+ _goto.x = s.readSint16LE();
+ _goto.y = s.readSint16LE();
+ if (!isRoseTattoo) {
+ _goto.x = _goto.x * FIXED_INT_MULTIPLIER / 100;
+ _goto.y = _goto.y * FIXED_INT_MULTIPLIER / 100;
+ }
+
+ _pickup = isRoseTattoo ? 0 : s.readByte();
+ _defaultCommand = isRoseTattoo ? 0 : s.readByte();
+ _lookFlag = s.readSint16LE();
+ _pickupFlag = isRoseTattoo ? 0 : s.readSint16LE();
+ _requiredFlag[0] = s.readSint16LE();
+ _noShapeSize.x = s.readUint16LE();
+ _noShapeSize.y = s.readUint16LE();
+ _status = s.readUint16LE();
+ _misc = s.readByte();
+ _maxFrames = s.readUint16LE();
+ _flags = s.readByte();
+
+ if (!isRoseTattoo)
+ _aOpen.load(s);
+
+ _aType = (AType)s.readByte();
+ _lookFrames = s.readByte();
+ _seqCounter = s.readByte();
+ if (isRoseTattoo) {
+ _lookPosition.x = s.readUint16LE() * FIXED_INT_MULTIPLIER;
+ _lookPosition.y = s.readSint16LE() * FIXED_INT_MULTIPLIER;
+ } else {
+ _lookPosition.x = s.readUint16LE() * FIXED_INT_MULTIPLIER / 100;
+ _lookPosition.y = s.readByte() * FIXED_INT_MULTIPLIER;
+ }
+ _lookPosition._facing = s.readByte();
+ _lookcAnim = s.readByte();
+
+ if (!isRoseTattoo)
+ _aClose.load(s);
+
+ _seqStack = s.readByte();
+ _seqTo = s.readByte();
+ _descOffset = s.readUint16LE();
+ _seqCounter2 = s.readByte();
+ _seqSize = s.readUint16LE();
+
+ if (isRoseTattoo) {
+ for (int idx = 0; idx < 6; ++idx)
+ _use[idx].load(s, true);
+
+ _quickDraw = s.readByte();
+ _scaleVal = s.readUint16LE();
+ _requiredFlag[1] = s.readSint16LE();
+ _gotoSeq = s.readByte();
+ _talkSeq = s.readByte();
+ _restoreSlot = s.readByte();
+ } else {
+ s.skip(1);
+ _aMove.load(s);
+ s.skip(8);
+
+ for (int idx = 0; idx < 4; ++idx)
+ _use[idx].load(s, false);
+ }
+ //warning("object %s, useAnim %d", _name.c_str(), _use[0]._cAnimNum);
+}
+
+void Object::load3DO(Common::SeekableReadStream &s) {
+ int32 streamStartPos = s.pos();
+ char buffer[41];
+
+ _examine.clear();
+ _sequences = nullptr;
+ _images = nullptr;
+ _imageFrame = nullptr;
+
+ // on 3DO all of this data is reordered!!!
+ // it seems that possibly the 3DO compiler reordered the global struct
+ // 3DO size for 1 object is 588 bytes
+ s.skip(4);
+ _sequenceOffset = s.readUint16LE(); // weird that this seems to be LE
+ s.seek(10, SEEK_CUR);
+
+ // Offset 16
+ _frameNumber = s.readSint16BE();
+ _sequenceNumber = s.readSint16BE();
+ _position.x = s.readSint16BE();
+ _position.y = s.readSint16BE();
+ _delta.x = s.readSint16BE();
+ _delta.y = s.readSint16BE();
+ _type = (SpriteType)s.readUint16BE();
+ _oldPosition.x = s.readSint16BE();
+ _oldPosition.y = s.readSint16BE();
+ _oldSize.x = s.readUint16BE();
+ _oldSize.y = s.readUint16BE();
+
+ _goto.x = s.readSint16BE();
+ _goto.y = s.readSint16BE();
+ _goto.x = _goto.x * FIXED_INT_MULTIPLIER / 100;
+ _goto.y = _goto.y * FIXED_INT_MULTIPLIER / 100;
+
+ // Offset 42
+ warning("pos %d", s.pos());
+
+ // Unverified
+ _lookFlag = s.readSint16BE();
+ _pickupFlag = s.readSint16BE();
+ _requiredFlag[0] = s.readSint16BE();
+ _noShapeSize.x = s.readUint16BE();
+ _noShapeSize.y = s.readUint16BE();
+ _status = s.readUint16BE();
+ // Unverified END
+
+ _maxFrames = s.readUint16BE();
+ // offset 56
+ _lookPosition.x = s.readUint16BE() * FIXED_INT_MULTIPLIER / 100;
+ // offset 58
+ _descOffset = s.readUint16BE();
+ _seqSize = s.readUint16BE();
+
+ s.skip(2); // boundary filler
+
+ // 288 bytes
+ for (int idx = 0; idx < 4; ++idx) {
+ _use[idx].load3DO(s);
+ s.skip(2); // Filler
+ }
+
+ // 158 bytes
+ _aOpen.load(s); // 2 + 12*4 bytes = 50 bytes
+ s.skip(2); // Boundary filler
+ _aClose.load(s);
+ s.skip(2); // Filler
+ _aMove.load(s);
+ s.skip(2); // Filler
+
+ // offset 508
+ // 3DO: name is at the end
+ s.read(buffer, 12);
+ _name = Common::String(buffer);
+ s.read(buffer, 41);
+ _description = Common::String(buffer);
+
+ // Unverified
+ _walkCount = s.readByte();
+ _allow = s.readByte();
+ _pickup = s.readByte();
+ _defaultCommand = s.readByte();
+ // Unverified END
+
+ // Probably those here?!?!
+ _misc = s.readByte();
+ _flags = s.readByte();
+
+ // Unverified
+ _aType = (AType)s.readByte();
+ _lookFrames = s.readByte();
+ _seqCounter = s.readByte();
+ // Unverified END
+
+ _lookPosition.y = s.readByte() * FIXED_INT_MULTIPLIER;
+ _lookPosition._facing = s.readByte();
+
+ // Unverified
+ _lookcAnim = s.readByte();
+ _seqStack = s.readByte();
+ _seqTo = s.readByte();
+ _seqCounter2 = s.readByte();
+ // Unverified END
+
+ s.skip(12); // Unknown
+
+ //warning("object %s, offset %d", _name.c_str(), streamPos);
+ //warning("object %s, lookPosX %d, lookPosY %d", _name.c_str(), _lookPosition.x, _lookPosition.y);
+ //warning("object %s, defCmd %d", _name.c_str(), _defaultCommand);
+ int32 dataSize = s.pos() - streamStartPos;
+ assert(dataSize == 588);
+}
+
+void Object::toggleHidden() {
+ if (_type != HIDDEN && _type != HIDE_SHAPE && _type != INVALID) {
+ if (_seqTo != 0)
+ _sequences[_frameNumber] = _seqTo + SEQ_TO_CODE + 128;
+ _seqTo = 0;
+
+ if (_images == nullptr || _images->size() == 0)
+ // No shape to erase, so flag as hidden
+ _type = HIDDEN;
+ else
+ // Otherwise, flag it to be hidden after it gets erased
+ _type = HIDE_SHAPE;
+ } else if (_type != INVALID) {
+ if (_seqTo != 0)
+ _sequences[_frameNumber] = _seqTo + SEQ_TO_CODE + 128;
+ _seqTo = 0;
+
+ _seqCounter = _seqCounter2 = 0;
+ _seqStack = 0;
+ _frameNumber = -1;
+
+ if (_images == nullptr || _images->size() == 0) {
+ _type = NO_SHAPE;
+ } else {
+ _type = ACTIVE_BG_SHAPE;
+ int idx = _sequences[0];
+ if (idx >= _maxFrames)
+ // Turn on: set up first frame
+ idx = 0;
+
+ _imageFrame = &(*_images)[idx];
+ }
+ }
+}
+
+void Object::setObjTalkSequence(int seq) {
+ Talk &talk = *_vm->_talk;
+
+ // See if we're supposed to restore the object's sequence from the talk sequence stack
+ if (seq == -1) {
+ if (_seqTo != 0)
+ _sequences[_frameNumber] = _seqTo;
+
+ talk.pullSequence(_restoreSlot);
+ return;
+ }
+
+ assert(_type != CHARACTER);
+
+ talk.pushSequenceEntry(this);
+ int talkSeqNum = seq;
+
+ // Find where the talk sequence data begins in the object
+ int idx = 0;
+ for (;;) {
+ // Get the Frame value
+ byte f = _sequences[idx++];
+
+ // See if we've found the beginning of a Talk Sequence
+ if ((f == TALK_SEQ_CODE && seq < 128) || (f == TALK_LISTEN_CODE && seq > 128)) {
+ --seq;
+
+ // See if we're at the correct Talk Sequence Number
+ if (!(seq & 127))
+ {
+ // Correct Sequence, Start Talking Here
+ if (_seqTo != 0)
+ _sequences[_frameNumber] = _seqTo;
+ _frameNumber = idx;
+ _seqTo = 0;
+ _seqStack = 0;
+ _seqCounter = 0;
+ _seqCounter2 = 0;
+ _talkSeq = talkSeqNum;
+ break;
+ }
+ } else {
+ // Move ahead any extra because of special control codes
+ switch (f) {
+ case 0: idx++; break;
+ case MOVE_CODE:
+ case TELEPORT_CODE: idx += 4; break;
+ case CALL_TALK_CODE: idx += 8; break;
+ case HIDE_CODE: idx += 2; break;
+ }
+ }
+
+ // See if we're out of sequence data
+ if (idx >= (int)_seqSize)
+ break;
+ }
+}
+
void Object::setFlagsAndToggles() {
Scene &scene = *_vm->_scene;
Talk &talk = *_vm->_talk;
@@ -983,7 +1310,22 @@ void Object::adjustObject() {
if (_type == REMOVE)
return;
- _position += _delta;
+ if (IS_ROSE_TATTOO && (_delta.x || _delta.y)) {
+ // The shape position is in pixels, and the delta is in fixed integer amounts
+ int t;
+ _noShapeSize.x += _delta.x;
+ t = _noShapeSize.x / (FIXED_INT_MULTIPLIER / 10);
+ _noShapeSize.x -= t * (FIXED_INT_MULTIPLIER / 10);
+ _position.x += t;
+
+ _noShapeSize.y += _delta.y;
+ t = _noShapeSize.y / (FIXED_INT_MULTIPLIER / 10);
+ _noShapeSize.y -= t * (FIXED_INT_MULTIPLIER / 10);
+ _position.y += t;
+ } else if (IS_SERRATED_SCALPEL) {
+ // The delta is in whole pixels, so simply adjust the position with it
+ _position += _delta;
+ }
if (_position.y > LOWER_LIMIT)
_position.y = LOWER_LIMIT;
@@ -1001,7 +1343,8 @@ void Object::adjustObject() {
}
}
-int Object::pickUpObject(const char *const messages[]) {
+int Object::pickUpObject(FixedTextActionId fixedTextActionId) {
+ FixedText &fixedText = *_vm->_fixedText;
Inventory &inv = *_vm->_inventory;
People &people = *_vm->_people;
Scene &scene = *_vm->_scene;
@@ -1014,7 +1357,7 @@ int Object::pickUpObject(const char *const messages[]) {
if (pickup == 99) {
for (int idx = 0; idx < NAMES_COUNT && !talk._talkToAbort; ++idx) {
- if (checkNameForCodes(_use[0]._names[idx], nullptr)) {
+ if (checkNameForCodes(_use[0]._names[idx], kFixedTextAction_Invalid)) {
if (!talk._talkToAbort)
printed = true;
}
@@ -1030,7 +1373,8 @@ int Object::pickUpObject(const char *const messages[]) {
ui._infoFlag = true;
ui.clearInfo();
- screen.print(Common::Point(0, INFO_LINE + 1), INFO_FOREGROUND, "%s", messages[message]);
+ Common::String errorMessage = fixedText.getActionMessage(fixedTextActionId, message);
+ screen.print(Common::Point(0, INFO_LINE + 1), COL_INFO_FOREGROUND, "%s", errorMessage.c_str());
ui._menuCounter = 30;
} else {
// Pick it up
@@ -1055,13 +1399,13 @@ int Object::pickUpObject(const char *const messages[]) {
} else {
// Play generic pickup sequence
// Original moved cursor position here
- people.goAllTheWay();
+ people[HOLMES].goAllTheWay();
ui._menuCounter = 25;
ui._temp1 = 1;
}
for (int idx = 0; idx < NAMES_COUNT && !talk._talkToAbort; ++idx) {
- if (checkNameForCodes(_use[0]._names[idx], nullptr)) {
+ if (checkNameForCodes(_use[0]._names[idx], kFixedTextAction_Invalid)) {
if (!talk._talkToAbort)
printed = true;
}
@@ -1079,7 +1423,7 @@ int Object::pickUpObject(const char *const messages[]) {
Common::String itemName = _description;
itemName.setChar(tolower(itemName[0]), 0);
- screen.print(Common::Point(0, INFO_LINE + 1), INFO_FOREGROUND, "Picked up %s", itemName.c_str());
+ screen.print(Common::Point(0, INFO_LINE + 1), COL_INFO_FOREGROUND, "Picked up %s", itemName.c_str());
ui._menuCounter = 25;
}
}
@@ -1088,7 +1432,7 @@ int Object::pickUpObject(const char *const messages[]) {
}
const Common::Rect Object::getNewBounds() const {
- Common::Point pt = _position;
+ Point32 pt = _position;
if (_imageFrame)
pt += _imageFrame->_offset;
@@ -1107,14 +1451,14 @@ const Common::Rect Object::getOldBounds() const {
/*----------------------------------------------------------------*/
-void CAnim::load(Common::SeekableReadStream &s, bool isRoseTattoo) {
+void CAnim::load(Common::SeekableReadStream &s, bool isRoseTattoo, uint32 dataOffset) {
char buffer[12];
s.read(buffer, 12);
_name = Common::String(buffer);
if (isRoseTattoo) {
Common::fill(&_sequences[0], &_sequences[30], 0);
- _size = s.readUint32LE();
+ _dataSize = s.readUint32LE();
} else {
s.read(_sequences, 30);
}
@@ -1126,33 +1470,85 @@ void CAnim::load(Common::SeekableReadStream &s, bool isRoseTattoo) {
_flags = s.readByte();
_scaleVal = s.readSint16LE();
} else {
- _size = s.readUint32LE();
+ _dataSize = s.readUint32LE();
_type = (SpriteType)s.readUint16LE();
_flags = s.readByte();
}
- _goto.x = s.readSint16LE();
- _goto.y = s.readSint16LE();
- _gotoDir = s.readSint16LE();
- _teleportPos.x = s.readSint16LE();
- _teleportPos.y = s.readSint16LE();
- _teleportDir = s.readSint16LE();
-}
+ _goto[0].x = s.readSint16LE();
+ _goto[0].y = s.readSint16LE();
+ _goto[0]._facing = s.readSint16LE();
+ ADJUST_COORD(_goto[0]);
-/*----------------------------------------------------------------*/
+ if (isRoseTattoo) {
+ // Get Goto position and facing for second NPC
+ _goto[1].x = s.readSint16LE();
+ _goto[1].y = s.readSint16LE();
+ _goto[1]._facing = s.readSint16LE();
+ ADJUST_COORD(_goto[1]);
+ } else if (_goto[0].x != -1) {
+ // For Serrated Scalpel, adjust the loaded co-ordinates
+ _goto[0].x = _goto[0].x / 100;
+ _goto[0].y = _goto[0].y / 100;
+ }
-CAnimStream::CAnimStream() {
- _stream = nullptr;
- _frameSize = 0;
- _images = nullptr;
- _imageFrame = nullptr;
- _flags = 0;
- _scaleVal = 0;
- _zPlacement = 0;
+ _teleport[0].x = s.readSint16LE();
+ _teleport[0].y = s.readSint16LE();
+ _teleport[0]._facing = s.readSint16LE();
+ ADJUST_COORD(_teleport[0]);
+
+ if (isRoseTattoo) {
+ // Get Teleport position and facing for second NPC
+ _teleport[1].x = s.readSint16LE();
+ _teleport[1].y = s.readSint16LE();
+ _teleport[1]._facing = s.readSint16LE();
+ ADJUST_COORD(_teleport[1]);
+ } else if (_teleport[0].x != -1) {
+ // For Serrated Scalpel, adjust the loaded co-ordinates
+ _teleport[0].x = _teleport[0].x / 100;
+ _teleport[0].y = _teleport[0].y / 100;
+ }
+
+ // Save offset of data, which is actually inside another table inside the room data file
+ // This table is at offset 44 for Serrated Scalpel
+ // TODO: find it for the other game
+ _dataOffset = dataOffset;
}
-void CAnimStream::getNextFrame() {
- // TODO
+void CAnim::load3DO(Common::SeekableReadStream &s, uint32 dataOffset) {
+ // this got reordered on 3DO
+ // maybe it was the 3DO compiler
+
+ _dataSize = s.readUint32BE();
+ // Save offset of data, which is inside another table inside the room data file
+ _dataOffset = dataOffset;
+
+ _position.x = s.readSint16BE();
+ _position.y = s.readSint16BE();
+
+ _type = (SpriteType)s.readUint16BE();
+
+ _goto[0].x = s.readSint16BE();
+ _goto[0].y = s.readSint16BE();
+ _goto[0]._facing = s.readSint16BE();
+
+ _teleport[0].x = s.readSint16BE();
+ _teleport[0].y = s.readSint16BE();
+ _teleport[0]._facing = s.readSint16BE();
+
+ char buffer[12];
+ s.read(buffer, 12);
+ _name = Common::String(buffer);
+
+ s.read(_sequences, 30);
+ _flags = s.readByte();
+
+ s.skip(3); // Filler
+
+ _goto[0].x = _goto[0].x * FIXED_INT_MULTIPLIER / 100;
+ _goto[0].y = _goto[0].y * FIXED_INT_MULTIPLIER / 100;
+ _teleport[0].x = _teleport[0].x * FIXED_INT_MULTIPLIER / 100;
+ _teleport[0].y = _teleport[0].y * FIXED_INT_MULTIPLIER / 100;
}
/*----------------------------------------------------------------*/
diff --git a/engines/sherlock/objects.h b/engines/sherlock/objects.h
index d671066a23..38b02aeae8 100644
--- a/engines/sherlock/objects.h
+++ b/engines/sherlock/objects.h
@@ -27,7 +27,9 @@
#include "common/rect.h"
#include "common/str-array.h"
#include "common/str.h"
-#include "sherlock/resources.h"
+#include "sherlock/image_file.h"
+#include "sherlock/fixed_text.h"
+#include "sherlock/saveload.h"
namespace Sherlock {
@@ -76,12 +78,26 @@ enum {
#define MAX_HOLMES_SEQUENCE 16
#define MAX_FRAME 30
-#define FIXED_INT_MULTIPLIER 100
+#define FIXED_INT_MULTIPLIER 1000
// code put into sequences to defines 1-10 type seqs
#define SEQ_TO_CODE 67
#define FLIP_CODE (64 + 128)
#define SOUND_CODE (34 + 128)
+#define HIDE_CODE (7+128) // Code for hiding/unhiding an object from a Sequence
+#define CALL_TALK_CODE (8+128) // Code for call a Talk File from a Sequence
+#define TELEPORT_CODE (9+128) // Code for setting Teleport Data (X,Y)
+#define MOVE_CODE (10+128) // Code for setting Movement Delta (X,Y)
+
+#define GOTO_CODE 228
+#define TALK_SEQ_CODE 252 // Code specifying start of talk sequence frames in a Sequence
+#define TALK_LISTEN_CODE 251 // Code specifying start of talk listen frames in a Sequence
+#define ALLOW_TALK_CODE 250
+
+#define UPPER_LIMIT 0
+#define LOWER_LIMIT (IS_SERRATED_SCALPEL ? CONTROLS_Y : SHERLOCK_SCREEN_HEIGHT)
+#define LEFT_LIMIT 0
+#define RIGHT_LIMIT SHERLOCK_SCREEN_WIDTH
class Point32 {
public:
@@ -102,6 +118,17 @@ public:
void operator-=(const Point32 &delta) { x -= delta.x; y -= delta.y; }
};
+class PositionFacing : public Point32 {
+public:
+ int _facing;
+
+ PositionFacing() : Point32(), _facing(0) {}
+ PositionFacing(int xp, int yp, int theFacing) : Point32(xp, yp), _facing(theFacing) {}
+ PositionFacing &operator=(const Point32 &pt) {
+ x = pt.x; y = pt.y;
+ return *this;
+ }
+};
struct WalkSequence {
Common::String _vgsName;
@@ -129,6 +156,9 @@ struct ActionType {
int _cAnimNum;
int _cAnimSpeed;
Common::String _names[NAMES_COUNT];
+ int _useFlag; // Which flag USE will set (if any)
+
+ ActionType();
/**
* Load the data for the action
@@ -136,11 +166,7 @@ struct ActionType {
void load(Common::SeekableReadStream &s);
};
-struct UseType {
- int _cAnimNum;
- int _cAnimSpeed;
- Common::String _names[NAMES_COUNT];
- int _useFlag; // Which flag USE will set (if any)
+struct UseType: public ActionType {
Common::String _target;
Common::String _verb;
@@ -150,66 +176,129 @@ struct UseType {
* Load the data for the UseType
*/
void load(Common::SeekableReadStream &s, bool isRoseTattoo);
-};
+ void load3DO(Common::SeekableReadStream &s);
+ /**
+ * Synchronize the data for a savegame
+ */
+ void synchronize(Serializer &s);
+};
-class Sprite {
-private:
+class BaseObject {
+protected:
static SherlockEngine *_vm;
+protected:
+ /**
+ * This will check to see if the object has reached the end of a sequence.
+ * If it has, it switch to whichever next sequence should be started.
+ * @returns true if the end of a sequence was reached
+ */
+ bool checkEndOfSequence();
+
+ /**
+ * Scans through the sequences array and finds the designated sequence.
+ * It then sets the frame number of the start of that sequence
+ */
+ void setObjSequence(int seq, bool wait);
+public:
+ static bool _countCAnimFrames;
+public:
+ SpriteType _type; // Type of object/sprite
+ Common::String _description; // Description lines
+ byte *_sequences; // Holds animation sequences
+ ImageFile *_images; // Sprite images
+ ImageFrame *_imageFrame; // Pointer to shape in the images
+ int _sequenceNumber; // Sequence being used
+ int _startSeq; // Frame sequence starts at
+ int _walkCount; // Walk counter
+ int _allow; // Allowed UI commands
+ int _frameNumber; // Frame number in rame sequence to draw
+ Point32 _position; // Current position
+ Point32 _delta; // Momvement amount
+ Common::Point _oldPosition; // Old position
+ Common::Point _oldSize; // Image's old size
+ Point32 _goto; // Walk destination
+
+ int _lookFlag; // Which flag LOOK will set (if any)
+ int _requiredFlag[2]; // Object will be hidden if not set
+ Common::Point _noShapeSize; // Size of a NO_SHAPE
+ int _status; // Status (open/closed, moved/not)
+ int8 _misc; // Misc field -- use varies with type
+ int _maxFrames; // Number of frames
+ int _flags; // Tells if object can be walked behind
+ AType _aType; // Tells if this is an object, person, talk, etc.
+ int _lookFrames; // How many frames to play of the look anim before pausing
+ int _seqCounter; // How many times this sequence has been executed
+ PositionFacing _lookPosition; // Where to walk when examining object
+ int _lookcAnim;
+ int _seqStack; // Allows gosubs to return to calling frame
+ int _seqTo; // Allows 1-5, 8-3 type sequences encoded in 2 bytes
+ uint _descOffset; // Tells where description starts in DescText
+ int _seqCounter2; // Counter of calling frame sequence
+ uint _seqSize; // Tells where description starts
+ UseType _use[6]; // Serrated Scalpel uses 4, Rose Tattoo 6
+ int _quickDraw; // Flag telling whether to use quick draw routine or not
+ int _scaleVal; // Tells how to scale the sprite
+ int _gotoSeq; // Used by Talk to tell which sequence to goto when able
+ int _talkSeq; // Tells which talk sequence currently in use (Talk or Listen)
+ int _restoreSlot; // Used when talk returns to the previous sequence
+public:
+ BaseObject();
+ virtual ~BaseObject() {}
+ static void setVm(SherlockEngine *vm);
+
+ /**
+ * Returns true if the the object has an Allow Talk Code in the sequence that it's
+ * currently running, specified by the _talkSeq field of the object. If it's 0,
+ * then it's a regular sequence. If it's not 0 but below 128, then it's a Talk Sequence.
+ * If it's above 128, then it's one of the Listen sequences.
+ */
+ bool hasAborts() const;
+
+ /**
+ * Check the state of the object
+ */
+ void checkObject();
+
+ /**
+ * Checks for codes
+ * @param name The name to check for codes
+ * @param messages Provides a lookup list of messages that can be printed
+ * @returns 0 if no codes are found, 1 if codes were found
+ */
+ int checkNameForCodes(const Common::String &name, FixedTextActionId fixedTextActionId = kFixedTextAction_Invalid);
+
+ /**
+ * Adjusts the frame and sequence variables of a sprite that corresponds to the current speaker
+ * so that it points to the beginning of the sequence number's talk sequence in the object's
+ * sequence buffer
+ * @param seq Which sequence to use (if there's more than 1)
+ * @remarks 1: First talk seq, 2: second talk seq, etc.
+ */
+ virtual void setObjTalkSequence(int seq) {}
+};
+
+class Sprite: public BaseObject {
public:
Common::String _name;
- Common::String _description;
Common::String _examine; // Examine in-depth description
Common::String _pickUp; // Message for if you can't pick up object
WalkSequences _walkSequences; // Holds animation sequences
- ImageFile *_images; // Sprite images
- ImageFrame *_imageFrame; // Pointer to shape in the images
- int _walkCount; // Character walk counter
- int _allow; // Allowed menu commands - ObjectAllow
- int _frameNumber; // Frame number in rame sequence to draw
- int _sequenceNumber; // Sequence being used
- Point32 _position; // Current position
- Point32 _delta; // Momvement delta
- Common::Point _oldPosition; // Old position
- Common::Point _oldSize; // Image's old size
- Common::Point _goto; // Walk destination
- SpriteType _type; // Type of object
Common::Point _noShapeSize; // Size of a NO_SHAPE
int _status; // Status: open/closed, moved/not moved
int8 _misc; // Miscellaneous use
- int _numFrames; // How many frames the object has
// Rose Tattoo fields
- int _startSeq; // Frame sequence starts at
- int _flags; // Flags for the sprite
- int _aType; // Tells if this is an object, person, talk, etc.
- int _lookFrames; // How many frames to play of a canim before pausing
- int _seqCounter; // How many times the sequence has been run
- Common::Point _lookPosition; // Where to look when examining object
- int _lookFacing; // Direction to face when examining object
- int _lookCAnim;
- int _seqStack; // Allow gosubs to return to calling frame
- int _seqTo; // Allows 1-5, 8-3 type sequences encoded in 2 bytes
- uint _descOffset; // Tells where description starts in description text for scene
- int _seqCounter2; // Counter of calling frame sequence
- uint _seqSize; // Size of sequence
- UseType _use[6];
- int _quickDraw; // Flag telling whether to use quick draw routine or not
- int _scaleVal; // Tells how to scale the sprite
- int _requiredFlags1; // This flag must also be set, or the sprite is hidden
- int _gotoSeq; // Used by Talk to tell which sequence to goto when able
- int _talkSeq; // Tells which talk sequence currently in use (Talk or Listen)
- int _restoreSlot; // Used when talk returns to the previous sequence
-
ImageFrame *_stopFrames[8]; // Stop/rest frame for each direction
ImageFile *_altImages; // Images used for alternate NPC sequences
- bool _altSequences; // Which of the sequences the alt graphics apply to (0: main, 1=NPC seq)
+ int _altSeq; // Which of the sequences the alt graphics apply to (0: main, 1=NPC seq)
int _centerWalk; // Flag telling the walk code to offset the walk destination
Common::Point _adjust; // Fine tuning adjustment to position when drawn
int _oldWalkSequence;
public:
- Sprite() { clear(); }
+ Sprite(): BaseObject() { clear(); }
+ virtual ~Sprite() {}
static void setVm(SherlockEngine *vm) { _vm = vm; }
@@ -224,16 +313,20 @@ public:
void setImageFrame();
/**
- * This adjusts the sprites position, as well as it's animation sequence:
- */
- void adjustSprite();
-
- /**
* Checks the sprite's position to see if it's collided with any special objects
*/
void checkSprite();
/**
+ * Adjusts the frame and sequence variables of a sprite that corresponds to the current speaker
+ * so that it points to the beginning of the sequence number's talk sequence in the object's
+ * sequence buffer
+ * @param seq Which sequence to use (if there's more than 1)
+ * @remarks 1: First talk seq, 2: second talk seq, etc.
+ */
+ virtual void setObjTalkSequence(int seq) {}
+
+ /**
* Return frame width
*/
int frameWidth() const { return _imageFrame ? _imageFrame->_frame.w : 0; }
@@ -242,71 +335,39 @@ public:
* Return frame height
*/
int frameHeight() const { return _imageFrame ? _imageFrame->_frame.h : 0; }
-};
-enum { OBJ_BEHIND = 1, OBJ_FLIPPED = 2, OBJ_FORWARD = 4, TURNON_OBJ = 0x20, TURNOFF_OBJ = 0x40 };
-#define USE_COUNT 4
+ /**
+ * Returns the old bounsd for the sprite from the previous frame
+ */
+ const Common::Rect getOldBounds() const;
-class Object {
-private:
- static SherlockEngine *_vm;
+ /**
+ * This adjusts the sprites position, as well as it's animation sequence:
+ */
+ virtual void adjustSprite() = 0;
/**
- * This will check to see if the object has reached the end of a sequence.
- * If it has, it switch to whichever next sequence should be started.
- * @returns true if the end of a sequence was reached
+ * Bring a moving character using the sprite to a standing position
*/
- bool checkEndOfSequence();
+ virtual void gotoStand() = 0;
/**
- * Scans through the sequences array and finds the designated sequence.
- * It then sets the frame number of the start of that sequence
+ * Set the variables for moving a character from one poisition to another
+ * in a straight line
*/
- void setObjSequence(int seq, bool wait);
-public:
- static bool _countCAnimFrames;
+ virtual void setWalking() = 0;
+};
- static void setVm(SherlockEngine *vm);
+enum { OBJ_BEHIND = 1, OBJ_FLIPPED = 2, OBJ_FORWARD = 4, TURNON_OBJ = 0x20, TURNOFF_OBJ = 0x40 };
+#define USE_COUNT 4
+
+class Object: public BaseObject {
public:
Common::String _name; // Name
- Common::String _description; // Description lines
Common::String _examine; // Examine in-depth description
int _sequenceOffset;
- uint8 *_sequences; // Holds animation sequences
- ImageFile *_images; // Sprite images
- ImageFrame *_imageFrame; // Pointer to shape in the images
- int _walkCount; // Character walk counter
- int _allow; // Allowed menu commands - ObjectAllow
- int _frameNumber; // Frame number in rame sequence to draw
- int _sequenceNumber; // Sequence being used
- SpriteType _type; // Object type
- Common::Point _position; // Current position
- Common::Point _delta; // Momvement amount
- Common::Point _oldPosition; // Old position
- Common::Point _oldSize; // Image's old size
- Common::Point _goto; // Walk destination
-
int _pickup;
int _defaultCommand; // Default right-click command
- int _lookFlag; // Which flag LOOK will set (if any)
- int _requiredFlag; // Object will be hidden if not set
- Common::Point _noShapeSize; // Size of a NO_SHAPE
- int _status; // Status (open/closed, moved/not)
- int8 _misc; // Misc field -- use varies with type
- int _maxFrames; // Number of frames
- int _flags; // Tells if object can be walked behind
- AType _aType; // Tells if this is an object, person, talk, etc.
- int _lookFrames; // How many frames to play of the look anim before pausing
- int _seqCounter; // How many times this sequence has been executed
- Common::Point _lookPosition; // Where to walk when examining object
- int _lookFacing; // Direction to face when examining object
- int _lookcAnim;
- int _seqStack; // Allows gosubs to return to calling frame
- int _seqTo; // Allows 1-5, 8-3 type sequences encoded in 2 bytes
- uint _descOffset; // Tells where description starts in DescText
- int _seqCounter2; // Counter of calling frame sequence
- uint _seqSize; // Tells where description starts
- UseType _use[6]; // Serrated Scalpel uses 4, Rose Tattoo 6
// Serrated Scalpel fields
int _pickupFlag; // Which flag PICKUP will set (if any)
@@ -314,20 +375,14 @@ public:
ActionType _aClose;
ActionType _aMove;
- // Rose Tattoo fields
- int _quickDraw;
- int _scaleVal;
- int _requiredFlag1;
- int _gotoSeq;
- int _talkSeq;
- int _restoreSlot;
-
Object();
+ virtual ~Object() {}
/**
* Load the data for the object
*/
void load(Common::SeekableReadStream &s, bool isRoseTattoo);
+ void load3DO(Common::SeekableReadStream &s);
/**
* Toggle the type of an object between hidden and active
@@ -335,19 +390,6 @@ public:
void toggleHidden();
/**
- * Check the state of the object
- */
- void checkObject();
-
- /**
- * Checks for codes
- * @param name The name to check for codes
- * @param messages Provides a lookup list of messages that can be printed
- * @returns 0 if no codes are found, 1 if codes were found
- */
- int checkNameForCodes(const Common::String &name, const char *const messages[]);
-
- /**
* Handle setting any flags associated with the object
*/
void setFlagsAndToggles();
@@ -362,13 +404,13 @@ public:
* Handles trying to pick up an object. If allowed, plays an y necessary animation for picking
* up the item, and then adds it to the player's inventory
*/
- int pickUpObject(const char *const messages[]);
+ int pickUpObject(FixedTextActionId fixedTextActionId = kFixedTextAction_Invalid);
/**
* Return the frame width
*/
int frameWidth() const { return _imageFrame ? _imageFrame->_frame.w : 0; }
-
+
/**
* Return the frame height
*/
@@ -388,17 +430,25 @@ public:
* Returns the old bounsd for the sprite from the previous frame
*/
const Common::Rect getOldBounds() const;
+
+ /**
+ * Adjusts the frame and sequence variables of a sprite that corresponds to the current speaker
+ * so that it points to the beginning of the sequence number's talk sequence in the object's
+ * sequence buffer
+ * @param seq Which sequence to use (if there's more than 1)
+ * @remarks 1: First talk seq, 2: second talk seq, etc.
+ */
+ virtual void setObjTalkSequence(int seq);
};
struct CAnim {
Common::String _name; // Name
Common::Point _position; // Position
- int _size; // Size of uncompressed animation
+ int _dataSize; // Size of uncompressed animation data
+ uint32 _dataOffset; // offset within room file of animation data
int _flags; // Tells if can be walked behind
- Common::Point _goto; // coords holmes should walk to before starting canim
- int _gotoDir;
- Common::Point _teleportPos; // Location Holmes shoul teleport to after
- int _teleportDir; // playing canim
+ PositionFacing _goto[2]; // Position Holmes (and NPC in Rose Tattoo) should walk to before anim starts
+ PositionFacing _teleport[2]; // Location Holmes (and NPC) shoul teleport to after playing canim
// Scalpel specific
byte _sequences[MAX_FRAME]; // Animation sequences
@@ -410,27 +460,8 @@ struct CAnim {
/**
* Load the data for the animation
*/
- void load(Common::SeekableReadStream &s, bool isRoseTattoo);
-};
-
-struct CAnimStream {
- Common::SeekableReadStream *_stream; // Stream to read frames from
- int _frameSize; // Temporary used to store the frame size
-
- void *_images; // TOOD: FIgure out hwo to hook up ImageFile with streaming support
- ImageFrame *_imageFrame;
-
- Common::Point _position; // Animation position
- Common::Rect _oldBounds; // Bounds of previous frame
- Common::Rect _removeBounds; // Remove area for just drawn frame
-
- int _flags; // Flags
- int _scaleVal; // Specifies the scale amount
- int _zPlacement; // Used by doBgAnim for determining Z order
-
- CAnimStream();
-
- void getNextFrame();
+ void load(Common::SeekableReadStream &s, bool isRoseTattoo, uint32 dataOffset);
+ void load3DO(Common::SeekableReadStream &s, uint32 dataOffset);
};
struct SceneImage {
diff --git a/engines/sherlock/people.cpp b/engines/sherlock/people.cpp
index 0ef49ffefb..b1f4abba47 100644
--- a/engines/sherlock/people.cpp
+++ b/engines/sherlock/people.cpp
@@ -22,14 +22,11 @@
#include "sherlock/people.h"
#include "sherlock/sherlock.h"
+#include "sherlock/scalpel/scalpel_people.h"
+#include "sherlock/tattoo/tattoo_people.h"
namespace Sherlock {
-// Walk speeds
-#define MWALK_SPEED 2
-#define XWALK_SPEED 4
-#define YWALK_SPEED 1
-
// Characer animation sequences
static const uint8 CHARACTER_SEQUENCES[MAX_HOLMES_SEQUENCE][MAX_FRAME] = {
{ 29, 1, 2, 3, 4, 5, 6, 7, 0 }, // Walk Right
@@ -52,8 +49,7 @@ static const uint8 CHARACTER_SEQUENCES[MAX_HOLMES_SEQUENCE][MAX_FRAME] = {
// Rose Tattoo walk image libraries
// Walk resources within WALK.LIB
-#define NUM_IN_WALK_LIB 10
-const char *const WALK_LIB_NAMES[10] = {
+const char *const WALK_LIB_NAMES[NUM_IN_WALK_LIB] = {
"SVGAWALK.VGS",
"COATWALK.VGS",
"WATSON.VGS",
@@ -68,34 +64,97 @@ const char *const WALK_LIB_NAMES[10] = {
/*----------------------------------------------------------------*/
-Person::Person() : Sprite(), _walkLoaded(false), _npcIndex(0), _npcStack(0), _npcPause(false) {
- Common::fill(&_npcPath[0], &_npcPath[MAX_NPC_PATH], 0);
- _tempX = _tempScaleVal = 0;
+Person::Person() : Sprite() {
+ _walkLoaded = false;
+ _oldWalkSequence = -1;
+ _srcZone = _destZone = 0;
}
-void Person::clearNPC() {
- Common::fill(&_npcPath[0], &_npcPath[MAX_NPC_PATH], 0);
- _npcIndex = _npcStack = 0;
- _npcName = "";
+void Person::goAllTheWay() {
+ Scene &scene = *_vm->_scene;
+ Common::Point srcPt = getSourcePoint();
+
+ // Get the zone the player is currently in
+ _srcZone = scene.whichZone(srcPt);
+ if (_srcZone == -1)
+ _srcZone = scene.closestZone(srcPt);
+
+ // Get the zone of the destination
+ _destZone = scene.whichZone(_walkDest);
+ if (_destZone == -1) {
+ _destZone = scene.closestZone(_walkDest);
+
+ // Check for any restriction of final destination position
+ _walkDest = _vm->_people->restrictToZone(_destZone, _walkDest);
+ }
+
+ // Only do a walk if both zones are acceptable
+ if (_srcZone == -2 || _destZone == -2)
+ return;
+
+ // If the start and dest zones are the same, walk directly to the dest point
+ if (_srcZone == _destZone) {
+ setWalking();
+ } else {
+ // Otherwise a path needs to be formed from the path information
+ int i = scene._walkDirectory[_srcZone][_destZone];
+
+ // See if we need to use a reverse path
+ if (i == -1)
+ i = scene._walkDirectory[_destZone][_srcZone];
+
+ const WalkArray &points = scene._walkPoints[i];
+
+ // See how many points there are between the src and dest zones
+ if (!points._pointsCount || points._pointsCount == -1) {
+ // There are none, so just walk to the new zone
+ setWalking();
+ } else {
+ // There are points, so set up a multi-step path between points
+ // to reach the given destination
+ _walkTo.clear();
+
+ if (scene._walkDirectory[_srcZone][_destZone] != -1) {
+ for (int idx = (int)points.size() - 1; idx >= 0; --idx)
+ _walkTo.push(points[idx]);
+ } else {
+ for (int idx = 0; idx < (int)points.size(); ++idx) {
+ _walkTo.push(points[idx]);
+ }
+ }
+
+ // Final position
+ _walkTo.push(_walkDest);
+
+ // Start walking
+ _walkDest = _walkTo.pop();
+ setWalking();
+ }
+ }
}
/*----------------------------------------------------------------*/
-People::People(SherlockEngine *vm) : _vm(vm), _player(_data[0]) {
+People *People::init(SherlockEngine *vm) {
+ if (vm->getGameID() == GType_SerratedScalpel)
+ return new Scalpel::ScalpelPeople(vm);
+ else
+ return new Tattoo::TattooPeople(vm);
+}
+
+People::People(SherlockEngine *vm) : _vm(vm) {
_holmesOn = true;
- _oldWalkSequence = -1;
- _allowWalkAbort = false;
+ _allowWalkAbort = true;
_portraitLoaded = false;
_portraitsOn = true;
_clearingThePortrait = false;
- _srcZone = _destZone = 0;
_talkPics = nullptr;
_portraitSide = 0;
_speakerFlip = false;
_holmesFlip = false;
_holmesQuotient = 0;
- _hSavedPos = Common::Point(-1, -1);
- _hSavedFacing = -1;
+ _savedPos = Point32(-1, -1);
+ _savedPos._facing = -1;
_forceWalkReload = false;
_useWalkLib = false;
_walkControl = 0;
@@ -104,9 +163,10 @@ People::People(SherlockEngine *vm) : _vm(vm), _player(_data[0]) {
}
People::~People() {
- for (int idx = 0; idx < MAX_CHARACTERS; ++idx) {
- if (_data[idx]._walkLoaded)
- delete _data[PLAYER]._images;
+ for (uint idx = 0; idx < _data.size(); ++idx) {
+ if (_data[idx]->_walkLoaded)
+ delete _data[idx]->_images;
+ delete _data[idx];
}
delete _talkPics;
@@ -114,27 +174,33 @@ People::~People() {
}
void People::reset() {
- _data[0]._description = "Sherlock Holmes!";
+ SaveManager &saves = *_vm->_saves;
+ Talk &talk = *_vm->_talk;
+ _data[HOLMES]->_description = "Sherlock Holmes!";
// Note: Serrated Scalpel only uses a single Person slot for Sherlock.. Watson is handled by scene sprites
int count = IS_SERRATED_SCALPEL ? 1 : MAX_CHARACTERS;
for (int idx = 0; idx < count; ++idx) {
- Sprite &p = _data[idx];
+ Person &p = *_data[idx];
- p._type = (idx == 0) ? CHARACTER : INVALID;
- if (IS_SERRATED_SCALPEL)
- p._position = Point32(10000, 11000);
- else
- p._position = Point32(36000, 29000);
+ if (IS_SERRATED_SCALPEL) {
+ p._type = CHARACTER;
+ 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);
+ p._use[0]._verb = "";
+ p._use[1]._verb = "";
+ }
- p._sequenceNumber = STOP_DOWNRIGHT;
+ p._sequenceNumber = IS_SERRATED_SCALPEL ? (int)Scalpel::STOP_DOWNRIGHT : (int)Tattoo::STOP_DOWNRIGHT;
p._imageFrame = nullptr;
p._frameNumber = 1;
- p._delta = Common::Point(0, 0);
+ p._startSeq = 0;
+ p._delta = Point32(0, 0);
p._oldPosition = Common::Point(0, 0);
p._oldSize = Common::Point(0, 0);
p._misc = 0;
- p._walkCount = 0;
p._pickUp = "";
p._allow = 0;
p._noShapeSize = Common::Point(0, 0);
@@ -147,11 +213,13 @@ void People::reset() {
p._restoreSlot = 0;
p._startSeq = 0;
p._altImages = nullptr;
- p._altSequences = 0;
+ p._altSeq = 0;
p._centerWalk = true;
p._adjust = Common::Point(0, 0);
// Load the default walk sequences
+ p._walkCount = 0;
+ p._walkTo.clear();
p._oldWalkSequence = -1;
p._walkSequences.clear();
if (IS_SERRATED_SCALPEL) {
@@ -166,93 +234,17 @@ void People::reset() {
}
}
}
-
- // Reset any walk path in progress when Sherlock leaves scenes
- _walkTo.clear();
-}
-
-bool People::loadWalk() {
- Resources &res = *_vm->_res;
- bool result = false;
-
- if (IS_SERRATED_SCALPEL) {
- if (_data[PLAYER]._walkLoaded) {
- return false;
- } else {
- _data[PLAYER]._images = new ImageFile("walk.vgs");
- _data[PLAYER].setImageFrame();
- _data[PLAYER]._walkLoaded = true;
-
- result = true;
- }
- } else {
- for (int idx = 0; idx < MAX_CHARACTERS; ++idx) {
- if (!_data[idx]._walkLoaded && (_data[idx]._type == CHARACTER || _data[idx]._type == HIDDEN_CHARACTER)) {
- if (_data[idx]._type == HIDDEN_CHARACTER)
- _data[idx]._type = INVALID;
-
- // See if this is one of the more used Walk Graphics stored in WALK.LIB
- for (int libNum = 0; libNum < NUM_IN_WALK_LIB; ++libNum) {
- if (!_data[0]._walkVGSName.compareToIgnoreCase(WALK_LIB_NAMES[libNum])) {
- _useWalkLib = true;
- break;
- }
- }
-
- // Load the images for the character
- _data[idx]._images = new ImageFile(_data[idx]._walkVGSName, false);
- _data[idx]._numFrames = _data[idx]._images->size();
-
- // Load walk sequence data
- Common::String fname = Common::String(_data[idx]._walkVGSName.c_str(), strchr(_data[idx]._walkVGSName.c_str(), '.'));
- fname += ".SEQ";
-
- // Load the walk sequence data
- Common::SeekableReadStream *stream = res.load(fname, _useWalkLib ? "walk.lib" : "vgs.lib");
-
- _data[idx]._walkSequences.resize(stream->readByte());
-
- for (uint seqNum = 0; seqNum < _data[idx]._walkSequences.size(); ++seqNum)
- _data[idx]._walkSequences[seqNum].load(*stream);
-
- // Close the sequences resource
- delete stream;
- _useWalkLib = false;
-
- _data[idx]._frameNumber = 0;
- _data[idx].setImageFrame();
-
- // Set the stop Frames pointers
- for (int dirNum = 0; dirNum < 8; ++dirNum) {
- int count = 0;
- while (_data[idx]._walkSequences[dirNum + 8][count] != 0)
- ++count;
- count += 2;
- count = _data[idx]._walkSequences[dirNum + 8][count] - 1;
- _data[idx]._stopFrames[dirNum] = &(*_data[idx]._images)[count];
- }
-
- result = true;
- _data[idx]._walkLoaded = true;
- } else if (_data[idx]._type != CHARACTER) {
- _data[idx]._walkLoaded = false;
- }
- }
- }
-
- _forceWalkReload = false;
- return result;
}
bool People::freeWalk() {
bool result = false;
for (int idx = 0; idx < MAX_CHARACTERS; ++idx) {
- if (_data[idx]._walkLoaded) {
- delete _data[idx]._images;
- _data[idx]._images = nullptr;
+ if (_data[idx]->_walkLoaded) {
+ delete _data[idx]->_images;
+ _data[idx]->_images = nullptr;
- _data[idx]._walkLoaded = false;
+ _data[idx]->_walkLoaded = false;
result = true;
}
}
@@ -260,322 +252,9 @@ bool People::freeWalk() {
return result;
}
-void People::setWalking() {
- Map &map = *_vm->_map;
- Scene &scene = *_vm->_scene;
- int oldDirection, oldFrame;
- Common::Point speed, delta;
-
- // Flag that player has now walked in the scene
- scene._walkedInScene = true;
-
- // Stop any previous walking, since a new dest is being set
- _player._walkCount = 0;
- oldDirection = _player._sequenceNumber;
- oldFrame = _player._frameNumber;
-
- // Set speed to use horizontal and vertical movement
- if (map._active) {
- speed = Common::Point(MWALK_SPEED, MWALK_SPEED);
- } else {
- speed = Common::Point(XWALK_SPEED, YWALK_SPEED);
- }
-
- // If the player is already close to the given destination that no
- // walking is needed, move to the next straight line segment in the
- // overall walking route, if there is one
- for (;;) {
- // Since we want the player to be centered on the destination they
- // clicked, but characters draw positions start at their left, move
- // the destination half the character width to draw him centered
- int temp;
- if (_walkDest.x >= (temp = _player._imageFrame->_frame.w / 2))
- _walkDest.x -= temp;
-
- delta = Common::Point(
- ABS(_player._position.x / 100 - _walkDest.x),
- ABS(_player._position.y / 100 - _walkDest.y)
- );
-
- // If we're ready to move a sufficient distance, that's it. Otherwise,
- // move onto the next portion of the walk path, if there is one
- if ((delta.x > 3 || delta.y > 0) || _walkTo.empty())
- break;
-
- // Pop next walk segment off the walk route stack
- _walkDest = _walkTo.pop();
- }
-
- // If a sufficient move is being done, then start the move
- if (delta.x > 3 || delta.y) {
- // See whether the major movement is horizontal or vertical
- if (delta.x >= delta.y) {
- // Set the initial frame sequence for the left and right, as well
- // as setting the delta x depending on direction
- if (_walkDest.x < (_player._position.x / 100)) {
- _player._sequenceNumber = (map._active ? (int)MAP_LEFT : (int)WALK_LEFT);
- _player._delta.x = speed.x * -100;
- } else {
- _player._sequenceNumber = (map._active ? (int)MAP_RIGHT : (int)WALK_RIGHT);
- _player._delta.x = speed.x * 100;
- }
-
- // See if the x delta is too small to be divided by the speed, since
- // this would cause a divide by zero error
- if (delta.x >= speed.x) {
- // Det the delta y
- _player._delta.y = (delta.y * 100) / (delta.x / speed.x);
- if (_walkDest.y < (_player._position.y / 100))
- _player._delta.y = -_player._delta.y;
-
- // Set how many times we should add the delta to the player's position
- _player._walkCount = delta.x / speed.x;
- } else {
- // The delta x was less than the speed (ie. we're really close to
- // the destination). So set delta to 0 so the player won't move
- _player._delta = Common::Point(0, 0);
- _player._position = Common::Point(_walkDest.x * 100, _walkDest.y * 100);
- _player._walkCount = 1;
- }
-
- // See if the sequence needs to be changed for diagonal walking
- if (_player._delta.y > 150) {
- if (!map._active) {
- switch (_player._sequenceNumber) {
- case WALK_LEFT:
- _player._sequenceNumber = WALK_DOWNLEFT;
- break;
- case WALK_RIGHT:
- _player._sequenceNumber = WALK_DOWNRIGHT;
- break;
- }
- }
- } else if (_player._delta.y < -150) {
- if (!map._active) {
- switch (_player._sequenceNumber) {
- case WALK_LEFT:
- _player._sequenceNumber = WALK_UPLEFT;
- break;
- case WALK_RIGHT:
- _player._sequenceNumber = WALK_UPRIGHT;
- break;
- }
- }
- }
- } else {
- // Major movement is vertical, so set the sequence for up and down,
- // and set the delta Y depending on the direction
- if (_walkDest.y < (_player._position.y / 100)) {
- _player._sequenceNumber = WALK_UP;
- _player._delta.y = speed.y * -100;
- } else {
- _player._sequenceNumber = WALK_DOWN;
- _player._delta.y = speed.y * 100;
- }
-
- // If we're on the overhead map, set the sequence so we keep moving
- // in the same direction
- if (map._active)
- _player._sequenceNumber = (oldDirection == -1) ? MAP_RIGHT : oldDirection;
-
- // Set the delta x
- _player._delta.x = (delta.x * 100) / (delta.y / speed.y);
- if (_walkDest.x < (_player._position.x / 100))
- _player._delta.x = -_player._delta.x;
-
- _player._walkCount = delta.y / speed.y;
- }
- }
-
- // See if the new walk sequence is the same as the old. If it's a new one,
- // we need to reset the frame number to zero so it's animation starts at
- // it's beginning. Otherwise, if it's the same sequence, we can leave it
- // as is, so it keeps the animation going at wherever it was up to
- if (_player._sequenceNumber != _oldWalkSequence)
- _player._frameNumber = 0;
- _oldWalkSequence = _player._sequenceNumber;
-
- if (!_player._walkCount)
- gotoStand(_player);
-
- // If the sequence is the same as when we started, then Holmes was
- // standing still and we're trying to re-stand him, so reset Holmes'
- // rame to the old frame number from before it was reset to 0
- if (_player._sequenceNumber == oldDirection)
- _player._frameNumber = oldFrame;
-}
-
-void People::gotoStand(Sprite &sprite) {
- Map &map = *_vm->_map;
- _walkTo.clear();
- sprite._walkCount = 0;
-
- switch (sprite._sequenceNumber) {
- case WALK_UP:
- sprite._sequenceNumber = STOP_UP;
- break;
- case WALK_DOWN:
- sprite._sequenceNumber = STOP_DOWN;
- break;
- case TALK_LEFT:
- case WALK_LEFT:
- sprite._sequenceNumber = STOP_LEFT;
- break;
- case TALK_RIGHT:
- case WALK_RIGHT:
- sprite._sequenceNumber = STOP_RIGHT;
- break;
- case WALK_UPRIGHT:
- sprite._sequenceNumber = STOP_UPRIGHT;
- break;
- case WALK_UPLEFT:
- sprite._sequenceNumber = STOP_UPLEFT;
- break;
- case WALK_DOWNRIGHT:
- sprite._sequenceNumber = STOP_DOWNRIGHT;
- break;
- case WALK_DOWNLEFT:
- sprite._sequenceNumber = STOP_DOWNLEFT;
- break;
- default:
- break;
- }
-
- // Only restart frame at 0 if the sequence number has changed
- if (_oldWalkSequence != -1 || sprite._sequenceNumber == STOP_UP)
- sprite._frameNumber = 0;
-
- if (map._active) {
- sprite._sequenceNumber = 0;
- _player._position.x = (map[map._charPoint].x - 6) * 100;
- _player._position.y = (map[map._charPoint].x + 10) * 100;
- }
-
- _oldWalkSequence = -1;
- _allowWalkAbort = true;
-}
-
-void People::walkToCoords(const Common::Point &destPos, int destDir) {
- Events &events = *_vm->_events;
- Scene &scene = *_vm->_scene;
- Talk &talk = *_vm->_talk;
-
- CursorId oldCursor = events.getCursor();
- events.setCursor(WAIT);
-
- _walkDest = Common::Point(destPos.x / 100 + 10, destPos.y / 100);
- _allowWalkAbort = true;
- goAllTheWay();
-
- // Keep calling doBgAnim until the walk is done
- do {
- events.pollEventsAndWait();
- scene.doBgAnim();
- } while (!_vm->shouldQuit() && _player._walkCount);
-
- if (!talk._talkToAbort) {
- // Put player exactly on destination position, and set direction
- _player._position = destPos;
- _player._sequenceNumber = destDir;
- gotoStand(_player);
-
- // Draw Holmes facing the new direction
- scene.doBgAnim();
-
- if (!talk._talkToAbort)
- events.setCursor(oldCursor);
- }
-}
-
-void People::goAllTheWay() {
- Scene &scene = *_vm->_scene;
- Common::Point srcPt(_player._position.x / 100 + _player.frameWidth() / 2,
- _player._position.y / 100);
-
- // Get the zone the player is currently in
- _srcZone = scene.whichZone(srcPt);
- if (_srcZone == -1)
- _srcZone = scene.closestZone(srcPt);
-
- // Get the zone of the destination
- _destZone = scene.whichZone(_walkDest);
- if (_destZone == -1) {
- _destZone = scene.closestZone(_walkDest);
-
- // The destination isn't in a zone
- if (_walkDest.x >= (SHERLOCK_SCREEN_WIDTH - 1))
- _walkDest.x = SHERLOCK_SCREEN_WIDTH - 2;
-
- // Trace a line between the centroid of the found closest zone to
- // the destination, to find the point at which the zone will be left
- const Common::Rect &destRect = scene._zones[_destZone];
- const Common::Point destCenter((destRect.left + destRect.right) / 2,
- (destRect.top + destRect.bottom) / 2);
- const Common::Point delta = _walkDest - destCenter;
- Common::Point pt(destCenter.x * 100, destCenter.y * 100);
-
- // Move along the line until the zone is left
- do {
- pt += delta;
- } while (destRect.contains(pt.x / 100, pt.y / 100));
-
- // Set the new walk destination to the last point that was in the
- // zone just before it was left
- _walkDest = Common::Point((pt.x - delta.x * 2) / 100,
- (pt.y - delta.y * 2) / 100);
- }
-
- // Only do a walk if both zones are acceptable
- if (_srcZone == -2 || _destZone == -2)
- return;
-
- // If the start and dest zones are the same, walk directly to the dest point
- if (_srcZone == _destZone) {
- setWalking();
- } else {
- // Otherwise a path needs to be formed from the path information
- int i = scene._walkDirectory[_srcZone][_destZone];
-
- // See if we need to use a reverse path
- if (i == -1)
- i = scene._walkDirectory[_destZone][_srcZone];
-
- int count = scene._walkData[i];
- ++i;
-
- // See how many points there are between the src and dest zones
- if (!count || count == -1) {
- // There are none, so just walk to the new zone
- setWalking();
- } else {
- // There are points, so set up a multi-step path between points
- // to reach the given destination
- _walkTo.clear();
-
- if (scene._walkDirectory[_srcZone][_destZone] != -1) {
- i += 3 * (count - 1);
- for (int idx = 0; idx < count; ++idx, i -= 3) {
- _walkTo.push(Common::Point(READ_LE_UINT16(&scene._walkData[i]),
- scene._walkData[i + 2]));
- }
- } else {
- for (int idx = 0; idx < count; ++idx, i += 3) {
- _walkTo.push(Common::Point(READ_LE_UINT16(&scene._walkData[i]), scene._walkData[i + 2]));
- }
- }
-
- // Final position
- _walkTo.push(_walkDest);
-
- // Start walking
- _walkDest = _walkTo.pop();
- setWalking();
- }
- }
-}
-
int People::findSpeaker(int speaker) {
Scene &scene = *_vm->_scene;
+ const char *portrait = _characters[speaker]._portrait;
for (int idx = 0; idx < (int)scene._bgShapes.size(); ++idx) {
Object &obj = scene._bgShapes[idx];
@@ -583,7 +262,7 @@ int People::findSpeaker(int speaker) {
if (obj._type == ACTIVE_BG_SHAPE) {
Common::String name(obj._name.c_str(), obj._name.c_str() + 4);
- if (name.equalsIgnoreCase(_characters[speaker]._portrait)
+ if (name.equalsIgnoreCase(portrait)
&& obj._name[4] >= '0' && obj._name[4] <= '9')
return idx;
}
@@ -622,91 +301,4 @@ void People::clearTalking() {
}
}
-void People::setTalking(int speaker) {
- Resources &res = *_vm->_res;
-
- // If no speaker is specified, then we can exit immediately
- if (speaker == -1)
- return;
-
- if (_portraitsOn) {
- delete _talkPics;
- Common::String filename = Common::String::format("%s.vgs", _characters[speaker]._portrait);
- _talkPics = new ImageFile(filename);
-
- // Load portrait sequences
- Common::SeekableReadStream *stream = res.load("sequence.txt");
- stream->seek(speaker * MAX_FRAME);
-
- int idx = 0;
- do {
- _portrait._sequences[idx] = stream->readByte();
- ++idx;
- } while (idx < 2 || _portrait._sequences[idx - 2] || _portrait._sequences[idx - 1]);
-
- delete stream;
-
- _portrait._maxFrames = idx;
- _portrait._frameNumber = 0;
- _portrait._sequenceNumber = 0;
- _portrait._images = _talkPics;
- _portrait._imageFrame = &(*_talkPics)[0];
- _portrait._position = Common::Point(_portraitSide, 10);
- _portrait._delta = Common::Point(0, 0);
- _portrait._oldPosition = Common::Point(0, 0);
- _portrait._goto = Common::Point(0, 0);
- _portrait._flags = 5;
- _portrait._status = 0;
- _portrait._misc = 0;
- _portrait._allow = 0;
- _portrait._type = ACTIVE_BG_SHAPE;
- _portrait._name = " ";
- _portrait._description = " ";
- _portrait._examine = " ";
- _portrait._walkCount = 0;
-
- if (_holmesFlip || _speakerFlip) {
- _portrait._flags |= 2;
-
- _holmesFlip = false;
- _speakerFlip = false;
- }
-
- if (_portraitSide == 20)
- _portraitSide = 220;
- else
- _portraitSide = 20;
-
- _portraitLoaded = true;
- }
-}
-
-void People::synchronize(Common::Serializer &s) {
- s.syncAsByte(_holmesOn);
-
- if (IS_SERRATED_SCALPEL) {
- s.syncAsSint16LE(_player._position.x);
- s.syncAsSint16LE(_player._position.y);
- s.syncAsSint16LE(_player._sequenceNumber);
- } else {
- for (int idx = 0; idx < MAX_CHARACTERS; ++idx) {
- Person &p = _data[idx];
- s.syncAsSint16LE(p._position.x);
- s.syncAsSint16LE(p._position.y);
- s.syncAsSint16LE(p._sequenceNumber);
- s.syncAsSint16LE(p._type);
- s.syncString(p._walkVGSName);
- s.syncString(p._description);
- s.syncString(p._examine);
- }
- }
-
- s.syncAsSint16LE(_holmesQuotient);
-
- if (s.isLoading()) {
- _hSavedPos = _player._position;
- _hSavedFacing = _player._sequenceNumber;
- }
-}
-
} // End of namespace Sherlock
diff --git a/engines/sherlock/people.h b/engines/sherlock/people.h
index 013727d8ba..c47d45145a 100644
--- a/engines/sherlock/people.h
+++ b/engines/sherlock/people.h
@@ -24,35 +24,28 @@
#define SHERLOCK_PEOPLE_H
#include "common/scummsys.h"
-#include "common/serializer.h"
#include "common/queue.h"
#include "sherlock/objects.h"
+#include "sherlock/saveload.h"
namespace Sherlock {
enum PeopleId {
- PLAYER = 0,
- AL = 0,
- PEG = 1,
- MAX_CHARACTERS = 6,
- MAX_NPC = 5,
+ HOLMES = 0,
+ WATSON = 1,
MAX_NPC_PATH = 200
};
-// Animation sequence identifiers for characters
-enum {
- WALK_RIGHT = 0, WALK_DOWN = 1, WALK_LEFT = 2, WALK_UP = 3, STOP_LEFT = 4,
- STOP_DOWN = 5, STOP_RIGHT = 6, STOP_UP = 7, WALK_UPRIGHT = 8,
- WALK_DOWNRIGHT = 9, WALK_UPLEFT = 10, WALK_DOWNLEFT = 11,
- STOP_UPRIGHT = 12, STOP_UPLEFT = 13, STOP_DOWNRIGHT = 14,
- STOP_DOWNLEFT = 15, TALK_RIGHT = 6, TALK_LEFT = 4
-};
-
enum {
MAP_UP = 1, MAP_UPRIGHT = 2, MAP_RIGHT = 1, MAP_DOWNRIGHT = 4,
MAP_DOWN = 5, MAP_DOWNLEFT = 6, MAP_LEFT = 2, MAP_UPLEFT = 8
};
+#define NUM_IN_WALK_LIB 10
+extern const char *const WALK_LIB_NAMES[10];
+
+#define MAX_CHARACTERS (IS_SERRATED_SCALPEL ? 1 : 6)
+
struct PersonData {
const char *_name;
const char *_portrait;
@@ -64,46 +57,55 @@ struct PersonData {
};
class Person : public Sprite {
+protected:
+ /**
+ * Get the source position for a character potentially affected by scaling
+ */
+ virtual Common::Point getSourcePoint() const = 0;
public:
+ Common::Queue<Common::Point> _walkTo;
+ int _srcZone, _destZone;
bool _walkLoaded;
Common::String _portrait;
-
- // NPC related fields
- int _npcIndex;
- int _npcStack;
- bool _npcPause;
- byte _npcPath[MAX_NPC_PATH];
+ Common::Point _walkDest;
Common::String _npcName;
- int _tempX;
- int _tempScaleVal;
// Rose Tattoo fields
Common::String _walkVGSName; // Name of walk library person is using
public:
Person();
+ virtual ~Person() {}
+
+ /**
+ * Called to set the character walking to the current cursor location.
+ * It uses the zones and the inter-zone points to determine a series
+ * of steps to walk to get to that position.
+ */
+ void goAllTheWay();
/**
- * Clear the NPC related data
+ * Walk to the co-ordinates passed, and then face the given direction
+ */
+ virtual void walkToCoords(const Point32 &destPos, int destDir) = 0;
+
+ /**
+ * Center the visible screen so that the person is in the center of the screen
*/
- void clearNPC();
+ virtual void centerScreenOnPerson() {}
};
class SherlockEngine;
class People {
-private:
+protected:
SherlockEngine *_vm;
- Person _data[MAX_CHARACTERS];
- int _oldWalkSequence;
- int _srcZone, _destZone;
+ Common::Array<Person *> _data;
+
+ People(SherlockEngine *vm);
public:
Common::Array<PersonData> _characters;
ImageFile *_talkPics;
- Common::Point _walkDest;
- Common::Point _hSavedPos;
- int _hSavedFacing;
- Common::Queue<Common::Point> _walkTo;
- Person &_player;
+ PositionFacing _savedPos;
bool _holmesOn;
bool _portraitLoaded;
bool _portraitsOn;
@@ -119,17 +121,11 @@ public:
int _walkControl;
public:
- People(SherlockEngine *vm);
- ~People();
+ static People *init(SherlockEngine *vm);
+ virtual ~People();
- Person &operator[](PeopleId id) {
- assert(id < MAX_CHARACTERS);
- return _data[id];
- }
- Person &operator[](int idx) {
- assert(idx < MAX_CHARACTERS);
- return _data[idx];
- }
+ Person &operator[](PeopleId id) { return *_data[id]; }
+ Person &operator[](int idx) { return *_data[idx]; }
/**
* Reset the player data
@@ -137,59 +133,50 @@ public:
void reset();
/**
- * Load the walking images for Sherlock
- */
- bool loadWalk();
-
- /**
* If the walk data has been loaded, then it will be freed
*/
bool freeWalk();
/**
- * Set the variables for moving a character from one poisition to another
- * in a straight line - goAllTheWay must have been previously called to
- * check for any obstacles in the path.
- */
- void setWalking();
-
- /**
- * Bring a moving character to a standing position. If the Scalpel chessboard
- * is being displayed, then the chraracter will always face down.
+ * Turn off any currently active portraits, and removes them from being drawn
*/
- void gotoStand(Sprite &sprite);
+ void clearTalking();
/**
- * Walk to the co-ordinates passed, and then face the given direction
- */
- void walkToCoords(const Common::Point &destPos, int destDir);
+ * Finds the scene background object corresponding to a specified speaker
+ */
+ virtual int findSpeaker(int speaker);
/**
- * Called to set the character walking to the current cursor location.
- * It uses the zones and the inter-zone points to determine a series
- * of steps to walk to get to that position.
+ * Synchronize the data for a savegame
*/
- void goAllTheWay();
+ virtual void synchronize(Serializer &s) = 0;
/**
- * Finds the scene background object corresponding to a specified speaker
+ * Change the sequence of the scene background object associated with the current speaker.
*/
- int findSpeaker(int speaker);
+ virtual void setTalkSequence(int speaker, int sequenceNum = 1) = 0;
/**
- * Turn off any currently active portraits, and removes them from being drawn
+ * Load the walking images for Sherlock
*/
- void clearTalking();
+ virtual bool loadWalk() = 0;
/**
- * Setup the data for an animating speaker portrait at the top of the screen
+ * Restrict passed point to zone using Sherlock's positioning rules
*/
- void setTalking(int speaker);
+ virtual const Common::Point restrictToZone(int zoneId, const Common::Point &destPos) = 0;
/**
- * Synchronize the data for a savegame
+ * If the specified speaker is a background object, it will set it so that it uses
+ * the Listen Sequence (specified by the sequence number). If the current sequence
+ * has an Allow Talk Code in it, the _gotoSeq field will be set so that the object
+ * begins listening as soon as it hits the Allow Talk Code. If there is no Abort Code,
+ * the Listen Sequence will begin immediately.
+ * @param speaker Who is speaking
+ * @param sequenceNum Which listen sequence to use
*/
- void synchronize(Common::Serializer &s);
+ virtual void setListenSequence(int speaker, int sequenceNum = 1) = 0;
};
} // End of namespace Sherlock
diff --git a/engines/sherlock/resources.cpp b/engines/sherlock/resources.cpp
index 2e6a0c2d7c..c4093048bd 100644
--- a/engines/sherlock/resources.cpp
+++ b/engines/sherlock/resources.cpp
@@ -64,7 +64,7 @@ void Cache::load(const Common::String &name, Common::SeekableReadStream &stream)
// Check whether the file is compressed
if (signature == MKTAG('L', 'Z', 'V', 26)) {
- // It's compressed, so decompress the file and store it's data in the cache entry
+ // It's compressed, so decompress the file and store its data in the cache entry
Common::SeekableReadStream *decompressed = _vm->_res->decompress(stream);
cacheEntry.resize(decompressed->size());
decompressed->read(&cacheEntry[0], decompressed->size());
@@ -89,18 +89,37 @@ Resources::Resources(SherlockEngine *vm) : _vm(vm), _cache(vm) {
_resourceIndex = -1;
if (_vm->_interactiveFl) {
- addToCache("vgs.lib");
- addToCache("talk.lib");
- addToCache("journal.txt");
+ if (!IS_3DO) {
+ addToCache("vgs.lib");
+ addToCache("talk.lib");
+ addToCache("journal.txt");
+
+ if (IS_SERRATED_SCALPEL) {
+ addToCache("sequence.txt");
+ addToCache("portrait.lib");
+ } else {
+ addToCache("walk.lib");
+ }
+ } else {
+ // 3DO
- if (IS_SERRATED_SCALPEL) {
- addToCache("sequence.txt");
- addToCache("portrait.lib");
+ // ITEM data from VGS.LIB is in ITEM.LIB
+ addToCache("item.lib");
+
+ // talk.lib - resources themselves seem to be the same, although a few texts were slightly changed
+ addToCache("talk.lib");
+
+ // remaining files are missing
+ // portraits were replaced with FMV
}
}
}
void Resources::addToCache(const Common::String &filename) {
+ // Return immediately if the library has already been loaded
+ if (_indexes.contains(filename))
+ return;
+
_cache.load(filename);
// Check to see if the file is a library
@@ -176,16 +195,27 @@ void Resources::decompressIfNecessary(Common::SeekableReadStream *&stream) {
}
}
-Common::SeekableReadStream *Resources::load(const Common::String &filename, const Common::String &libraryFile) {
+Common::SeekableReadStream *Resources::load(const Common::String &filename, const Common::String &libraryFile,
+ bool suppressErrors) {
// Open up the library for access
Common::SeekableReadStream *libStream = load(libraryFile);
- // Check if the library has already had it's index read, and if not, load it
+ // Check if the library has already had its index read, and if not, load it
if (!_indexes.contains(libraryFile))
loadLibraryIndex(libraryFile, libStream, false);
+ LibraryIndex &libIndex = _indexes[libraryFile];
+
+ // Handle if resource is not present
+ if (!libIndex.contains(filename)) {
+ if (!suppressErrors)
+ error("Could not find resource - %s", filename.c_str());
+
+ delete libStream;
+ return nullptr;
+ }
// Extract the data for the specified resource and return it
- LibraryEntry &entry = _indexes[libraryFile][filename];
+ LibraryEntry &entry = libIndex[filename];
libStream->seek(entry._offset);
Common::SeekableReadStream *stream = libStream->readStream(entry._size);
decompressIfNecessary(stream);
@@ -203,38 +233,80 @@ void Resources::loadLibraryIndex(const Common::String &libFilename,
Common::SeekableReadStream *stream, bool isNewStyle) {
uint32 offset, nextOffset;
+ // Return immediately if the library has already been loaded
+ if (_indexes.contains(libFilename))
+ return;
+
// Create an index entry
_indexes[libFilename] = LibraryIndex();
LibraryIndex &index = _indexes[libFilename];
// Read in the number of resources
stream->seek(4);
- int count = stream->readUint16LE();
+ int count = 0;
- if (isNewStyle)
- stream->seek((count + 1) * 8, SEEK_CUR);
+ if (!IS_3DO) {
+ // PC
+ count = stream->readUint16LE();
- // Loop through reading in the entries
- for (int idx = 0; idx < count; ++idx) {
- // Read the name of the resource
- char resName[13];
- stream->read(resName, 13);
- resName[12] = '\0';
+ if (isNewStyle)
+ stream->seek((count + 1) * 8, SEEK_CUR);
- // Read the offset
- offset = stream->readUint32LE();
+ // Loop through reading in the entries
+ for (int idx = 0; idx < count; ++idx) {
+ // Read the name of the resource
+ char resName[13];
+ stream->read(resName, 13);
+ resName[12] = '\0';
- if (idx == (count - 1)) {
- nextOffset = stream->size();
- } else {
- // Read the size by jumping forward to read the next entry's offset
- stream->seek(13, SEEK_CUR);
- nextOffset = stream->readUint32LE();
- stream->seek(-17, SEEK_CUR);
+ // Read the offset
+ offset = stream->readUint32LE();
+
+ if (idx == (count - 1)) {
+ nextOffset = stream->size();
+ } else {
+ // Read the size by jumping forward to read the next entry's offset
+ stream->seek(13, SEEK_CUR);
+ nextOffset = stream->readUint32LE();
+ stream->seek(-17, SEEK_CUR);
+ }
+
+ // Add the entry to the index
+ index[resName] = LibraryEntry(idx, offset, nextOffset - offset);
}
- // Add the entry to the index
- index[resName] = LibraryEntry(idx, offset, nextOffset - offset);
+ } else {
+ // 3DO
+ count = stream->readUint16BE();
+
+ // 3DO header
+ // Loop through reading in the entries
+
+ // Read offset of first entry
+ offset = stream->readUint32BE();
+
+ for (int idx = 0; idx < count; ++idx) {
+
+ // Read the name of the resource
+ char resName[13];
+ stream->read(resName, 13);
+ resName[12] = '\0';
+
+ stream->skip(3); // filler
+
+ if (idx == (count - 1)) {
+ nextOffset = stream->size();
+ } else {
+ // Read the offset of the next entry
+ nextOffset = stream->readUint32BE();
+ }
+
+ // Add the entry to the index
+ index[resName] = LibraryEntry(idx, offset, nextOffset - offset);
+
+ // use next offset as current offset
+ offset = nextOffset;
+ }
}
}
@@ -242,10 +314,18 @@ int Resources::resourceIndex() const {
return _resourceIndex;
}
+void Resources::getResourceNames(const Common::String &libraryFile, Common::StringArray &names) {
+ addToCache(libraryFile);
+ LibraryIndex &libIndex = _indexes[libraryFile];
+ for (LibraryIndex::iterator i = libIndex.begin(); i != libIndex.end(); ++i) {
+ names.push_back(i->_key);
+ }
+}
+
Common::SeekableReadStream *Resources::decompress(Common::SeekableReadStream &source) {
// This variation can't be used by Rose Tattoo, since compressed resources include the input size,
// not the output size. Which means their decompression has to be done via passed buffers
- assert(_vm->getGameID() == GType_SerratedScalpel);
+ assert(IS_SERRATED_SCALPEL);
uint32 id = source.readUint32BE();
assert(id == MKTAG('L', 'Z', 'V', 0x1A));
@@ -255,7 +335,7 @@ Common::SeekableReadStream *Resources::decompress(Common::SeekableReadStream &so
}
Common::SeekableReadStream *Resources::decompress(Common::SeekableReadStream &source, uint32 outSize) {
- int inSize = (_vm->getGameID() == GType_RoseTattoo) ? source.readSint32LE() : -1;
+ int inSize = IS_ROSE_TATTOO ? source.readSint32LE() : -1;
byte *outBuffer = (byte *)malloc(outSize);
Common::MemoryReadStream *outStream = new Common::MemoryReadStream(outBuffer, outSize, DisposeAfterUse::YES);
@@ -265,7 +345,7 @@ Common::SeekableReadStream *Resources::decompress(Common::SeekableReadStream &so
}
void Resources::decompress(Common::SeekableReadStream &source, byte *buffer, uint32 outSize) {
- int inputSize = (_vm->getGameID() == GType_RoseTattoo) ? source.readSint32LE() : -1;
+ int inputSize = IS_ROSE_TATTOO ? source.readSint32LE() : -1;
decompressLZ(source, buffer, outSize, inputSize);
}
@@ -316,184 +396,4 @@ void Resources::decompressLZ(Common::SeekableReadStream &source, byte *outBuffer
} while ((outSize == -1 || outBuffer < outBufferEnd) && (inSize == -1 || source.pos() < endPos));
}
-/*----------------------------------------------------------------*/
-
-SherlockEngine *ImageFile::_vm;
-
-void ImageFile::setVm(SherlockEngine *vm) {
- _vm = vm;
-}
-
-ImageFile::ImageFile(const Common::String &name, bool skipPal, bool animImages) {
- Common::SeekableReadStream *stream = _vm->_res->load(name);
-
- Common::fill(&_palette[0], &_palette[PALETTE_SIZE], 0);
- load(*stream, skipPal, animImages);
-
- delete stream;
-}
-
-ImageFile::ImageFile(Common::SeekableReadStream &stream, bool skipPal) {
- Common::fill(&_palette[0], &_palette[PALETTE_SIZE], 0);
- load(stream, skipPal, false);
-}
-
-ImageFile::~ImageFile() {
- for (uint idx = 0; idx < size(); ++idx)
- (*this)[idx]._frame.free();
-}
-
-void ImageFile::load(Common::SeekableReadStream &stream, bool skipPalette, bool animImages) {
- loadPalette(stream);
-
- int streamSize = stream.size();
- while (stream.pos() < streamSize) {
- ImageFrame frame;
- frame._width = stream.readUint16LE() + 1;
- frame._height = stream.readUint16LE() + 1;
- frame._paletteBase = stream.readByte();
-
- if (animImages) {
- // Animation cutscene image files use a 16-bit x offset
- frame._offset.x = stream.readUint16LE();
- frame._rleEncoded = (frame._offset.x & 0xff) == 1;
- frame._offset.y = stream.readByte();
- } else {
- // Standard image files have a separate byte for the RLE flag, and an 8-bit X offset
- frame._rleEncoded = stream.readByte() == 1;
- frame._offset.x = stream.readByte();
- frame._offset.y = stream.readByte();
- }
-
- frame._rleEncoded = !skipPalette && frame._rleEncoded;
-
- if (frame._paletteBase) {
- // Nibble packed frame data
- frame._size = (frame._width * frame._height) / 2;
- } else if (frame._rleEncoded) {
- // This size includes the header size, which we subtract
- frame._size = stream.readUint16LE() - 11;
- frame._rleMarker = stream.readByte();
- } else {
- // Uncompressed data
- frame._size = frame._width * frame._height;
- }
-
- // Load data for frame and decompress it
- byte *data = new byte[frame._size];
- stream.read(data, frame._size);
- decompressFrame(frame, data);
- delete[] data;
-
- push_back(frame);
- }
-}
-
-void ImageFile::loadPalette(Common::SeekableReadStream &stream) {
- // Check for palette
- int v1 = stream.readUint16LE() + 1;
- int v2 = stream.readUint16LE() + 1;
- stream.skip(1); // Skip paletteBase byte
- bool rleEncoded = stream.readByte() == 1;
- int palSize = v1 * v2;
-
- if ((palSize - 12) == PALETTE_SIZE && !rleEncoded) {
- // Found palette, so read it in
- stream.seek(2 + 12, SEEK_CUR);
- for (int idx = 0; idx < PALETTE_SIZE; ++idx)
- _palette[idx] = VGA_COLOR_TRANS(stream.readByte());
- } else {
- // Not a palette, so rewind to start of frame data for normal frame processing
- stream.seek(-6, SEEK_CUR);
- }
-}
-
-void ImageFile::decompressFrame(ImageFrame &frame, const byte *src) {
- frame._frame.create(frame._width, frame._height, Graphics::PixelFormat::createFormatCLUT8());
-
- if (frame._paletteBase) {
- // Nibble-packed
- byte *pDest = (byte *)frame._frame.getPixels();
- for (uint idx = 0; idx < frame._size; ++idx, ++src) {
- *pDest++ = *src & 0xF;
- *pDest++ = (*src >> 4);
- }
- } else if (frame._rleEncoded && _vm->getGameID() == GType_RoseTattoo) {
- // Rose Tattoo run length encoding doesn't use the RLE marker byte
- byte *dst = (byte *)frame._frame.getPixels();
-
- for (int yp = 0; yp < frame._height; ++yp) {
- int xSize = frame._width;
- while (xSize > 0) {
- // Skip a given number of pixels
- byte skip = *src++;
- dst += skip;
- xSize -= skip;
- if (!xSize)
- break;
-
- // Get a run length, and copy the following number of pixels
- int rleCount = *src++;
- xSize -= rleCount;
- while (rleCount-- > 0)
- *dst++ = *src++;
- }
- assert(xSize == 0);
- }
- } else if (frame._rleEncoded) {
- // RLE encoded
- byte *dst = (byte *)frame._frame.getPixels();
-
- int frameSize = frame._width * frame._height;
- while (frameSize > 0) {
- if (*src == frame._rleMarker) {
- byte rleColor = src[1];
- byte rleCount = src[2];
- src += 3;
- frameSize -= rleCount;
- while (rleCount--)
- *dst++ = rleColor;
- } else {
- *dst++ = *src++;
- --frameSize;
- }
- }
- assert(frameSize == 0);
- } else {
- // Uncompressed frame
- Common::copy(src, src + frame._width * frame._height,
- (byte *)frame._frame.getPixels());
- }
-}
-
-/*----------------------------------------------------------------*/
-
-int ImageFrame::sDrawXSize(int scaleVal) const {
- int width = _width;
- int scale = scaleVal == 0 ? 1 : scaleVal;
-
- if (scaleVal >= 256)
- --width;
-
- int result = width * 256 / scale;
- if (scaleVal >= 256)
- ++result;
-
- return result;
-}
-
-int ImageFrame::sDrawYSize(int scaleVal) const {
- int height = _height;
- int scale = scaleVal == 0 ? 1 : scaleVal;
-
- if (scaleVal >= 256)
- --height;
-
- int result = height * 256 / scale;
- if (scaleVal >= 256)
- ++result;
-
- return result;
-}
-
} // End of namespace Sherlock
diff --git a/engines/sherlock/resources.h b/engines/sherlock/resources.h
index 5c071e3922..99d58a51b1 100644
--- a/engines/sherlock/resources.h
+++ b/engines/sherlock/resources.h
@@ -29,6 +29,7 @@
#include "common/hash-str.h"
#include "common/rect.h"
#include "common/str.h"
+#include "common/str-array.h"
#include "common/stream.h"
#include "graphics/surface.h"
@@ -88,7 +89,7 @@ private:
int _resourceIndex;
/**
- * Reads in the index from a library file, and caches it's index for later use
+ * Reads in the index from a library file, and caches its index for later use
*/
void loadLibraryIndex(const Common::String &libFilename, Common::SeekableReadStream *stream, bool isNewStyle);
public:
@@ -96,7 +97,7 @@ public:
/**
* Adds the specified file to the cache. If it's a library file, takes care of
- * loading it's index for future use
+ * loading its index for future use
*/
void addToCache(const Common::String &filename);
@@ -113,7 +114,7 @@ public:
bool isInCache(const Common::String &filename) const { return _cache.isCached(filename); }
/**
- * Checks the passed stream, and if is compressed, deletes it and replaces it with it's uncompressed data
+ * Checks the passed stream, and if is compressed, deletes it and replaces it with its uncompressed data
*/
void decompressIfNecessary(Common::SeekableReadStream *&stream);
@@ -125,7 +126,7 @@ public:
/**
* Loads a specific resource from a given library file
*/
- Common::SeekableReadStream *load(const Common::String &filename, const Common::String &libraryFile);
+ Common::SeekableReadStream *load(const Common::String &filename, const Common::String &libraryFile, bool suppressErrors = false);
/**
* Returns true if the given file exists on disk or in the cache
@@ -133,13 +134,18 @@ public:
bool exists(const Common::String &filename) const;
/**
- * Returns the index of the last loaded resource in it's given library file.
+ * Returns the index of the last loaded resource in its given library file.
* This will be used primarily when loading talk files, so the engine can
* update the given conversation number in the journal
*/
int resourceIndex() const;
/**
+ * Produces a list of all resource names within a file. Used by the debugger.
+ */
+ void getResourceNames(const Common::String &libraryFile, Common::StringArray &names);
+
+ /**
* Decompresses LZW compressed data
*/
Common::SeekableReadStream *decompress(Common::SeekableReadStream &source);
@@ -165,53 +171,6 @@ public:
static void decompressLZ(Common::SeekableReadStream &source, byte *outBuffer, int32 outSize, int32 inSize);
};
-struct ImageFrame {
- uint32 _size;
- uint16 _width, _height;
- int _paletteBase;
- bool _rleEncoded;
- Common::Point _offset;
- byte _rleMarker;
- Graphics::Surface _frame;
-
- /**
- * Return the frame width adjusted by a specified scale amount
- */
- int sDrawXSize(int scaleVal) const;
-
- /**
- * Return the frame height adjusted by a specified scale amount
- */
- int sDrawYSize(int scaleVal) const;
-};
-
-class ImageFile : public Common::Array<ImageFrame> {
-private:
- static SherlockEngine *_vm;
-
- /**
- * Load the data of the sprite
- */
- void load(Common::SeekableReadStream &stream, bool skipPalette, bool animImages);
-
- /**
- * Gets the palette at the start of the sprite file
- */
- void loadPalette(Common::SeekableReadStream &stream);
-
- /**
- * Decompress a single frame for the sprite
- */
- void decompressFrame(ImageFrame &frame, const byte *src);
-public:
- byte _palette[256 * 3];
-public:
- ImageFile(const Common::String &name, bool skipPal = false, bool animImages = false);
- ImageFile(Common::SeekableReadStream &stream, bool skipPal = false);
- ~ImageFile();
- static void setVm(SherlockEngine *vm);
-};
-
} // End of namespace Sherlock
#endif
diff --git a/engines/sherlock/saveload.cpp b/engines/sherlock/saveload.cpp
index ddf4917a34..f32552c7ea 100644
--- a/engines/sherlock/saveload.cpp
+++ b/engines/sherlock/saveload.cpp
@@ -23,31 +23,30 @@
#include "sherlock/saveload.h"
#include "sherlock/surface.h"
#include "sherlock/sherlock.h"
+#include "sherlock/scalpel/scalpel_saveload.h"
+#include "sherlock/tattoo/widget_files.h"
#include "common/system.h"
#include "graphics/scaler.h"
#include "graphics/thumbnail.h"
namespace Sherlock {
-const int ENV_POINTS[6][3] = {
- { 41, 80, 61 }, // Exit
- { 81, 120, 101 }, // Load
- { 121, 160, 141 }, // Save
- { 161, 200, 181 }, // Up
- { 201, 240, 221 }, // Down
- { 241, 280, 261 } // Quit
-};
-
-static const char *const EMPTY_SAVEGAME_SLOT = "-EMPTY-";
+const char *const EMPTY_SAVEGAME_SLOT = "-EMPTY-";
static const char *const SAVEGAME_STR = "SHLK";
#define SAVEGAME_STR_SIZE 4
/*----------------------------------------------------------------*/
+SaveManager *SaveManager::init(SherlockEngine *vm, const Common::String &target) {
+ if (vm->getGameID() == GType_SerratedScalpel)
+ return new Scalpel::ScalpelSaveManager(vm, target);
+ else
+ return new Tattoo::WidgetFiles(vm, target);
+}
+
SaveManager::SaveManager(SherlockEngine *vm, const Common::String &target) :
_vm(vm), _target(target) {
_saveThumb = nullptr;
- _envMode = SAVEMODE_NONE;
_justLoaded = false;
_savegameIndex = 0;
}
@@ -59,54 +58,6 @@ SaveManager::~SaveManager() {
}
}
-void SaveManager::drawInterface() {
- Screen &screen = *_vm->_screen;
- UserInterface &ui = *_vm->_ui;
-
- // Create a list of savegame slots
- createSavegameList();
-
- screen._backBuffer1.fillRect(Common::Rect(0, CONTROLS_Y, SHERLOCK_SCREEN_WIDTH, CONTROLS_Y + 10), BORDER_COLOR);
- screen._backBuffer1.fillRect(Common::Rect(0, CONTROLS_Y + 10, 2, SHERLOCK_SCREEN_HEIGHT), BORDER_COLOR);
- screen._backBuffer1.fillRect(Common::Rect(318, CONTROLS_Y + 10, SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT), BORDER_COLOR);
- screen._backBuffer1.fillRect(Common::Rect(0, 199, SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT), BORDER_COLOR);
- 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");
- 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");
- 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");
- 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");
- 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");
- 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");
-
- if (!_savegameIndex)
- screen.buttonPrint(Common::Point(ENV_POINTS[3][2], CONTROLS_Y), COMMAND_NULL, 0, "Up");
-
- if (_savegameIndex == MAX_SAVEGAME_SLOTS - ONSCREEN_FILES_COUNT)
- screen.buttonPrint(Common::Point(ENV_POINTS[4][2], CONTROLS_Y), COMMAND_NULL, 0, "Down");
-
- for (int idx = _savegameIndex; idx < _savegameIndex + ONSCREEN_FILES_COUNT; ++idx) {
- screen.gPrint(Common::Point(6, CONTROLS_Y + 11 + (idx - _savegameIndex) * 10),
- INV_FOREGROUND, "%d.", idx + 1);
- screen.gPrint(Common::Point(24, CONTROLS_Y + 11 + (idx - _savegameIndex) * 10),
- INV_FOREGROUND, "%s", _savegames[idx].c_str());
- }
-
- if (!ui._slideWindows) {
- screen.slamRect(Common::Rect(0, CONTROLS_Y, SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT));
- } else {
- ui.summonWindow();
- }
-
- _envMode = SAVEMODE_NONE;
-}
-
void SaveManager::createSavegameList() {
Screen &screen = *_vm->_screen;
@@ -116,7 +67,7 @@ void SaveManager::createSavegameList() {
SaveStateList saveList = getSavegameList(_target);
for (uint idx = 0; idx < saveList.size(); ++idx) {
- int slot = saveList[idx].getSaveSlot() - 1;
+ int slot = saveList[idx].getSaveSlot();
if (slot >= 0 && slot < MAX_SAVEGAME_SLOTS)
_savegames[slot] = saveList[idx].getDescription();
}
@@ -153,7 +104,9 @@ SaveStateList SaveManager::getSavegameList(const Common::String &target) {
Common::InSaveFile *in = g_system->getSavefileManager()->openForLoading(*file);
if (in) {
- readSavegameHeader(in, header);
+ if (!readSavegameHeader(in, header))
+ continue;
+
saveList.push_back(SaveStateDescriptor(slot, header._saveName));
header._thumbnail->free();
@@ -176,7 +129,7 @@ bool SaveManager::readSavegameHeader(Common::InSaveFile *in, SherlockSavegameHea
return false;
header._version = in->readByte();
- if (header._version > SHERLOCK_SAVEGAME_VERSION)
+ if (header._version < MINIMUM_SAVEGAME_VERSION || header._version > CURRENT_SAVEGAME_VERSION)
return false;
// Read in the string
@@ -204,7 +157,7 @@ void SaveManager::writeSavegameHeader(Common::OutSaveFile *out, SherlockSavegame
// Write out a savegame header
out->write(SAVEGAME_STR, SAVEGAME_STR_SIZE + 1);
- out->writeByte(SHERLOCK_SAVEGAME_VERSION);
+ out->writeByte(CURRENT_SAVEGAME_VERSION);
// Write savegame name
out->write(header._saveName.c_str(), header._saveName.size());
@@ -236,56 +189,19 @@ void SaveManager::createThumbnail() {
delete _saveThumb;
}
- uint8 thumbPalette[PALETTE_SIZE];
- _vm->_screen->getPalette(thumbPalette);
_saveThumb = new Graphics::Surface();
- ::createThumbnail(_saveThumb, (const byte *)_vm->_screen->getPixels(), SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT, thumbPalette);
-}
-int SaveManager::getHighlightedButton() const {
- Common::Point pt = _vm->_events->mousePos();
-
- for (int idx = 0; idx < 6; ++idx) {
- if (pt.x > ENV_POINTS[idx][0] && pt.x < ENV_POINTS[idx][1] && pt.y > CONTROLS_Y
- && pt.y < (CONTROLS_Y + 10))
- return idx;
+ if (!IS_3DO) {
+ uint8 thumbPalette[PALETTE_SIZE];
+ _vm->_screen->getPalette(thumbPalette);
+ ::createThumbnail(_saveThumb, (const byte *)_vm->_screen->getPixels(), SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT, thumbPalette);
+ } else {
+ ::createThumbnailFromScreen(_saveThumb);
}
-
- return -1;
-}
-
-void SaveManager::highlightButtons(int btnIndex) {
- Screen &screen = *_vm->_screen;
- byte color = (btnIndex == 0) ? COMMAND_HIGHLIGHTED : COMMAND_FOREGROUND;
-
- screen.buttonPrint(Common::Point(ENV_POINTS[0][2], CONTROLS_Y), color, 1, "Exit");
-
- if ((btnIndex == 1) || ((_envMode == SAVEMODE_LOAD) && (btnIndex != 2)))
- screen.buttonPrint(Common::Point(ENV_POINTS[1][2], CONTROLS_Y), COMMAND_HIGHLIGHTED, true, "Load");
- else
- screen.buttonPrint(Common::Point(ENV_POINTS[1][2], CONTROLS_Y), COMMAND_FOREGROUND, true, "Load");
-
- if ((btnIndex == 2) || ((_envMode == SAVEMODE_SAVE) && (btnIndex != 1)))
- screen.buttonPrint(Common::Point(ENV_POINTS[2][2], CONTROLS_Y), COMMAND_HIGHLIGHTED, true, "Save");
- else
- screen.buttonPrint(Common::Point(ENV_POINTS[2][2], CONTROLS_Y), COMMAND_FOREGROUND, true, "Save");
-
- if (btnIndex == 3 && _savegameIndex)
- screen.buttonPrint(Common::Point(ENV_POINTS[3][2], CONTROLS_Y), COMMAND_HIGHLIGHTED, true, "Up");
- else
- if (_savegameIndex)
- screen.buttonPrint(Common::Point(ENV_POINTS[3][2], CONTROLS_Y), COMMAND_FOREGROUND, true, "Up");
-
- if ((btnIndex == 4) && (_savegameIndex < MAX_SAVEGAME_SLOTS - 5))
- screen.buttonPrint(Common::Point(ENV_POINTS[4][2], CONTROLS_Y), COMMAND_HIGHLIGHTED, true, "Down");
- else if (_savegameIndex < (MAX_SAVEGAME_SLOTS - 5))
- screen.buttonPrint(Common::Point(ENV_POINTS[4][2], CONTROLS_Y), COMMAND_FOREGROUND, true, "Down");
-
- color = (btnIndex == 5) ? COMMAND_HIGHLIGHTED : COMMAND_FOREGROUND;
- screen.buttonPrint(Common::Point(ENV_POINTS[5][2], CONTROLS_Y), color, 1, "Quit");
}
void SaveManager::loadGame(int slot) {
+ Events &events = *_vm->_events;
Common::InSaveFile *saveFile = g_system->getSavefileManager()->openForLoading(
generateSaveName(slot));
if (!saveFile)
@@ -302,13 +218,16 @@ void SaveManager::loadGame(int slot) {
}
// Synchronize the savegame data
- Common::Serializer s(saveFile, nullptr);
+ Serializer s(saveFile, nullptr);
+ s.setSaveVersion(header._version);
synchronize(s);
delete saveFile;
+ events.clearEvents();
}
void SaveManager::saveGame(int slot, const Common::String &name) {
+ Events &events = *_vm->_events;
Common::OutSaveFile *out = g_system->getSavefileManager()->openForSaving(
generateSaveName(slot));
@@ -317,18 +236,20 @@ void SaveManager::saveGame(int slot, const Common::String &name) {
writeSavegameHeader(out, header);
// Synchronize the savegame data
- Common::Serializer s(nullptr, out);
+ Serializer s(nullptr, out);
+ s.setSaveVersion(CURRENT_SAVEGAME_VERSION);
synchronize(s);
out->finalize();
delete out;
+ events.clearEvents();
}
Common::String SaveManager::generateSaveName(int slot) {
return Common::String::format("%s.%03d", _target.c_str(), slot);
}
-void SaveManager::synchronize(Common::Serializer &s) {
+void SaveManager::synchronize(Serializer &s) {
Inventory &inv = *_vm->_inventory;
Journal &journal = *_vm->_journal;
Map &map = *_vm->_map;
@@ -351,130 +272,7 @@ void SaveManager::synchronize(Common::Serializer &s) {
if (screen.fontNumber() != oldFont)
journal.resetPosition();
- _justLoaded = true;
-}
-
-bool SaveManager::checkGameOnScreen(int slot) {
- Screen &screen = *_vm->_screen;
-
- // Check if it's already on-screen
- if (slot != -1 && (slot < _savegameIndex || slot >= (_savegameIndex + ONSCREEN_FILES_COUNT))) {
- _savegameIndex = slot;
-
- screen._backBuffer1.fillRect(Common::Rect(3, CONTROLS_Y + 11, SHERLOCK_SCREEN_WIDTH - 2,
- SHERLOCK_SCREEN_HEIGHT - 1), INV_BACKGROUND);
-
- for (int idx = _savegameIndex; idx < (_savegameIndex + 5); ++idx) {
- screen.gPrint(Common::Point(6, CONTROLS_Y + 11 + (idx - _savegameIndex) * 10),
- INV_FOREGROUND, "%d.", idx + 1);
- screen.gPrint(Common::Point(24, CONTROLS_Y + 11 + (idx - _savegameIndex) * 10),
- INV_FOREGROUND, "%s", _savegames[idx].c_str());
- }
-
- 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");
-
- color = (_savegameIndex == (MAX_SAVEGAME_SLOTS - 5)) ? COMMAND_NULL : COMMAND_FOREGROUND;
- screen.buttonPrint(Common::Point(ENV_POINTS[4][2], CONTROLS_Y), color, 1, "Down");
-
- return true;
- }
-
- return false;
-}
-
-bool SaveManager::promptForDescription(int slot) {
- Events &events = *_vm->_events;
- Scene &scene = *_vm->_scene;
- Screen &screen = *_vm->_screen;
- Talk &talk = *_vm->_talk;
- 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");
-
- Common::String saveName = _savegames[slot];
- if (isSlotEmpty(slot)) {
- // It's an empty slot, so start off with an empty save name
- saveName = "";
-
- yp = CONTROLS_Y + 12 + (slot - _savegameIndex) * 10;
- screen.vgaBar(Common::Rect(24, yp, 85, yp + 9), INV_BACKGROUND);
- }
-
- screen.print(Common::Point(6, CONTROLS_Y + 12 + (slot - _savegameIndex) * 10), TALK_FOREGROUND, "%d.", slot + 1);
- screen.print(Common::Point(24, CONTROLS_Y + 12 + (slot - _savegameIndex) * 10), TALK_FOREGROUND, "%s", saveName.c_str());
- xp = 24 + screen.stringWidth(saveName);
- yp = CONTROLS_Y + 12 + (slot - _savegameIndex) * 10;
-
- int done = 0;
- do {
- while (!_vm->shouldQuit() && !events.kbHit()) {
- scene.doBgAnim();
-
- if (talk._talkToAbort)
- return false;
-
- // Allow event processing
- events.pollEventsAndWait();
- events.setButtonState();
-
- flag = !flag;
- if (flag)
- screen.vgaBar(Common::Rect(xp, yp - 1, xp + 8, yp + 9), INV_FOREGROUND);
- else
- screen.vgaBar(Common::Rect(xp, yp - 1, xp + 8, yp + 9), INV_BACKGROUND);
- }
- if (_vm->shouldQuit())
- return false;
-
- // Get the next keypress
- Common::KeyState keyState = events.getKey();
-
- if (keyState.keycode == Common::KEYCODE_BACKSPACE && saveName.size() > 0) {
- // Delete character of save name
- screen.vgaBar(Common::Rect(xp - screen.charWidth(saveName.lastChar()), yp - 1,
- xp + 8, yp + 9), INV_BACKGROUND);
- xp -= screen.charWidth(saveName.lastChar());
- screen.vgaBar(Common::Rect(xp, yp - 1, xp + 8, yp + 9), INV_FOREGROUND);
- saveName.deleteLastChar();
-
- } else if (keyState.keycode == Common::KEYCODE_RETURN && saveName.compareToIgnoreCase(EMPTY_SAVEGAME_SLOT)) {
- done = 1;
-
- } else if (keyState.keycode == Common::KEYCODE_ESCAPE) {
- screen.vgaBar(Common::Rect(xp, yp - 1, xp + 8, yp + 9), INV_BACKGROUND);
- done = -1;
-
- } else if (keyState.ascii >= ' ' && keyState.ascii <= 'z' && saveName.size() < 50
- && (xp + screen.charWidth(keyState.ascii)) < 308) {
- char c = (char)keyState.ascii;
-
- screen.vgaBar(Common::Rect(xp, yp - 1, xp + 8, yp + 9), INV_BACKGROUND);
- screen.print(Common::Point(xp, yp), TALK_FOREGROUND, "%c", c);
- xp += screen.charWidth(c);
- screen.vgaBar(Common::Rect(xp, yp - 1, xp + 8, yp + 9), INV_FOREGROUND);
- saveName += c;
- }
- } while (!done);
-
- if (done == 1) {
- // Enter key perssed
- _savegames[slot] = saveName;
- } else {
- done = 0;
- _envMode = SAVEMODE_NONE;
- highlightButtons(-1);
- }
-
- return done == 1;
+ _justLoaded = s.isLoading();
}
bool SaveManager::isSlotEmpty(int slot) const {
diff --git a/engines/sherlock/saveload.h b/engines/sherlock/saveload.h
index a7ed852a5f..f4f3e7cfd9 100644
--- a/engines/sherlock/saveload.h
+++ b/engines/sherlock/saveload.h
@@ -34,11 +34,15 @@ namespace Sherlock {
#define MAX_SAVEGAME_SLOTS 99
#define ONSCREEN_FILES_COUNT 5
-#define SHERLOCK_SAVEGAME_VERSION 1
+
+enum {
+ CURRENT_SAVEGAME_VERSION = 4,
+ MINIMUM_SAVEGAME_VERSION = 4
+};
enum SaveMode { SAVEMODE_NONE = 0, SAVEMODE_LOAD = 1, SAVEMODE_SAVE = 2 };
-extern const int ENV_POINTS[6][3];
+extern const char *const EMPTY_SAVEGAME_SLOT;
struct SherlockSavegameHeader {
uint8 _version;
@@ -51,8 +55,22 @@ struct SherlockSavegameHeader {
class SherlockEngine;
+
+/**
+ * Derived serializer class with extra synchronization types
+ */
+class Serializer : public Common::Serializer {
+public:
+ Serializer(Common::SeekableReadStream *in, Common::WriteStream *out) : Common::Serializer(in, out) {}
+
+ /**
+ * New method to allow setting the version
+ */
+ void setSaveVersion(byte version) { _version = version; }
+};
+
class SaveManager {
-private:
+protected:
SherlockEngine *_vm;
Common::String _target;
Graphics::Surface *_saveThumb;
@@ -65,20 +83,15 @@ private:
/**
* Synchronize the data for a savegame
*/
- void synchronize(Common::Serializer &s);
+ void synchronize(Serializer &s);
public:
Common::StringArray _savegames;
int _savegameIndex;
- SaveMode _envMode;
bool _justLoaded;
public:
+ static SaveManager *init(SherlockEngine *vm, const Common::String &target);
SaveManager(SherlockEngine *vm, const Common::String &target);
- ~SaveManager();
-
- /**
- * Shows the in-game dialog interface for loading and saving games
- */
- void drawInterface();
+ virtual ~SaveManager();
/**
* Creates a thumbnail for the current on-screen contents
@@ -127,16 +140,6 @@ public:
void saveGame(int slot, const Common::String &name);
/**
- * Make sure that the selected savegame is on-screen
- */
- bool checkGameOnScreen(int slot);
-
- /**
- * Prompts the user to enter a description in a given slot
- */
- bool promptForDescription(int slot);
-
- /**
* Returns true if the given save slot is empty
*/
bool isSlotEmpty(int slot) const;
diff --git a/engines/sherlock/scalpel/3do/movie_decoder.cpp b/engines/sherlock/scalpel/3do/movie_decoder.cpp
new file mode 100644
index 0000000000..8e8f99bc19
--- /dev/null
+++ b/engines/sherlock/scalpel/3do/movie_decoder.cpp
@@ -0,0 +1,510 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public 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 "audio/decoders/3do.h"
+
+#include "sherlock/scalpel/3do/movie_decoder.h"
+#include "image/codecs/cinepak.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 Sherlock {
+
+Scalpel3DOMovieDecoder::Scalpel3DOMovieDecoder()
+ : _stream(0), _videoTrack(0), _audioTrack(0) {
+ _streamVideoOffset = 0;
+ _streamAudioOffset = 0;
+}
+
+Scalpel3DOMovieDecoder::~Scalpel3DOMovieDecoder() {
+ close();
+}
+
+bool Scalpel3DOMovieDecoder::loadStream(Common::SeekableReadStream *stream) {
+ uint32 videoSubType = 0;
+ uint32 videoCodecTag = 0;
+ uint32 videoHeight = 0;
+ uint32 videoWidth = 0;
+ uint32 videoFrameCount = 0;
+ uint32 audioSubType = 0;
+ uint32 audioCodecTag = 0;
+ uint32 audioChannels = 0;
+ uint32 audioSampleRate = 0;
+
+ close();
+
+ _stream = stream;
+ _streamVideoOffset = 0;
+ _streamAudioOffset = 0;
+
+ // Look for packets that we care about
+ static const int maxPacketCheckCount = 20;
+ for (int i = 0; i < maxPacketCheckCount; i++) {
+ uint32 chunkTag = _stream->readUint32BE();
+ uint32 chunkSize = _stream->readUint32BE() - 8;
+
+ // Bail out if done
+ if (_stream->eos())
+ break;
+
+ uint32 dataStartOffset = _stream->pos();
+
+ switch (chunkTag) {
+ case MKTAG('F','I','L','M'): {
+ // See if this is a FILM header
+ _stream->skip(4); // time stamp (based on 240 per second)
+ _stream->skip(4); // Unknown 0x00000000
+ videoSubType = _stream->readUint32BE();
+
+ switch (videoSubType) {
+ case MKTAG('F', 'H', 'D', 'R'):
+ // FILM header found
+ if (_videoTrack) {
+ warning("Sherlock 3DO movie: Multiple FILM headers found");
+ close();
+ return false;
+ }
+ _stream->readUint32BE();
+ videoCodecTag = _stream->readUint32BE();
+ videoHeight = _stream->readUint32BE();
+ videoWidth = _stream->readUint32BE();
+ _stream->skip(4); // time scale
+ videoFrameCount = _stream->readUint32BE();
+
+ _videoTrack = new StreamVideoTrack(videoWidth, videoHeight, videoCodecTag, videoFrameCount);
+ addTrack(_videoTrack);
+ break;
+
+ case MKTAG('F', 'R', 'M', 'E'):
+ break;
+
+ default:
+ warning("Sherlock 3DO movie: Unknown subtype inside FILM packet");
+ close();
+ return false;
+ }
+ break;
+ }
+
+ case MKTAG('S','N','D','S'): {
+ _stream->skip(8);
+ audioSubType = _stream->readUint32BE();
+
+ switch (audioSubType) {
+ case MKTAG('S', 'H', 'D', 'R'):
+ // Audio header
+
+ // Bail if we already have a track
+ if (_audioTrack) {
+ warning("Sherlock 3DO movie: Multiple SNDS headers found");
+ close();
+ return false;
+ }
+
+ // OK, this is the start of a audio stream
+ _stream->readUint32BE(); // Version, always 0x00000000
+ _stream->readUint32BE(); // Unknown 0x00000008 ?!
+ _stream->readUint32BE(); // Unknown 0x00007500
+ _stream->readUint32BE(); // Unknown 0x00004000
+ _stream->readUint32BE(); // Unknown 0x00000000
+ _stream->readUint32BE(); // Unknown 0x00000010
+ audioSampleRate = _stream->readUint32BE();
+ audioChannels = _stream->readUint32BE();
+ audioCodecTag = _stream->readUint32BE();
+ _stream->readUint32BE(); // Unknown 0x00000004 compression ratio?
+ _stream->readUint32BE(); // Unknown 0x00000A2C
+
+ _audioTrack = new StreamAudioTrack(audioCodecTag, audioSampleRate, audioChannels);
+ addTrack(_audioTrack);
+ break;
+
+ case MKTAG('S', 'S', 'M', 'P'):
+ // Audio data
+ break;
+ default:
+ warning("Sherlock 3DO movie: Unknown subtype inside FILM packet");
+ close();
+ return false;
+ }
+ break;
+ }
+
+ case MKTAG('C','T','R','L'):
+ case MKTAG('F','I','L','L'): // filler chunk, fills to certain boundary
+ case MKTAG('D','A','C','Q'):
+ case MKTAG('J','O','I','N'): // add cel data (not used in sherlock)
+ // Ignore these chunks
+ break;
+
+ case MKTAG('S','H','D','R'):
+ // Happens for EA logo, seems to be garbage data right at the start of the file
+ break;
+
+ default:
+ warning("Unknown chunk-tag '%s' inside Sherlock 3DO movie", tag2str(chunkTag));
+ close();
+ return false;
+ }
+
+ if ((_videoTrack) && (_audioTrack))
+ break;
+
+ // Seek to next chunk
+ _stream->seek(dataStartOffset + chunkSize);
+ }
+
+ // Bail if we didn't find video + audio
+ if ((!_videoTrack) || (!_audioTrack)) {
+ close();
+ return false;
+ }
+
+ // Rewind back to the beginning
+ _stream->seek(0);
+
+ return true;
+}
+
+void Scalpel3DOMovieDecoder::close() {
+ Video::VideoDecoder::close();
+
+ delete _stream; _stream = 0;
+ _videoTrack = 0;
+}
+
+// We try to at least decode 1 frame
+// and also try to get at least 0.5 seconds of audio queued up
+void Scalpel3DOMovieDecoder::readNextPacket() {
+ uint32 currentMovieTime = getTime();
+ uint32 wantedAudioQueued = currentMovieTime + 500; // always try to be 0.500 seconds in front of movie time
+
+ int32 chunkOffset = 0;
+ int32 dataStartOffset = 0;
+ int32 nextChunkOffset = 0;
+ uint32 chunkTag = 0;
+ uint32 chunkSize = 0;
+
+ uint32 videoSubType = 0;
+ uint32 videoTimeStamp = 0;
+ uint32 videoFrameSize = 0;
+ uint32 audioSubType = 0;
+ uint32 audioBytes = 0;
+ bool videoGotFrame = false;
+ bool videoDone = false;
+ bool audioDone = false;
+
+ // Seek to smallest stream offset
+ if (_streamVideoOffset <= _streamAudioOffset) {
+ _stream->seek(_streamVideoOffset);
+ } else {
+ _stream->seek(_streamAudioOffset);
+ }
+
+ if (wantedAudioQueued <= _audioTrack->getTotalAudioQueued()) {
+ // already got enough audio queued up
+ audioDone = true;
+ }
+
+ while (1) {
+ chunkOffset = _stream->pos();
+ assert(chunkOffset >= 0);
+
+ // Read chunk header
+ chunkTag = _stream->readUint32BE();
+ chunkSize = _stream->readUint32BE() - 8;
+
+ // Calculate offsets
+ dataStartOffset = _stream->pos();
+ assert(dataStartOffset >= 0);
+ nextChunkOffset = dataStartOffset + chunkSize;
+
+ //warning("offset %lx - tag %lx", dataStartOffset, tag);
+
+ if (_stream->eos())
+ break;
+
+ switch (chunkTag) {
+ case MKTAG('F','I','L','M'):
+ videoTimeStamp = _stream->readUint32BE();
+ _stream->skip(4); // Unknown
+ videoSubType = _stream->readUint32BE();
+
+ switch (videoSubType) {
+ case MKTAG('F', 'H', 'D', 'R'):
+ // Ignore video header
+ break;
+
+ case MKTAG('F', 'R', 'M', 'E'):
+ // Found frame data
+ if (_streamVideoOffset <= chunkOffset) {
+ // We are at an offset that is still relevant to video decoding
+ if (!videoDone) {
+ if (!videoGotFrame) {
+ // We haven't decoded any frame yet, so do so now
+ _stream->readUint32BE();
+ videoFrameSize = _stream->readUint32BE();
+ _videoTrack->decodeFrame(_stream->readStream(videoFrameSize), videoTimeStamp);
+
+ _streamVideoOffset = nextChunkOffset;
+ videoGotFrame = true;
+
+ } else {
+ // Already decoded a frame, so get timestamp of follow-up frame
+ // and then we are done with video
+
+ // Calculate next frame time
+ // 3DO clock time for movies runs at 240Hh, that's why timestamps are based on 240.
+ uint32 currentFrameStartTime = _videoTrack->getNextFrameStartTime();
+ uint32 nextFrameStartTime = videoTimeStamp * 1000 / 240;
+ assert(currentFrameStartTime <= nextFrameStartTime);
+ _videoTrack->setNextFrameStartTime(nextFrameStartTime);
+
+ // next time we want to start at the current chunk
+ _streamVideoOffset = chunkOffset;
+ videoDone = true;
+ }
+ }
+ }
+ break;
+
+ default:
+ error("Sherlock 3DO movie: Unknown subtype inside FILM packet");
+ break;
+ }
+ break;
+
+ case MKTAG('S','N','D','S'):
+ _stream->skip(8);
+ audioSubType = _stream->readUint32BE();
+
+ switch (audioSubType) {
+ case MKTAG('S', 'H', 'D', 'R'):
+ // Ignore the audio header
+ break;
+
+ case MKTAG('S', 'S', 'M', 'P'):
+ // Got audio chunk
+ if (_streamAudioOffset <= chunkOffset) {
+ // We are at an offset that is still relevant to audio decoding
+ if (!audioDone) {
+ audioBytes = _stream->readUint32BE();
+ _audioTrack->queueAudio(_stream, audioBytes);
+
+ _streamAudioOffset = nextChunkOffset;
+ if (wantedAudioQueued <= _audioTrack->getTotalAudioQueued()) {
+ // Got enough audio
+ audioDone = true;
+ }
+ }
+ }
+ break;
+
+ default:
+ error("Sherlock 3DO movie: Unknown subtype inside SNDS packet");
+ break;
+ }
+ break;
+
+ case MKTAG('C','T','R','L'):
+ case MKTAG('F','I','L','L'): // filler chunk, fills to certain boundary
+ case MKTAG('D','A','C','Q'):
+ case MKTAG('J','O','I','N'): // add cel data (not used in sherlock)
+ // Ignore these chunks
+ break;
+
+ case MKTAG('S','H','D','R'):
+ // Happens for EA logo, seems to be garbage data right at the start of the file
+ break;
+
+ default:
+ error("Unknown chunk-tag '%s' inside Sherlock 3DO movie", tag2str(chunkTag));
+ }
+
+ // Always seek to end of chunk
+ // Sometimes not all of the chunk is filled with audio
+ _stream->seek(nextChunkOffset);
+
+ if ((videoDone) && (audioDone)) {
+ return;
+ }
+ }
+}
+
+Scalpel3DOMovieDecoder::StreamVideoTrack::StreamVideoTrack(uint32 width, uint32 height, uint32 codecTag, uint32 frameCount) {
+ _width = width;
+ _height = height;
+ _frameCount = frameCount;
+ _curFrame = -1;
+ _nextFrameStartTime = 0;
+
+ // Create the Cinepak decoder, if we're using it
+ if (codecTag == MKTAG('c', 'v', 'i', 'd'))
+ _codec = new Image::CinepakDecoder();
+ else
+ error("Unsupported Sherlock 3DO movie video codec tag '%s'", tag2str(codecTag));
+}
+
+Scalpel3DOMovieDecoder::StreamVideoTrack::~StreamVideoTrack() {
+ delete _codec;
+}
+
+bool Scalpel3DOMovieDecoder::StreamVideoTrack::endOfTrack() const {
+ return getCurFrame() >= getFrameCount() - 1;
+}
+
+Graphics::PixelFormat Scalpel3DOMovieDecoder::StreamVideoTrack::getPixelFormat() const {
+ return _codec->getPixelFormat();
+}
+
+void Scalpel3DOMovieDecoder::StreamVideoTrack::decodeFrame(Common::SeekableReadStream *stream, uint32 videoTimeStamp) {
+ _surface = _codec->decodeFrame(*stream);
+ _curFrame++;
+}
+
+Scalpel3DOMovieDecoder::StreamAudioTrack::StreamAudioTrack(uint32 codecTag, uint32 sampleRate, uint32 channels) {
+ switch (codecTag) {
+ case MKTAG('A','D','P','4'):
+ case MKTAG('S','D','X','2'):
+ // ADP4 + SDX2 are both allowed
+ break;
+
+ default:
+ error("Unsupported Sherlock 3DO movie audio codec tag '%s'", tag2str(codecTag));
+ }
+
+ _totalAudioQueued = 0; // currently 0 milliseconds queued
+
+ _codecTag = codecTag;
+ _sampleRate = sampleRate;
+ switch (channels) {
+ case 1:
+ _stereo = false;
+ break;
+ case 2:
+ _stereo = true;
+ break;
+ default:
+ error("Unsupported Sherlock 3DO movie audio channels %d", channels);
+ }
+
+ _audioStream = Audio::makeQueuingAudioStream(sampleRate, _stereo);
+
+ // reset audio decoder persistent spaces
+ memset(&_ADP4_PersistentSpace, 0, sizeof(_ADP4_PersistentSpace));
+ memset(&_SDX2_PersistentSpace, 0, sizeof(_SDX2_PersistentSpace));
+}
+
+Scalpel3DOMovieDecoder::StreamAudioTrack::~StreamAudioTrack() {
+ delete _audioStream;
+// free(_ADP4_PersistentSpace);
+// free(_SDX2_PersistentSpace);
+}
+
+void Scalpel3DOMovieDecoder::StreamAudioTrack::queueAudio(Common::SeekableReadStream *stream, uint32 size) {
+ Common::SeekableReadStream *compressedAudioStream = 0;
+ Audio::RewindableAudioStream *audioStream = 0;
+ uint32 audioLengthMSecs = 0;
+
+ // Read the specified chunk into memory
+ compressedAudioStream = stream->readStream(size);
+
+ switch(_codecTag) {
+ case MKTAG('A','D','P','4'):
+ audioStream = Audio::make3DO_ADP4AudioStream(compressedAudioStream, _sampleRate, _stereo, &audioLengthMSecs, DisposeAfterUse::YES, &_ADP4_PersistentSpace);
+ break;
+ case MKTAG('S','D','X','2'):
+ audioStream = Audio::make3DO_SDX2AudioStream(compressedAudioStream, _sampleRate, _stereo, &audioLengthMSecs, DisposeAfterUse::YES, &_SDX2_PersistentSpace);
+ break;
+ default:
+ break;
+ }
+ if (audioStream) {
+ _totalAudioQueued += audioLengthMSecs;
+ _audioStream->queueAudioStream(audioStream, DisposeAfterUse::YES);
+ } else {
+ // in case there was an error
+ delete compressedAudioStream;
+ }
+}
+
+Audio::AudioStream *Scalpel3DOMovieDecoder::StreamAudioTrack::getAudioStream() const {
+ return _audioStream;
+}
+
+// Test-code
+
+// Code for showing a movie. Only meant for testing/debug purposes
+bool Scalpel3DOMoviePlay(const char *filename, Common::Point pos) {
+ Scalpel3DOMovieDecoder *videoDecoder = new Scalpel3DOMovieDecoder();
+
+ if (!videoDecoder->loadFile(filename)) {
+ warning("Scalpel3DOMoviePlay: could not open '%s'", filename);
+ return false;
+ }
+
+ bool skipVideo = false;
+ //byte bytesPerPixel = videoDecoder->getPixelFormat().bytesPerPixel;
+ uint16 width = videoDecoder->getWidth();
+ uint16 height = videoDecoder->getHeight();
+ //uint16 pitch = videoDecoder->getWidth() * bytesPerPixel;
+
+ videoDecoder->start();
+
+ while (!g_engine->shouldQuit() && !videoDecoder->endOfVideo() && (!skipVideo)) {
+ if (videoDecoder->needsUpdate()) {
+ const Graphics::Surface *frame = videoDecoder->decodeNextFrame();
+
+ if (frame) {
+ g_system->copyRectToScreen(frame->getPixels(), frame->pitch, pos.x, pos.y, width, height);
+ g_system->updateScreen();
+ }
+ }
+
+ Common::Event event;
+ while (g_system->getEventManager()->pollEvent(event)) {
+ if ((event.type == Common::EVENT_KEYDOWN && event.kbd.keycode == Common::KEYCODE_ESCAPE))
+ skipVideo = true;
+ }
+
+ g_system->delayMillis(10);
+ }
+ videoDecoder->close();
+ delete videoDecoder;
+
+ return !skipVideo;
+}
+
+} // End of namespace Sherlock
diff --git a/engines/sherlock/scalpel/3do/movie_decoder.h b/engines/sherlock/scalpel/3do/movie_decoder.h
new file mode 100644
index 0000000000..9f1670fc6c
--- /dev/null
+++ b/engines/sherlock/scalpel/3do/movie_decoder.h
@@ -0,0 +1,127 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public 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_MOVIE_DECODER_H
+#define SHERLOCK_SCALPEL_3DO_MOVIE_DECODER_H
+
+#include "common/rect.h"
+#include "video/video_decoder.h"
+#include "audio/decoders/3do.h"
+
+namespace Audio {
+class QueuingAudioStream;
+}
+
+namespace Common {
+class SeekableReadStream;
+}
+
+namespace Image {
+class Codec;
+}
+
+namespace Sherlock {
+
+class Scalpel3DOMovieDecoder : public Video::VideoDecoder {
+public:
+ Scalpel3DOMovieDecoder();
+ ~Scalpel3DOMovieDecoder();
+
+ bool loadStream(Common::SeekableReadStream *stream);
+ void close();
+
+protected:
+ void readNextPacket();
+
+private:
+ int32 _streamVideoOffset; /* current stream offset for video decoding */
+ int32 _streamAudioOffset; /* current stream offset for audio decoding */
+
+private:
+ class StreamVideoTrack : public VideoTrack {
+ public:
+ StreamVideoTrack(uint32 width, uint32 height, uint32 codecTag, uint32 frameCount);
+ ~StreamVideoTrack();
+
+ bool endOfTrack() const;
+
+ uint16 getWidth() const { return _width; }
+ uint16 getHeight() const { return _height; }
+ Graphics::PixelFormat getPixelFormat() const;
+ int getCurFrame() const { return _curFrame; }
+ int getFrameCount() const { return _frameCount; }
+ void setNextFrameStartTime(uint32 nextFrameStartTime) { _nextFrameStartTime = nextFrameStartTime; }
+ uint32 getNextFrameStartTime() const { return _nextFrameStartTime; }
+ const Graphics::Surface *decodeNextFrame() { return _surface; }
+
+ void decodeFrame(Common::SeekableReadStream *stream, uint32 videoTimeStamp);
+
+ private:
+ const Graphics::Surface *_surface;
+
+ int _curFrame;
+ uint32 _frameCount;
+ uint32 _nextFrameStartTime;
+
+ Image::Codec *_codec;
+ uint16 _width, _height;
+ };
+
+ class StreamAudioTrack : public AudioTrack {
+ public:
+ StreamAudioTrack(uint32 codecTag, uint32 sampleRate, uint32 channels);
+ ~StreamAudioTrack();
+
+ void queueAudio(Common::SeekableReadStream *stream, uint32 size);
+
+ 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);
+
+ uint32 _codecTag;
+ uint16 _sampleRate;
+ bool _stereo;
+
+ Audio::audio_3DO_ADP4_PersistentSpace _ADP4_PersistentSpace;
+ Audio::audio_3DO_SDX2_PersistentSpace _SDX2_PersistentSpace;
+ };
+
+ Common::SeekableReadStream *_stream;
+ StreamVideoTrack *_videoTrack;
+ StreamAudioTrack *_audioTrack;
+};
+
+// Testing
+extern bool Scalpel3DOMoviePlay(const char *filename, Common::Point pos);
+
+} // End of namespace Sherlock
+
+#endif
diff --git a/engines/sherlock/scalpel/drivers/adlib.cpp b/engines/sherlock/scalpel/drivers/adlib.cpp
index db1151c841..29a39f0c39 100644
--- a/engines/sherlock/scalpel/drivers/adlib.cpp
+++ b/engines/sherlock/scalpel/drivers/adlib.cpp
@@ -35,21 +35,21 @@ namespace Sherlock {
#define SHERLOCK_ADLIB_VOICES_COUNT 9
#define SHERLOCK_ADLIB_NOTES_COUNT 96
-byte adlib_Operator1Register[SHERLOCK_ADLIB_VOICES_COUNT] = {
+byte operator1Register[SHERLOCK_ADLIB_VOICES_COUNT] = {
0x00, 0x01, 0x02, 0x08, 0x09, 0x0A, 0x10, 0x11, 0x12
};
-byte adlib_Operator2Register[SHERLOCK_ADLIB_VOICES_COUNT] = {
+byte operator2Register[SHERLOCK_ADLIB_VOICES_COUNT] = {
0x03, 0x04, 0x05, 0x0B, 0x0C, 0x0D, 0x13, 0x14, 0x15
};
-struct adlib_percussionChannelEntry {
+struct percussionChannelEntry {
byte requiredNote;
byte replacementNote;
};
// hardcoded, dumped from ADHOM.DRV
-const adlib_percussionChannelEntry adlib_percussionChannelTable[SHERLOCK_ADLIB_VOICES_COUNT] = {
+const percussionChannelEntry percussionChannelTable[SHERLOCK_ADLIB_VOICES_COUNT] = {
{ 0x00, 0x00 },
{ 0x00, 0x00 },
{ 0x00, 0x00 },
@@ -61,7 +61,7 @@ const adlib_percussionChannelEntry adlib_percussionChannelTable[SHERLOCK_ADLIB_V
{ 0x26, 0x1E }
};
-struct adlib_InstrumentEntry {
+struct InstrumentEntry {
byte reg20op1;
byte reg40op1;
byte reg60op1;
@@ -77,7 +77,7 @@ struct adlib_InstrumentEntry {
};
// hardcoded, dumped from ADHOM.DRV
-const adlib_InstrumentEntry adlib_instrumentTable[] = {
+const InstrumentEntry instrumentTable[] = {
{ 0x71, 0x89, 0x51, 0x11, 0x00, 0x61, 0x23, 0x42, 0x15, 0x01, 0x02, 0xF4 },
{ 0x22, 0x20, 0x97, 0x89, 0x00, 0xA2, 0x1F, 0x70, 0x07, 0x00, 0x0A, 0xF4 },
{ 0x70, 0x1A, 0x64, 0x13, 0x00, 0x20, 0x1F, 0x53, 0x46, 0x00, 0x0E, 0xF4 },
@@ -203,7 +203,7 @@ const adlib_InstrumentEntry adlib_instrumentTable[] = {
};
// hardcoded, dumped from ADHOM.DRV
-uint16 adlib_FrequencyLookUpTable[SHERLOCK_ADLIB_NOTES_COUNT] = {
+uint16 frequencyLookUpTable[SHERLOCK_ADLIB_NOTES_COUNT] = {
0x0158, 0x016C, 0x0182, 0x0199, 0x01B1, 0x01CB, 0x01E6, 0x0203, 0x0222, 0x0242,
0x0265, 0x0289, 0x0558, 0x056C, 0x0582, 0x0599, 0x05B1, 0x05CB, 0x05E6, 0x0603,
0x0622, 0x0642, 0x0665, 0x0689, 0x0958, 0x096C, 0x0982, 0x0999, 0x09B1, 0x09CB,
@@ -216,13 +216,14 @@ uint16 adlib_FrequencyLookUpTable[SHERLOCK_ADLIB_NOTES_COUNT] = {
0x1DE6, 0x1E03, 0x1E22, 0x1E42, 0x1E65, 0x1E89
};
-class MidiDriver_AdLib : public MidiDriver_Emulated {
+class MidiDriver_SH_AdLib : public MidiDriver {
public:
- MidiDriver_AdLib(Audio::Mixer *mixer)
- : MidiDriver_Emulated(mixer), _masterVolume(15), _opl(0) {
+ MidiDriver_SH_AdLib(Audio::Mixer *mixer)
+ : _masterVolume(15), _opl(0),
+ _adlibTimerProc(0), _adlibTimerParam(0), _isOpen(false) {
memset(_voiceChannelMapping, 0, sizeof(_voiceChannelMapping));
}
- virtual ~MidiDriver_AdLib() { }
+ virtual ~MidiDriver_SH_AdLib() { }
// MidiDriver
int open();
@@ -230,15 +231,13 @@ public:
void send(uint32 b);
MidiChannel *allocateChannel() { return NULL; }
MidiChannel *getPercussionChannel() { return NULL; }
+ bool isOpen() const { return _isOpen; }
+ uint32 getBaseTempo() { return 1000000 / OPL::OPL::kDefaultCallbackFrequency; }
- // AudioStream
- bool isStereo() const { return false; }
- int getRate() const { return _mixer->getOutputRate(); }
int getPolyphony() const { return SHERLOCK_ADLIB_VOICES_COUNT; }
bool hasRhythmChannel() const { return false; }
- // MidiDriver_Emulated
- void generateSamples(int16 *buf, int len);
+ virtual void setTimerCallback(void *timerParam, Common::TimerManager::TimerProc timerProc);
void setVolume(byte volume);
virtual uint32 property(int prop, uint32 param);
@@ -249,7 +248,7 @@ private:
struct adlib_ChannelEntry {
bool inUse;
uint16 inUseTimer;
- const adlib_InstrumentEntry *currentInstrumentPtr;
+ const InstrumentEntry *currentInstrumentPtr;
byte currentNote;
byte currentA0hReg;
byte currentB0hReg;
@@ -261,19 +260,22 @@ private:
OPL::OPL *_opl;
int _masterVolume;
+ Common::TimerManager::TimerProc _adlibTimerProc;
+ void *_adlibTimerParam;
+
+ bool _isOpen;
+
// points to a MIDI channel for each of the new voice channels
byte _voiceChannelMapping[SHERLOCK_ADLIB_VOICES_COUNT];
// stores information about all FM voice channels
adlib_ChannelEntry _channels[SHERLOCK_ADLIB_VOICES_COUNT];
-protected:
void onTimer();
-private:
void resetAdLib();
- void resetAdLib_OperatorRegisters(byte baseRegister, byte value);
- void resetAdLib_FMVoiceChannelRegisters(byte baseRegister, byte value);
+ void resetAdLibOperatorRegisters(byte baseRegister, byte value);
+ void resetAdLibFMVoiceChannelRegisters(byte baseRegister, byte value);
void programChange(byte MIDIchannel, byte parameter);
void setRegister(int reg, int value);
@@ -284,32 +286,31 @@ private:
void pitchBendChange(byte MIDIchannel, byte parameter1, byte parameter2);
};
-int MidiDriver_AdLib::open() {
- int rate = _mixer->getOutputRate();
-
- debug(3, "ADLIB: Starting driver");
+int MidiDriver_SH_AdLib::open() {
+ debugC(kDebugLevelAdLibDriver, "AdLib: starting driver");
_opl = OPL::Config::create(OPL::Config::kOpl2);
if (!_opl)
return -1;
- _opl->init(rate);
+ _opl->init();
- MidiDriver_Emulated::open();
+ _isOpen = true;
- _mixer->playStream(Audio::Mixer::kPlainSoundType, &_mixerSoundHandle, this, -1, _mixer->kMaxChannelVolume, 0, DisposeAfterUse::NO);
+ _opl->start(new Common::Functor0Mem<void, MidiDriver_SH_AdLib>(this, &MidiDriver_SH_AdLib::onTimer));
return 0;
}
-void MidiDriver_AdLib::close() {
- _mixer->stopHandle(_mixerSoundHandle);
+void MidiDriver_SH_AdLib::close() {
+ // Stop the OPL timer
+ _opl->stop();
delete _opl;
}
-void MidiDriver_AdLib::setVolume(byte volume) {
+void MidiDriver_SH_AdLib::setVolume(byte volume) {
_masterVolume = volume;
//renewNotes(-1, true);
}
@@ -317,7 +318,13 @@ void MidiDriver_AdLib::setVolume(byte volume) {
// this should/must get called per tick
// original driver did this before MIDI data processing on each tick
// we do it atm after MIDI data processing
-void MidiDriver_AdLib::onTimer() {
+void MidiDriver_SH_AdLib::onTimer() {
+ if (_adlibTimerProc)
+ (*_adlibTimerProc)(_adlibTimerParam);
+
+ // this should/must get called per tick
+ // original driver did this before MIDI data processing on each tick
+ // we do it atm after MIDI data processing
for (byte FMvoiceChannel = 0; FMvoiceChannel < SHERLOCK_ADLIB_VOICES_COUNT; FMvoiceChannel++) {
if (_channels[FMvoiceChannel].inUse) {
_channels[FMvoiceChannel].inUseTimer++;
@@ -326,7 +333,7 @@ void MidiDriver_AdLib::onTimer() {
}
// Called when a music track got loaded into memory
-void MidiDriver_AdLib::newMusicData(byte *musicData, int32 musicDataSize) {
+void MidiDriver_SH_AdLib::newMusicData(byte *musicData, int32 musicDataSize) {
assert(musicDataSize >= 0x7F);
// MIDI Channel <-> FM Voice Channel mapping at offset 0x22 of music data
memcpy(&_voiceChannelMapping, musicData + 0x22, 9);
@@ -338,7 +345,7 @@ void MidiDriver_AdLib::newMusicData(byte *musicData, int32 musicDataSize) {
memset(&_channels, 0, sizeof(_channels));
}
-void MidiDriver_AdLib::resetAdLib() {
+void MidiDriver_SH_AdLib::resetAdLib() {
setRegister(0x01, 0x20); // enable waveform control on both operators
setRegister(0x04, 0xE0); // Timer control
@@ -347,17 +354,17 @@ void MidiDriver_AdLib::resetAdLib() {
setRegister(0xBD, 0); // disable Rhythm
// reset FM voice instrument data
- resetAdLib_OperatorRegisters(0x20, 0);
- resetAdLib_OperatorRegisters(0x60, 0);
- resetAdLib_OperatorRegisters(0x80, 0);
- resetAdLib_FMVoiceChannelRegisters(0xA0, 0);
- resetAdLib_FMVoiceChannelRegisters(0xB0, 0);
- resetAdLib_FMVoiceChannelRegisters(0xC0, 0);
- resetAdLib_OperatorRegisters(0xE0, 0);
- resetAdLib_OperatorRegisters(0x40, 0x3F);
+ resetAdLibOperatorRegisters(0x20, 0);
+ resetAdLibOperatorRegisters(0x60, 0);
+ resetAdLibOperatorRegisters(0x80, 0);
+ resetAdLibFMVoiceChannelRegisters(0xA0, 0);
+ resetAdLibFMVoiceChannelRegisters(0xB0, 0);
+ resetAdLibFMVoiceChannelRegisters(0xC0, 0);
+ resetAdLibOperatorRegisters(0xE0, 0);
+ resetAdLibOperatorRegisters(0x40, 0x3F);
}
-void MidiDriver_AdLib::resetAdLib_OperatorRegisters(byte baseRegister, byte value) {
+void MidiDriver_SH_AdLib::resetAdLibOperatorRegisters(byte baseRegister, byte value) {
byte operatorIndex;
for (operatorIndex = 0; operatorIndex < 0x16; operatorIndex++) {
@@ -373,7 +380,7 @@ void MidiDriver_AdLib::resetAdLib_OperatorRegisters(byte baseRegister, byte valu
}
}
-void MidiDriver_AdLib::resetAdLib_FMVoiceChannelRegisters(byte baseRegister, byte value) {
+void MidiDriver_SH_AdLib::resetAdLibFMVoiceChannelRegisters(byte baseRegister, byte value) {
byte FMvoiceChannel;
for (FMvoiceChannel = 0; FMvoiceChannel < SHERLOCK_ADLIB_VOICES_COUNT; FMvoiceChannel++) {
@@ -382,7 +389,7 @@ void MidiDriver_AdLib::resetAdLib_FMVoiceChannelRegisters(byte baseRegister, byt
}
// MIDI messages can be found at http://www.midi.org/techspecs/midimessages.php
-void MidiDriver_AdLib::send(uint32 b) {
+void MidiDriver_SH_AdLib::send(uint32 b) {
byte command = b & 0xf0;
byte channel = b & 0xf;
byte op1 = (b >> 8) & 0xff;
@@ -406,22 +413,18 @@ void MidiDriver_AdLib::send(uint32 b) {
// Aftertouch doesn't seem to be implemented in the Sherlock Holmes adlib driver
break;
case 0xe0:
- warning("pitch bend change");
+ debugC(kDebugLevelAdLibDriver, "AdLib: pitch bend change");
pitchBendChange(channel, op1, op2);
break;
case 0xf0: // SysEx
- warning("SysEx: %x", b);
+ warning("ADLIB: SysEx: %x", b);
break;
default:
warning("ADLIB: Unknown event %02x", command);
}
}
-void MidiDriver_AdLib::generateSamples(int16 *data, int len) {
- _opl->readBuffer(data, len);
-}
-
-void MidiDriver_AdLib::noteOn(byte MIDIchannel, byte note, byte velocity) {
+void MidiDriver_SH_AdLib::noteOn(byte MIDIchannel, byte note, byte velocity) {
int16 oldestInUseChannel = -1;
uint16 oldestInUseTimer = 0;
@@ -453,7 +456,7 @@ void MidiDriver_AdLib::noteOn(byte MIDIchannel, byte note, byte velocity) {
}
if (oldestInUseChannel >= 0) {
// channel found
- warning("used In-Use channel");
+ debugC(kDebugLevelAdLibDriver, "AdLib: used In-Use channel");
// original driver used note 0, we use the current note
// because using note 0 could create a bad note (out of index) and we check that. Original driver didn't.
voiceOnOff(oldestInUseChannel, false, _channels[oldestInUseChannel].currentNote, 0);
@@ -464,27 +467,26 @@ void MidiDriver_AdLib::noteOn(byte MIDIchannel, byte note, byte velocity) {
voiceOnOff(oldestInUseChannel, true, note, velocity);
return;
}
- warning("MIDI channel not mapped/all FM voice channels busy %d", MIDIchannel);
+ debugC(kDebugLevelAdLibDriver, "AdLib: MIDI channel not mapped/all FM voice channels busy %d", MIDIchannel);
} else {
// Percussion channel
- warning("percussion!");
for (byte FMvoiceChannel = 0; FMvoiceChannel < SHERLOCK_ADLIB_VOICES_COUNT; FMvoiceChannel++) {
if (_voiceChannelMapping[FMvoiceChannel] == MIDIchannel) {
- if (note == adlib_percussionChannelTable[FMvoiceChannel].requiredNote) {
+ if (note == percussionChannelTable[FMvoiceChannel].requiredNote) {
_channels[FMvoiceChannel].inUse = true;
_channels[FMvoiceChannel].currentNote = note;
- voiceOnOff(FMvoiceChannel, true, adlib_percussionChannelTable[FMvoiceChannel].replacementNote, velocity);
+ voiceOnOff(FMvoiceChannel, true, percussionChannelTable[FMvoiceChannel].replacementNote, velocity);
return;
}
}
}
- warning("percussion MIDI channel not mapped/all FM voice channels busy");
+ debugC(kDebugLevelAdLibDriver, "AdLib: percussion MIDI channel not mapped/all FM voice channels busy");
}
}
-void MidiDriver_AdLib::noteOff(byte MIDIchannel, byte note) {
+void MidiDriver_SH_AdLib::noteOff(byte MIDIchannel, byte note) {
for (byte FMvoiceChannel = 0; FMvoiceChannel < SHERLOCK_ADLIB_VOICES_COUNT; FMvoiceChannel++) {
if (_voiceChannelMapping[FMvoiceChannel] == MIDIchannel) {
if (_channels[FMvoiceChannel].currentNote == note) {
@@ -496,7 +498,7 @@ void MidiDriver_AdLib::noteOff(byte MIDIchannel, byte note) {
// not-percussion
voiceOnOff(FMvoiceChannel, false, note, 0);
} else {
- voiceOnOff(FMvoiceChannel, false, adlib_percussionChannelTable[FMvoiceChannel].replacementNote, 0);
+ voiceOnOff(FMvoiceChannel, false, percussionChannelTable[FMvoiceChannel].replacementNote, 0);
}
return;
}
@@ -504,7 +506,7 @@ void MidiDriver_AdLib::noteOff(byte MIDIchannel, byte note) {
}
}
-void MidiDriver_AdLib::voiceOnOff(byte FMvoiceChannel, bool keyOn, byte note, byte velocity) {
+void MidiDriver_SH_AdLib::voiceOnOff(byte FMvoiceChannel, bool keyOn, byte note, byte velocity) {
byte frequencyOffset = 0;
uint16 frequency = 0;
byte op2RegAdjust = 0;
@@ -519,10 +521,10 @@ void MidiDriver_AdLib::voiceOnOff(byte FMvoiceChannel, bool keyOn, byte note, by
frequencyOffset = note;
}
if (frequencyOffset >= SHERLOCK_ADLIB_NOTES_COUNT) {
- warning("CRITICAL - bad note!!!");
+ warning("CRITICAL - AdLib driver: bad note!!!");
return;
}
- frequency = adlib_FrequencyLookUpTable[frequencyOffset];
+ frequency = frequencyLookUpTable[frequencyOffset];
if (keyOn) {
// adjust register 40h
@@ -530,7 +532,7 @@ void MidiDriver_AdLib::voiceOnOff(byte FMvoiceChannel, bool keyOn, byte note, by
regValue40h = _channels[FMvoiceChannel].currentInstrumentPtr->reg40op2;
}
regValue40h = regValue40h - (velocity >> 3);
- op2RegAdjust = adlib_Operator2Register[FMvoiceChannel];
+ op2RegAdjust = operator2Register[FMvoiceChannel];
setRegister(0x40 + op2RegAdjust, regValue40h);
}
@@ -546,7 +548,7 @@ void MidiDriver_AdLib::voiceOnOff(byte FMvoiceChannel, bool keyOn, byte note, by
_channels[FMvoiceChannel].currentB0hReg = regValueB0h;
}
-void MidiDriver_AdLib::pitchBendChange(byte MIDIchannel, byte parameter1, byte parameter2) {
+void MidiDriver_SH_AdLib::pitchBendChange(byte MIDIchannel, byte parameter1, byte parameter2) {
uint16 channelFrequency = 0;
byte channelRegB0hWithoutFrequency = 0;
uint16 parameter = 0;
@@ -585,20 +587,20 @@ void MidiDriver_AdLib::pitchBendChange(byte MIDIchannel, byte parameter1, byte p
}
}
-void MidiDriver_AdLib::programChange(byte MIDIchannel, byte op1) {
- const adlib_InstrumentEntry *instrumentPtr;
+void MidiDriver_SH_AdLib::programChange(byte MIDIchannel, byte op1) {
+ const InstrumentEntry *instrumentPtr;
byte op1Reg = 0;
byte op2Reg = 0;
// setup instrument
- instrumentPtr = &adlib_instrumentTable[op1];
+ instrumentPtr = &instrumentTable[op1];
//warning("program change for MIDI channel %d, instrument id %d", MIDIchannel, op1);
for (byte FMvoiceChannel = 0; FMvoiceChannel < SHERLOCK_ADLIB_VOICES_COUNT; FMvoiceChannel++) {
if (_voiceChannelMapping[FMvoiceChannel] == MIDIchannel) {
- op1Reg = adlib_Operator1Register[FMvoiceChannel];
- op2Reg = adlib_Operator2Register[FMvoiceChannel];
+ op1Reg = operator1Register[FMvoiceChannel];
+ op2Reg = operator2Register[FMvoiceChannel];
setRegister(0x20 + op1Reg, instrumentPtr->reg20op1);
setRegister(0x40 + op1Reg, instrumentPtr->reg40op1);
@@ -619,21 +621,26 @@ void MidiDriver_AdLib::programChange(byte MIDIchannel, byte op1) {
}
}
}
-void MidiDriver_AdLib::setRegister(int reg, int value) {
+void MidiDriver_SH_AdLib::setRegister(int reg, int value) {
_opl->write(0x220, reg);
_opl->write(0x221, value);
}
-uint32 MidiDriver_AdLib::property(int prop, uint32 param) {
+uint32 MidiDriver_SH_AdLib::property(int prop, uint32 param) {
return 0;
}
-MidiDriver *MidiDriver_AdLib_create() {
- return new MidiDriver_AdLib(g_system->getMixer());
+void MidiDriver_SH_AdLib::setTimerCallback(void *timerParam, Common::TimerManager::TimerProc timerProc) {
+ _adlibTimerProc = timerProc;
+ _adlibTimerParam = timerParam;
+}
+
+MidiDriver *MidiDriver_SH_AdLib_create() {
+ return new MidiDriver_SH_AdLib(g_system->getMixer());
}
-void MidiDriver_AdLib_newMusicData(MidiDriver *driver, byte *musicData, int32 musicDataSize) {
- static_cast<MidiDriver_AdLib *>(driver)->newMusicData(musicData, musicDataSize);
+void MidiDriver_SH_AdLib_newMusicData(MidiDriver *driver, byte *musicData, int32 musicDataSize) {
+ static_cast<MidiDriver_SH_AdLib *>(driver)->newMusicData(musicData, musicDataSize);
}
-} // End of namespace Sci
+} // End of namespace Sherlock
diff --git a/engines/sherlock/scalpel/drivers/mididriver.h b/engines/sherlock/scalpel/drivers/mididriver.h
index 64213315e8..1b8ceeda3d 100644
--- a/engines/sherlock/scalpel/drivers/mididriver.h
+++ b/engines/sherlock/scalpel/drivers/mididriver.h
@@ -20,8 +20,8 @@
*
*/
-#ifndef SHERLOCK_SOFTSEQ_MIDIDRIVER_H
-#define SHERLOCK_SOFTSEQ_MIDIDRIVER_H
+#ifndef SHERLOCK_SCALPEL_DRIVERS_MIDIDRIVER_H
+#define SHERLOCK_SCALPEL_DRIVERS_MIDIDRIVER_H
#include "sherlock/sherlock.h"
#include "audio/mididrv.h"
@@ -29,9 +29,13 @@
namespace Sherlock {
-extern MidiDriver *MidiDriver_AdLib_create();
-extern void MidiDriver_AdLib_newMusicData(MidiDriver *driver, byte *musicData, int32 musicDataSize);
+extern MidiDriver *MidiDriver_SH_AdLib_create();
+extern void MidiDriver_SH_AdLib_newMusicData(MidiDriver *driver, byte *musicData, int32 musicDataSize);
-} // End of namespace Sci
+extern MidiDriver *MidiDriver_MT32_create();
+extern void MidiDriver_MT32_uploadPatches(MidiDriver *driver, byte *driverData, int32 driverSize);
+extern void MidiDriver_MT32_newMusicData(MidiDriver *driver, byte *musicData, int32 musicDataSize);
-#endif // SHERLOCK_SOFTSEQ_MIDIDRIVER_H
+} // End of namespace Sherlock
+
+#endif // SHERLOCK_SCALPEL_DRIVERS_MIDIDRIVER_H
diff --git a/engines/sherlock/scalpel/drivers/mt32.cpp b/engines/sherlock/scalpel/drivers/mt32.cpp
new file mode 100644
index 0000000000..33e7671719
--- /dev/null
+++ b/engines/sherlock/scalpel/drivers/mt32.cpp
@@ -0,0 +1,282 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public 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/sherlock.h"
+#include "sherlock/scalpel/drivers/mididriver.h"
+
+#include "common/config-manager.h"
+#include "common/file.h"
+#include "common/system.h"
+#include "common/textconsole.h"
+
+//#include "audio/mididrv.h"
+
+namespace Sherlock {
+
+#define SHERLOCK_MT32_CHANNEL_COUNT 16
+
+const byte mt32ReverbDataSysEx[] = {
+ 0x10, 0x00, 0x01, 0x01, 0x05, 0x05, 0xFF
+};
+
+class MidiDriver_MT32 : public MidiDriver {
+public:
+ MidiDriver_MT32() {
+ _driver = NULL;
+ _isOpen = false;
+ _nativeMT32 = false;
+ _baseFreq = 250;
+
+ memset(_MIDIchannelActive, 1, sizeof(_MIDIchannelActive));
+ }
+ virtual ~MidiDriver_MT32();
+
+ // MidiDriver
+ int open();
+ void close();
+ bool isOpen() const { return _isOpen; }
+
+ void send(uint32 b);
+
+ void newMusicData(byte *musicData, int32 musicDataSize);
+
+ MidiChannel *allocateChannel() {
+ if (_driver)
+ return _driver->allocateChannel();
+ return NULL;
+ }
+ MidiChannel *getPercussionChannel() {
+ if (_driver)
+ return _driver->getPercussionChannel();
+ return NULL;
+ }
+
+ void setTimerCallback(void *timer_param, Common::TimerManager::TimerProc timer_proc) {
+ if (_driver)
+ _driver->setTimerCallback(timer_param, timer_proc);
+ }
+
+ uint32 getBaseTempo() {
+ if (_driver) {
+ return _driver->getBaseTempo();
+ }
+ return 1000000 / _baseFreq;
+ }
+
+protected:
+ Common::Mutex _mutex;
+ MidiDriver *_driver;
+ bool _nativeMT32;
+
+ bool _isOpen;
+ int _baseFreq;
+
+private:
+ // points to a MIDI channel for each of the new voice channels
+ byte _MIDIchannelActive[SHERLOCK_MT32_CHANNEL_COUNT];
+
+public:
+ void uploadMT32Patches(byte *driverData, int32 driverSize);
+
+ void mt32SysEx(const byte *&dataPtr, int32 &bytesLeft);
+};
+
+MidiDriver_MT32::~MidiDriver_MT32() {
+ Common::StackLock lock(_mutex);
+ if (_driver) {
+ _driver->setTimerCallback(0, 0);
+ _driver->close();
+ delete _driver;
+ }
+ _driver = NULL;
+}
+
+int MidiDriver_MT32::open() {
+ assert(!_driver);
+
+ debugC(kDebugLevelMT32Driver, "MT32: starting driver");
+
+ // Setup midi driver
+ MidiDriver::DeviceHandle dev = MidiDriver::detectDevice(MDT_MIDI | MDT_PREFER_MT32);
+ MusicType musicType = MidiDriver::getMusicType(dev);
+
+ switch (musicType) {
+ case MT_MT32:
+ _nativeMT32 = true;
+ break;
+ case MT_GM:
+ if (ConfMan.getBool("native_mt32")) {
+ _nativeMT32 = true;
+ }
+ break;
+ default:
+ break;
+ }
+
+ _driver = MidiDriver::createMidi(dev);
+ if (!_driver)
+ return 255;
+
+ if (_nativeMT32)
+ _driver->property(MidiDriver::PROP_CHANNEL_MASK, 0x03FE);
+
+ int ret = _driver->open();
+ if (ret)
+ return ret;
+
+ if (_nativeMT32)
+ _driver->sendMT32Reset();
+ else
+ _driver->sendGMReset();
+
+ return 0;
+}
+
+void MidiDriver_MT32::close() {
+ if (_driver) {
+ _driver->close();
+ }
+}
+
+// Called when a music track got loaded into memory
+void MidiDriver_MT32::newMusicData(byte *musicData, int32 musicDataSize) {
+ assert(musicDataSize >= 0x7F); // Security check
+
+ // MIDI Channel Enable/Disable bytes at offset 0x2 of music data
+ memcpy(&_MIDIchannelActive, musicData + 0x2, SHERLOCK_MT32_CHANNEL_COUNT);
+
+ // Send 16 bytes from offset 0x12 to MT32
+ // All the music tracks of Sherlock seem to contain dummy data
+ // probably a feature, that was used in the game "Ski or Die"
+ // that's why we don't implement this
+
+ // Also send these bytes to MT32 (SysEx) - seems to be reverb configuration
+ if (_nativeMT32) {
+ const byte *reverbData = mt32ReverbDataSysEx;
+ int32 reverbDataSize = sizeof(mt32ReverbDataSysEx);
+ mt32SysEx(reverbData, reverbDataSize);
+ }
+}
+
+void MidiDriver_MT32::uploadMT32Patches(byte *driverData, int32 driverSize) {
+ if (!_driver)
+ return;
+
+ if (!_nativeMT32)
+ return;
+
+ // patch data starts at offset 0x863
+ assert(driverSize == 0x13B9); // Security check
+ assert(driverData[0x863] == 0x7F); // another security check
+
+ const byte *patchPtr = driverData + 0x863;
+ int32 bytesLeft = driverSize - 0x863;
+
+ while(1) {
+ mt32SysEx(patchPtr, bytesLeft);
+
+ assert(bytesLeft);
+ if (*patchPtr == 0x80) // List terminator
+ break;
+ }
+}
+
+void MidiDriver_MT32::mt32SysEx(const byte *&dataPtr, int32 &bytesLeft) {
+ byte sysExMessage[270];
+ uint16 sysExPos = 0;
+ byte sysExByte = 0;
+ uint16 sysExChecksum = 0;
+
+ memset(&sysExMessage, 0, sizeof(sysExMessage));
+
+ sysExMessage[0] = 0x41; // Roland
+ sysExMessage[1] = 0x10;
+ sysExMessage[2] = 0x16; // Model MT32
+ sysExMessage[3] = 0x12; // Command DT1
+
+ sysExPos = 4;
+ sysExChecksum = 0;
+ while (1) {
+ assert(bytesLeft);
+
+ sysExByte = *dataPtr++;
+ bytesLeft--;
+ if (sysExByte == 0xff)
+ break; // Message done
+
+ assert(sysExPos < sizeof(sysExMessage));
+ sysExMessage[sysExPos++] = sysExByte;
+ sysExChecksum -= sysExByte;
+ }
+
+ // Calculate checksum
+ assert(sysExPos < sizeof(sysExMessage));
+ sysExMessage[sysExPos++] = sysExChecksum & 0x7f;
+
+ debugC(kDebugLevelMT32Driver, "MT32: uploading patch data, size %d", sysExPos);
+
+ // Send SysEx
+ _driver->sysEx(sysExMessage, sysExPos);
+
+ // Wait the time it takes to send the SysEx data
+ uint32 delay = (sysExPos + 2) * 1000 / 3125;
+
+ // Plus an additional delay for the MT-32 rev00
+ if (_nativeMT32)
+ delay += 40;
+
+ g_system->delayMillis(delay);
+}
+
+// MIDI messages can be found at http://www.midi.org/techspecs/midimessages.php
+void MidiDriver_MT32::send(uint32 b) {
+ byte command = b & 0xf0;
+ byte channel = b & 0xf;
+
+ if (command == 0xF0) {
+ if (_driver) {
+ _driver->send(b);
+ }
+ return;
+ }
+
+ if (_MIDIchannelActive[channel]) {
+ // Only forward MIDI-data in case the channel is currently enabled via music-data
+ if (_driver) {
+ _driver->send(b);
+ }
+ }
+}
+
+MidiDriver *MidiDriver_MT32_create() {
+ return new MidiDriver_MT32();
+}
+
+void MidiDriver_MT32_newMusicData(MidiDriver *driver, byte *musicData, int32 musicDataSize) {
+ static_cast<MidiDriver_MT32 *>(driver)->newMusicData(musicData, musicDataSize);
+}
+
+void MidiDriver_MT32_uploadPatches(MidiDriver *driver, byte *driverData, int32 driverSize) {
+ static_cast<MidiDriver_MT32 *>(driver)->uploadMT32Patches(driverData, driverSize);
+}
+
+} // End of namespace Sherlock
diff --git a/engines/sherlock/scalpel/scalpel.cpp b/engines/sherlock/scalpel/scalpel.cpp
index 43b69068ab..c3915a1cf2 100644
--- a/engines/sherlock/scalpel/scalpel.cpp
+++ b/engines/sherlock/scalpel/scalpel.cpp
@@ -22,10 +22,16 @@
#include "engines/util.h"
#include "sherlock/scalpel/scalpel.h"
+#include "sherlock/scalpel/scalpel_fixed_text.h"
+#include "sherlock/scalpel/scalpel_map.h"
+#include "sherlock/scalpel/scalpel_people.h"
+#include "sherlock/scalpel/scalpel_scene.h"
#include "sherlock/scalpel/tsage/logo.h"
#include "sherlock/sherlock.h"
#include "sherlock/music.h"
#include "sherlock/animation.h"
+// for 3DO
+#include "sherlock/scalpel/3do/movie_decoder.h"
namespace Sherlock {
@@ -92,280 +98,80 @@ static const byte MAP_SEQUENCES[3][MAX_FRAME] = {
#define MAX_PEOPLE 66
-const char PEOPLE_PORTRAITS[MAX_PEOPLE][5] = {
- { "HOLM" }, // Sherlock Holmes
- { "WATS" }, // Dr. Watson
- { "LEST" }, // Inspector Lestrade
- { "CON1" }, // Constable O'Brien
- { "CON2" }, // Constable Lewis
- { "SHEI" }, // Sheila Parker
- { "HENR" }, // Henry Carruthers
- { "LESL" }, // Lesley (flower girl)
- { "USH1" }, // Usher #1
- { "USH2" }, // Usher #2
- { "FRED" }, // Fredrick Epstein
- { "WORT" }, // Mrs. Worthington
- { "COAC" }, // Coach
- { "PLAY" }, // Player
- { "WBOY" }, // Tim (Waterboy)
- { "JAME" }, // James Sanders
- { "BELL" }, // Belle (perfumerie)
- { "GIRL" }, // Cleaning Girl (perfumerie)
- { "EPST" }, // Epstien in the Opera Balcony
- { "WIGG" }, // Wiggins
- { "PAUL" }, // Paul (Brumwell / Carroway)
- { "BART" }, // Bartender
- { "DIRT" }, // Dirty Drunk
- { "SHOU" }, // Shouting Drunk
- { "STAG" }, // Staggering Drunk
- { "BOUN" }, // Bouncer
- { "SAND" }, // James Sanders - At Home
- { "CORO" }, // The Coroner
- { "EQUE" }, // The Equestrian Shop Keeper
- { "GEOR" }, // George Blackwood
- { "LARS" }, // Lars
- { "PARK" }, // Sheila Parker (happy)
- { "CHEM" }, // Chemist
- { "GREG" }, // Inspector Gregson
- { "LAWY" }, // Jacob Farthington Lawyer
- { "MYCR" }, // Mycroft
- { "SHER" }, // Old Sherman
- { "CHMB" }, // Richard Chemist Stock boy
- { "BARM" }, // Barman
- { "DAND" }, // Dandy Player
- { "ROUG" }, // Rough-looking Player
- { "SPEC" }, // Spectator
- { "HUNT" }, // Robert Hunt
- { "VIOL" }, // Violet Secretary
- { "PETT" }, // Pettigrew
- { "APPL" }, // Augie (apple seller)
- { "ANNA" }, // Anna Carroway
- { "GUAR" }, // Guard
- { "ANTO" }, // Antonio Caruso
- { "TOBY" }, // Toby the Dog
- { "KING" }, // Simon Kingsley
- { "ALFR" }, // Alfred Tobacco Clerk
- { "LADY" }, // Lady Brumwell
- { "ROSA" }, // Madame Rosa
- { "LADB" }, // Lady Brumwell
- { "MOOR" }, // Joseph Moorehead
- { "BEAL" }, // Mrs. Beale
- { "LION" }, // Felix the Lion
- { "HOLL" }, // Hollingston
- { "CALL" }, // Constable Callaghan
- { "JERE" }, // Sergeant Jeremy Duncan
- { "LORD" }, // Lord Brumwell
- { "NIGE" }, // Nigel Jameson
- { "JONA" }, // Jonas (newspaper seller)
- { "DUGA" }, // Constable Dugan
- { "INSP" } // Inspector Lestrade (Scotland Yard)
+struct PeopleData {
+ const char *portrait;
+ const char *name;
+ byte stillSequences[MAX_TALK_SEQUENCES];
+ byte talkSequences[MAX_TALK_SEQUENCES];
};
-const char *const PEOPLE_NAMES[MAX_PEOPLE] = {
- "Sherlock Holmes",
- "Dr. Watson",
- "Inspector Lestrade",
- "Constable O'Brien",
- "Constable Lewis",
- "Sheila Parker",
- "Henry Carruthers",
- "Lesley",
- "An Usher",
- "An Usher",
- "Fredrick Epstein",
- "Mrs. Worthington",
- "The Coach",
- "A Player",
- "Tim",
- "James Sanders",
- "Belle",
- "Cleaning Girl",
- "Fredrick Epstein",
- "Wiggins",
- "Paul",
- "The Bartender",
- "A Dirty Drunk",
- "A Shouting Drunk",
- "A Staggering Drunk",
- "The Bouncer",
- "James Sanders",
- "The Coroner",
- "Reginald Snipes",
- "George Blackwood",
- "Lars",
- "Sheila Parker",
- "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",
- "Lady Brumwell",
- "Joseph Moorehead",
- "Mrs. Beale",
- "Felix",
- "Hollingston",
- "Constable Callaghan",
- "Sergeant Duncan",
- "Lord Brumwell",
- "Nigel Jaimeson",
- "Jonas",
- "Constable Dugan",
- "Inspector Lestrade"
-};
-
-static const byte PEOPLE_STILL_SEQUENCES[MAX_PEOPLE][MAX_TALK_SEQUENCES] = {
- { 1, 0, 0 }, // Sherlock Holmes
- { 6, 0, 0 }, // Dr. Watson
- { 4, 0, 0 }, // Inspector Lestrade
- { 2, 0, 0 }, // Constable #1
- { 2, 0, 0 }, // Constable #2
- { 2, 0, 0 }, // Sheila Parker
- { 3, 0, 0 }, // Henry Carruthers
- { 9, 0, 0 }, // Lesly (flower girl)
- { 13, 0, 0 }, // Usher #1
- { 2, 0, 0 }, // Usher #2
- { 4, 0, 0 }, // Fredrick Epstein
- { 9, 0, 0 }, // Mrs.Worthington
- { 2, 0, 0 }, // Coach
- { 8, 0, 0 }, // Player
- { 13, 0, 0 }, // Waterboy
- { 6, 0, 0 }, // James Sanders
- { 1, 0, 0 }, // Belle (perfumerie)
- { 20, 0, 0 }, // Cleaning Girl (perfumerie)
- { 17, 0, 0 }, // Epstien in the Opera Balcony
- { 3, 0, 0 }, // Wiggins
- { 2, 0, 0 }, // Paul (Brumwell/Carroway)
- { 1, 0, 0 }, // Bartender
- { 1, 0, 0 }, // Dirty Drunk
- { 1, 0, 0 }, // Shouting Drunk
- { 1, 0, 0 }, // Staggering Drunk
- { 1, 0, 0 }, // Bouncer
- { 6, 0, 0 }, // James Sanders - At Home
- { 6, 0, 0 }, // The Coroner
- { 1, 0, 0 }, // The Equestrian Shop Keeper
- { 1, 0, 0 }, // George Blackwood
- { 7, 0, 0 }, // Lars
- { 1, 0, 0 }, // Sheila Parker
- { 8, 0, 0 }, // Chemist
- { 6, 0, 0 }, // Inspector Gregson
- { 1, 0, 0 }, // Lawyer
- { 1, 0, 0 }, // Mycroft
- { 7, 0, 0 }, // Old Sherman
- { 1, 0, 0 }, // Stock Boy in Chemist Shop
- { 1, 0, 0 }, // Barman
- { 1, 0, 0 }, // Dandy Player
- { 1, 0, 0 }, // Rough-looking Player
- { 1, 0, 0 }, // Spectator
- { 1, 0, 0 }, // Robert Hunt
- { 3, 0, 0 }, // Violet Secretary
- { 1, 0, 0 }, // Pettigrew
- { 8, 0, 0 }, // Augie (apple seller)
- { 16, 0, 0 }, // Anna Carroway
- { 1, 0, 0 }, // Guard
- { 8, 0, 0 }, // Antonio Caruso
- { 1, 0, 0 }, // Toby the Dog
- { 13, 0, 0 }, // Simon Kingsley
- { 2, 0, 0 }, // Alfred Tobacco Clerk
- { 1, 0, 0 }, // Lady Brumwell
- { 1, 0, 0 }, // Madame Rosa
- { 1, 0, 0 }, // Lady Brumwell
- { 1, 0, 0 }, // Joseph Moorehead
- { 5, 0, 0 }, // Mrs. Beale
- { 1, 0, 0 }, // Felix the Lion
- { 1, 0, 0 }, // Hollingston
- { 1, 0, 0 }, // Constable Callaghan
- { 2, 0, 0 }, // Sergeant Jeremy Duncan
- { 1, 0, 0 }, // Lord Brumwell
- { 1, 0, 0 }, // Nigel Jameson
- { 1, 0, 0 }, // Jonas (newspaper seller)
- { 1, 0, 0 }, // Constable Dugan
- { 4, 0, 0 } // Inspector Lestrade (Yard)
-};
-
-static const byte PEOPLE_TALK_SEQUENCES[MAX_PEOPLE][MAX_TALK_SEQUENCES] = {
- { 1, 0, 0 }, // Sherlock Holmes
- { 5, 5, 6, 7, 8, 7, 8, 6, 0, 0 }, // Dr. Watson
- { 2, 0, 0 }, // Inspector Lestrade
- { 1, 0, 0 }, // Constable #1
- { 1, 0, 0 }, // Constable #2
- { 2, 3, 0, 0 }, // Sheila Parker
- { 3, 0, 0 }, // Henry Carruthers
- { 1, 2, 3, 2, 1, 2, 3, 0, 0 }, // Lesly (flower girl)
- { 13, 14, 0, 0 }, // Usher #1
- { 2, 0, 0 }, // Usher #2
- { 1, 2, 3, 4, 3, 4, 3, 2, 0, 0 }, // Fredrick Epstein
- { 8, 0, 0 }, // Mrs.Worthington
- { 1, 2, 3, 4, 5, 4, 3, 2, 0, 0 }, // Coach
- { 7, 8, 0, 0 }, // Player
- { 12, 13, 0, 0 }, // Waterboy
- { 3, 4, 0, 0 }, // James Sanders
- { 4, 5, 0, 0 }, // Belle (perfumerie)
- { 14, 15, 16, 17, 18, 19, 20, 20, 20, 0, 0 }, // Cleaning Girl (perfumerie)
- { 16, 17, 18, 18, 18, 17, 17, 0, 0 }, // Epstien in the Opera Balcony
- { 2, 3, 0, 0 }, // Wiggins
- { 1, 2, 0, 0 }, // Paul (Brumwell/Carroway)
- { 1, 0, 0 }, // Bartender
- { 1, 0, 0 }, // Dirty Drunk
- { 1, 0, 0 }, // Shouting Drunk
- { 1, 0, 0 }, // Staggering Drunk
- { 1, 0, 0 }, // Bouncer
- { 5, 6, 0, 0 }, // James Sanders - At Home
- { 4, 5, 0, 0 }, // The Coroner
- { 1, 0, 0 }, // The Equestrian Shop Keeper
- { 1, 0, 0 }, // George Blackwood
- { 5, 6, 0, 0 }, // Lars
- { 1, 0, 0 }, // Sheila Parker
- { 8, 9, 0, 0 }, // Chemist
- { 5, 6, 0, 0 }, // Inspector Gregson
- { 1, 0, 0 }, // Lawyer
- { 1, 0, 0 }, // Mycroft
- { 7, 8, 0, 0 }, // Old Sherman
- { 1, 0, 0 }, // Stock Boy in Chemist Shop
- { 1, 0, 0 }, // Barman
- { 1, 0, 0 }, // Dandy Player
- { 1, 0, 0 }, // Rough-looking Player
- { 1, 0, 0 }, // Spectator
- { 1, 0, 0 }, // Robert Hunt
- { 3, 4, 0, 0 }, // Violet Secretary
- { 1, 0, 0 }, // Pettigrew
- { 14, 15, 0, 0 }, // Augie (apple seller)
- { 3, 4, 5, 6, 0, 0 }, // Anna Carroway
- { 4, 5, 6, 0, 0 }, // Guard
- { 7, 8, 0, 0 }, // Antonio Caruso
- { 1, 0, 0 }, // Toby the Dog
- { 13, 14, 0, 0 }, // Simon Kingsley
- { 2, 3, 0, 0 }, // Alfred Tobacco Clerk
- { 3, 4, 0, 0 }, // Lady Brumwell
- { 1, 30, 0, 0 }, // Madame Rosa
- { 3, 4, 0, 0 }, // Lady Brumwell
- { 1, 0, 0 }, // Joseph Moorehead
- { 14, 15, 16, 17, 18, 19, 20, 0, 0 }, // Mrs. Beale
- { 1, 0, 0 }, // Felix the Lion
- { 1, 0, 0 }, // Hollingston
- { 1, 0, 0 }, // Constable Callaghan
- { 1, 1, 2, 2, 0, 0 }, // Sergeant Jeremy Duncan
- { 9, 10, 0, 0 }, // Lord Brumwell
- { 1, 2, 0, 138, 3, 4, 0, 138, 0, 0 }, // Nigel Jameson
- { 1, 8, 0, 0 }, // Jonas (newspaper seller)
- { 1, 0, 0 }, // Constable Dugan
- { 2, 0, 0 } // Inspector Lestrade (Yard)
+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 } }
};
/*----------------------------------------------------------------*/
@@ -381,7 +187,16 @@ ScalpelEngine::~ScalpelEngine() {
}
void ScalpelEngine::initialize() {
- initGraphics(320, 200, false);
+ // 3DO actually uses RGB555, but some platforms of ours only support RGB565, so we use that
+
+ if (getPlatform() == Common::kPlatform3DO) {
+ const Graphics::PixelFormat pixelFormatRGB565 = Graphics::PixelFormat(2, 5, 6, 5, 0, 11, 5, 0, 0);
+ // 320x200 16-bit RGB565 for 3DO support
+ initGraphics(320, 200, false, &pixelFormatRGB565);
+ } else {
+ // 320x200 palettized
+ initGraphics(320, 200, false);
+ }
// Let the base engine intialize
SherlockEngine::initialize();
@@ -394,9 +209,10 @@ void ScalpelEngine::initialize() {
if (!isDemo()) {
// Load the map co-ordinates for each scene and sequence data
- _map->loadPoints(NUM_PLACES, &MAP_X[0], &MAP_Y[0], &MAP_TRANSLATE[0]);
- _map->loadSequences(3, &MAP_SEQUENCES[0][0]);
- _map->_oldCharPoint = BAKER_ST_EXTERIOR;
+ ScalpelMap &map = *(ScalpelMap *)_map;
+ map.loadPoints(NUM_PLACES, &MAP_X[0], &MAP_Y[0], &MAP_TRANSLATE[0]);
+ map.loadSequences(3, &MAP_SEQUENCES[0][0]);
+ map._oldCharPoint = BAKER_ST_EXTERIOR;
}
// Load the inventory
@@ -404,8 +220,8 @@ void ScalpelEngine::initialize() {
// Set up list of people
for (int idx = 0; idx < MAX_PEOPLE; ++idx)
- _people->_characters.push_back(PersonData(PEOPLE_NAMES[idx], PEOPLE_PORTRAITS[idx],
- PEOPLE_STILL_SEQUENCES[idx], PEOPLE_TALK_SEQUENCES[idx]));
+ _people->_characters.push_back(PersonData(PEOPLE_DATA[idx].name, 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);
@@ -421,45 +237,81 @@ void ScalpelEngine::initialize() {
}
void ScalpelEngine::showOpening() {
+ bool finished = true;
+
if (isDemo() && _interactiveFl)
return;
- if (!TsAGE::Logo::show(this))
- return;
- if (!showCityCutscene())
- return;
- if (!showAlleyCutscene())
- return;
- if (!showStreetCutscene())
- return;
- if (!showOfficeCutscene())
- return;
+ _events->setFrameRate(60);
+
+ if (getPlatform() == Common::kPlatform3DO) {
+ show3DOSplash();
+
+ finished = showCityCutscene3DO();
+ if (finished)
+ finished = showAlleyCutscene3DO();
+ if (finished)
+ finished = showStreetCutscene3DO();
+ if (finished)
+ showOfficeCutscene3DO();
+
+ _events->clearEvents();
+ _music->stopMusic();
+ } else {
+ TsAGE::Logo::show(this);
+
+ finished = showCityCutscene();
+ if (finished)
+ finished = showAlleyCutscene();
+ if (finished)
+ finished = showStreetCutscene();
+ if (finished)
+ showOfficeCutscene();
+
+ _events->clearEvents();
+ _music->stopMusic();
+ }
- _events->clearEvents();
- _music->stopMusic();
+ _events->setFrameRate(GAME_FRAME_RATE);
}
bool ScalpelEngine::showCityCutscene() {
+ byte greyPalette[PALETTE_SIZE];
byte palette[PALETTE_SIZE];
- _music->playMusic("prolog1.mus");
+ // Demo fades from black into grey and then fades from grey into the scene
+ Common::fill(&greyPalette[0], &greyPalette[PALETTE_SIZE], 142);
+ _screen->fadeIn((const byte *)greyPalette, 3);
+
+ _music->loadSong("prolog1");
_animation->_gfxLibraryFilename = "title.lib";
_animation->_soundLibraryFilename = "title.snd";
- bool finished = _animation->play("26open1", 1, 255, true, 2);
+ bool finished = _animation->play("26open1", true, 1, 255, true, 2);
if (finished) {
- ImageFile titleImages("title2.vgs", true);
+ ImageFile titleImages_LondonNovember("title2.vgs", true);
_screen->_backBuffer1.blitFrom(*_screen);
_screen->_backBuffer2.blitFrom(*_screen);
+ Common::Point londonPosition;
+
+ if ((titleImages_LondonNovember[0]._width == 302) && (titleImages_LondonNovember[0]._height == 39)) {
+ // Spanish
+ londonPosition = Common::Point(9, 8);
+ } else {
+ // English (German uses the same English graphics), width 272, height 37
+ // In the German version this is placed differently, check against German floppy version TODO
+ londonPosition = Common::Point(30, 50);
+ }
+
// London, England
- _screen->_backBuffer1.transBlitFrom(titleImages[0], Common::Point(10, 11));
+ _screen->_backBuffer1.transBlitFrom(titleImages_LondonNovember[0], londonPosition);
_screen->randomTransition();
finished = _events->delay(1000, true);
// November, 1888
if (finished) {
- _screen->_backBuffer1.transBlitFrom(titleImages[1], Common::Point(101, 102));
+ _screen->_backBuffer1.transBlitFrom(titleImages_LondonNovember[1], Common::Point(100, 100));
_screen->randomTransition();
finished = _events->delay(5000, true);
}
@@ -470,19 +322,35 @@ bool ScalpelEngine::showCityCutscene() {
}
if (finished)
- finished = _animation->play("26open2", 1, 0, false, 2);
+ finished = _animation->play("26open2", true, 1, 0, false, 2);
if (finished) {
- ImageFile titleImages("title.vgs", true);
+ ImageFile titleImages_SherlockHolmesTitle("title.vgs", true);
_screen->_backBuffer1.blitFrom(*_screen);
_screen->_backBuffer2.blitFrom(*_screen);
+ Common::Point lostFilesPosition;
+ Common::Point sherlockHolmesPosition;
+ Common::Point copyrightPosition;
+
+ if ((titleImages_SherlockHolmesTitle[0]._width == 306) && (titleImages_SherlockHolmesTitle[0]._height == 39)) {
+ // Spanish
+ lostFilesPosition = Common::Point(5, 5);
+ sherlockHolmesPosition = Common::Point(24, 40);
+ copyrightPosition = Common::Point(3, 190);
+ } else {
+ // English (German uses the same English graphics), width 208, height 39
+ lostFilesPosition = Common::Point(75, 6);
+ sherlockHolmesPosition = Common::Point(34, 21);
+ copyrightPosition = Common::Point(4, 190);
+ }
+
// The Lost Files of
- _screen->_backBuffer1.transBlitFrom(titleImages[0], Common::Point(75, 6));
+ _screen->_backBuffer1.transBlitFrom(titleImages_SherlockHolmesTitle[0], lostFilesPosition);
// Sherlock Holmes
- _screen->_backBuffer1.transBlitFrom(titleImages[1], Common::Point(34, 21));
+ _screen->_backBuffer1.transBlitFrom(titleImages_SherlockHolmesTitle[1], sherlockHolmesPosition);
// copyright
- _screen->_backBuffer1.transBlitFrom(titleImages[2], Common::Point(4, 190));
+ _screen->_backBuffer1.transBlitFrom(titleImages_SherlockHolmesTitle[2], copyrightPosition);
_screen->verticalTransition();
finished = _events->delay(4000, true);
@@ -500,9 +368,23 @@ bool ScalpelEngine::showCityCutscene() {
if (finished) {
// In the alley...
- _screen->transBlitFrom(titleImages[3], Common::Point(72, 51));
+ Common::Point alleyPosition;
+
+ if ((titleImages_SherlockHolmesTitle[3]._width == 105) && (titleImages_SherlockHolmesTitle[3]._height == 16)) {
+ // German
+ alleyPosition = Common::Point(72, 50);
+ } else if ((titleImages_SherlockHolmesTitle[3]._width == 166) && (titleImages_SherlockHolmesTitle[3]._height == 36)) {
+ // Spanish
+ alleyPosition = Common::Point(71, 50);
+ } else {
+ // English, width 175, height 38
+ alleyPosition = Common::Point(72, 51);
+ }
+ _screen->transBlitFrom(titleImages_SherlockHolmesTitle[3], alleyPosition);
_screen->fadeIn(palette, 3);
- finished = _events->delay(3000, true);
+
+ // Wait until the track got looped and the first few notes were played
+ finished = _music->waitUntilMSec(4300, 21300, 0, 2500); // ticks 0x104 / ticks 0x500
}
}
@@ -513,22 +395,45 @@ bool ScalpelEngine::showCityCutscene() {
bool ScalpelEngine::showAlleyCutscene() {
byte palette[PALETTE_SIZE];
- _music->playMusic("prolog2.mus");
+ _music->loadSong("prolog2");
_animation->_gfxLibraryFilename = "TITLE.LIB";
_animation->_soundLibraryFilename = "TITLE.SND";
- bool finished = _animation->play("27PRO1", 1, 3, true, 2);
- if (finished)
- finished = _animation->play("27PRO2", 1, 0, false, 2);
+ // Fade "In The Alley..." text to black
+ _screen->fadeToBlack(2);
+
+ bool finished = _animation->play("27PRO1", true, 1, 3, true, 2);
+ if (finished) {
+ _screen->getPalette(palette);
+ _screen->fadeToBlack(2);
+
+ // wait until second lower main note
+ finished = _music->waitUntilMSec(26800, 0xFFFFFFFF, 0, 1000); // ticks 0x64A
+ }
+
+ if (finished) {
+ _screen->setPalette(palette);
+ finished = _animation->play("27PRO2", true, 1, 0, false, 2);
+ }
if (finished) {
showLBV("scream.lbv");
- finished = _events->delay(6000);
+
+ // wait until first "scream" in music happened
+ finished = _music->waitUntilMSec(45800, 0xFFFFFFFF, 0, 6000); // ticks 0xABE
+ }
+
+ if (finished) {
+ // quick fade out
+ _screen->fadeToBlack(1);
+
+ // wait until after third "scream" in music happened
+ finished = _music->waitUntilMSec(49000, 0xFFFFFFFF, 0, 2000); // ticks 0xB80
}
if (finished)
- finished = _animation->play("27PRO3", 1, 0, true, 2);
+ finished = _animation->play("27PRO3", true, 1, 0, true, 2);
if (finished) {
_screen->getPalette(palette);
@@ -536,11 +441,28 @@ bool ScalpelEngine::showAlleyCutscene() {
}
if (finished) {
- ImageFile titleImages("title3.vgs", true);
+ ImageFile titleImages_EarlyTheFollowingMorning("title3.vgs", true);
// "Early the following morning on Baker Street..."
- _screen->_backBuffer1.transBlitFrom(titleImages[0], Common::Point(35, 51), false, 0);
- _screen->fadeIn(palette, 3);
- finished = _events->delay(1000);
+ Common::Point earlyTheFollowingMorningPosition;
+
+ if ((titleImages_EarlyTheFollowingMorning[0]._width == 164) && (titleImages_EarlyTheFollowingMorning[0]._height == 19)) {
+ // German
+ earlyTheFollowingMorningPosition = Common::Point(35, 50);
+ } else if ((titleImages_EarlyTheFollowingMorning[0]._width == 171) && (titleImages_EarlyTheFollowingMorning[0]._height == 32)) {
+ // Spanish
+ earlyTheFollowingMorningPosition = Common::Point(35, 50);
+ } else {
+ // English, width 218, height 31
+ earlyTheFollowingMorningPosition = Common::Point(35, 52);
+ }
+
+ _screen->transBlitFrom(titleImages_EarlyTheFollowingMorning[0], earlyTheFollowingMorningPosition);
+
+ // fast fade-in
+ _screen->fadeIn(palette, 1);
+
+ // wait for music to end and wait an additional 2.5 seconds
+ finished = _music->waitUntilMSec(0xFFFFFFFF, 0xFFFFFFFF, 2500, 3000);
}
_animation->_gfxLibraryFilename = "";
@@ -552,24 +474,89 @@ bool ScalpelEngine::showStreetCutscene() {
_animation->_gfxLibraryFilename = "TITLE.LIB";
_animation->_soundLibraryFilename = "TITLE.SND";
- _music->playMusic("PROLOG3.MUS");
+ _music->loadSong("prolog3");
+
+ // wait a bit
+ bool finished = _events->delay(500);
- bool finished = _animation->play("14KICK", 1, 3, true, 2);
+ if (finished) {
+ // fade out "Early the following morning..."
+ _screen->fadeToBlack(2);
+
+ // wait for music a bit
+ finished = _music->waitUntilMSec(3800, 0xFFFFFFFF, 0, 1000); // ticks 0xE4
+ }
if (finished)
- finished = _animation->play("14NOTE", 1, 0, false, 2);
+ finished = _animation->play("14KICK", true, 1, 3, true, 2);
+
+ // Constable animation plays slower than speed 2
+ // If we play it with speed 2, music gets obviously out of sync
+ if (finished)
+ finished = _animation->play("14NOTE", true, 1, 0, false, 3);
+
+ // Fade to black
+ if (finished)
+ _screen->fadeToBlack(1);
_animation->_gfxLibraryFilename = "";
_animation->_soundLibraryFilename = "";
return finished;
}
+bool ScalpelEngine::showOfficeCutscene() {
+ _music->loadSong("prolog4");
+ _animation->_gfxLibraryFilename = "TITLE2.LIB";
+ _animation->_soundLibraryFilename = "TITLE.SND";
+
+ bool finished = _animation->play("COFF1", true, 1, 3, true, 3);
+ if (finished)
+ finished = _animation->play("COFF2", true, 1, 0, false, 3);
+ if (finished) {
+ showLBV("note.lbv");
+
+ if (_sound->_voices) {
+ finished = _sound->playSound("NOTE1", WAIT_KBD_OR_FINISH);
+ if (finished)
+ finished = _sound->playSound("NOTE2", WAIT_KBD_OR_FINISH);
+ if (finished)
+ finished = _sound->playSound("NOTE3", WAIT_KBD_OR_FINISH);
+ if (finished)
+ finished = _sound->playSound("NOTE4", WAIT_KBD_OR_FINISH);
+ } else
+ finished = _events->delay(19000);
+
+ if (finished) {
+ _events->clearEvents();
+ finished = _events->delay(500);
+ }
+ }
+
+ if (finished)
+ finished = _animation->play("COFF3", true, 1, 0, true, 3);
+
+ if (finished)
+ finished = _animation->play("COFF4", true, 1, 0, false, 3);
+
+ if (finished)
+ finished = scrollCredits();
+
+ if (finished)
+ _screen->fadeToBlack(3);
+
+ _animation->_gfxLibraryFilename = "";
+ _animation->_soundLibraryFilename = "";
+ return finished;
+}
bool ScalpelEngine::scrollCredits() {
// Load the images for displaying credit text
Common::SeekableReadStream *stream = _res->load("credits.vgs", "title.lib");
ImageFile creditsImages(*stream);
- _screen->setPalette(creditsImages._palette);
+
+ // Demo fades slowly from the scene into credits palette
+ _screen->fadeIn(creditsImages._palette, 3);
+
delete stream;
// Save a copy of the screen background for use in drawing each credit frame
@@ -597,70 +584,327 @@ bool ScalpelEngine::scrollCredits() {
return true;
}
-bool ScalpelEngine::showOfficeCutscene() {
- _music->playMusic("PROLOG4.MUS");
- _animation->_gfxLibraryFilename = "TITLE2.LIB";
+// 3DO variant
+bool ScalpelEngine::show3DOSplash() {
+ // 3DO EA Splash screen
+ ImageFile3DO titleImage_3DOSplash("3DOSplash.cel", kImageFile3DOType_Cel);
+
+ _screen->transBlitFrom(titleImage_3DOSplash[0]._frame, Common::Point(0, -20));
+ bool finished = _events->delay(3000, true);
+
+ if (finished) {
+ _screen->clear();
+ finished = _events->delay(500, true);
+ }
+
+ if (finished) {
+ // EA logo movie
+ Scalpel3DOMoviePlay("EAlogo.stream", Common::Point(20, 0));
+ }
+
+ // Always clear screen
+ _screen->clear();
+ return finished;
+}
+
+bool ScalpelEngine::showCityCutscene3DO() {
_animation->_soundLibraryFilename = "TITLE.SND";
- bool finished = _animation->play("COFF1", 1, 3, true, 3);
+ _screen->clear();
+ bool finished = _events->delay(2500, true);
+
+ // rain.aiff seems to be playing in an endless loop until
+ // sherlock logo fades away TODO
+
+ if (finished) {
+ finished = _events->delay(2500, true);
+
+ // Play intro music
+ _music->loadSong("prolog");
+
+ // Fade screen to grey
+ _screen->_backBuffer1.fill(0xCE59); // RGB565: 25, 50, 25 (grey)
+ _screen->fadeIntoScreen3DO(2);
+ }
+
+ if (finished) {
+ finished = _music->waitUntilMSec(3400, 0, 0, 3400);
+ }
+
+ if (finished) {
+ _screen->_backBuffer1.fill(0); // fill backbuffer with black to avoid issues during fade from white
+ finished = _animation->play3DO("26open1", true, 1, true, 2);
+ }
+
+ if (finished) {
+ _screen->_backBuffer1.blitFrom(*_screen); // save into backbuffer 1, used for fade
+ _screen->_backBuffer2.blitFrom(*_screen); // save into backbuffer 2, for restoring later
+
+ // "London, England"
+ ImageFile3DO titleImage_London("title2a.cel", kImageFile3DOType_Cel);
+ _screen->_backBuffer1.transBlitFrom(titleImage_London[0]._frame, Common::Point(30, 50));
+
+ _screen->fadeIntoScreen3DO(1);
+ finished = _events->delay(1500, true);
+
+ if (finished) {
+ // "November, 1888"
+ ImageFile3DO titleImage_November("title2b.cel", kImageFile3DOType_Cel);
+ _screen->_backBuffer1.transBlitFrom(titleImage_November[0]._frame, Common::Point(100, 100));
+
+ _screen->fadeIntoScreen3DO(1);
+ finished = _music->waitUntilMSec(14700, 0, 0, 5000);
+ }
+
+ if (finished) {
+ // Restore screen
+ _screen->blitFrom(_screen->_backBuffer2);
+ }
+ }
+
if (finished)
- finished = _animation->play("COFF2", 1, 0, false, 3);
+ finished = _animation->play3DO("26open2", true, 1, false, 2);
+
if (finished) {
- showLBV("note.lbv");
+ _screen->_backBuffer1.blitFrom(*_screen); // save into backbuffer 1, used for fade
- if (_sound->_voices) {
- finished = _sound->playSound("NOTE1", WAIT_KBD_OR_FINISH);
- if (finished)
- finished = _sound->playSound("NOTE2", WAIT_KBD_OR_FINISH);
- if (finished)
- finished = _sound->playSound("NOTE3", WAIT_KBD_OR_FINISH);
- if (finished)
- finished = _sound->playSound("NOTE4", WAIT_KBD_OR_FINISH);
- } else
- finished = _events->delay(19000);
+ // "Sherlock Holmes" (title)
+ ImageFile3DO titleImage_SherlockHolmesTitle("title1ab.cel", kImageFile3DOType_Cel);
+ _screen->_backBuffer1.transBlitFrom(titleImage_SherlockHolmesTitle[0]._frame, Common::Point(34, 5));
+
+ // Blend in
+ _screen->fadeIntoScreen3DO(2);
+ finished = _events->delay(500, true);
+ // Title should fade in, Copyright should be displayed a bit after that
if (finished) {
- _events->clearEvents();
- finished = _events->delay(500);
+ ImageFile3DO titleImage_Copyright("title1c.cel", kImageFile3DOType_Cel);
+
+ _screen->transBlitFrom(titleImage_Copyright[0]._frame, Common::Point(20, 190));
+ finished = _events->delay(3500, true);
}
}
if (finished)
- finished = _animation->play("COFF3", 1, 0, true, 3);
+ finished = _music->waitUntilMSec(33600, 0, 0, 2000);
+
+ if (finished) {
+ // Fade to black
+ _screen->_backBuffer1.clear();
+ _screen->fadeIntoScreen3DO(3);
+ }
+
+ 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));
+
+ // Fade in
+ _screen->fadeIntoScreen3DO(4);
+ finished = _music->waitUntilMSec(39900, 0, 0, 2500);
+
+ // Fade out
+ _screen->_backBuffer1.clear();
+ _screen->fadeIntoScreen3DO(4);
+ }
+ return finished;
+}
+
+bool ScalpelEngine::showAlleyCutscene3DO() {
+ bool finished = _music->waitUntilMSec(43500, 0, 0, 1000);
if (finished)
- finished = _animation->play("COFF4", 1, 0, false, 3);
+ finished = _animation->play3DO("27PRO1", true, 1, false, 2);
+
+ if (finished) {
+ // Fade out...
+ _screen->_backBuffer1.clear();
+ _screen->fadeIntoScreen3DO(3);
+
+ finished = _music->waitUntilMSec(67100, 0, 0, 1000); // 66700
+ }
if (finished)
- finished = scrollCredits();
+ finished = _animation->play3DO("27PRO2", true, 1, false, 2);
if (finished)
- _screen->fadeToBlack(3);
+ finished = _music->waitUntilMSec(76000, 0, 0, 1000);
+
+ if (finished) {
+ // Show screaming victim
+ ImageFile3DO titleImage_ScreamingVictim("scream.cel", kImageFile3DOType_Cel);
+
+ _screen->clear();
+ _screen->transBlitFrom(titleImage_ScreamingVictim[0]._frame, Common::Point(0, 0));
+
+ // Play "scream.aiff"
+ if (_sound->_voices)
+ _sound->playSound("prologue/sounds/scream.aiff", WAIT_RETURN_IMMEDIATELY, 100);
+
+ finished = _music->waitUntilMSec(81600, 0, 0, 6000);
+ }
+
+ if (finished) {
+ // Fade out
+ _screen->_backBuffer1.clear();
+ _screen->fadeIntoScreen3DO(5);
+
+ finished = _music->waitUntilMSec(84400, 0, 0, 2000);
+ }
+
+ if (finished)
+ finished = _animation->play3DO("27PRO3", true, 1, false, 2);
+
+ if (finished) {
+ // Fade out
+ _screen->_backBuffer1.clear();
+ _screen->fadeIntoScreen3DO(5);
+ }
+
+ 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));
+
+ // Fade in
+ _screen->fadeIntoScreen3DO(4);
+ finished = _music->waitUntilMSec(96700, 0, 0, 3000);
+ }
+
+ return finished;
+}
+
+bool ScalpelEngine::showStreetCutscene3DO() {
+ bool finished = true;
+
+ if (finished) {
+ // fade out "Early the following morning..."
+ _screen->_backBuffer1.clear();
+ _screen->fadeIntoScreen3DO(4);
+
+ // wait for music a bit
+ finished = _music->waitUntilMSec(100300, 0, 0, 1000);
+ }
+
+ if (finished)
+ finished = _animation->play3DO("14KICK", true, 1, false, 2);
+
+ // note: part of the constable is sticking to the door during the following
+ // animation, when he walks away. This is a bug of course, but it actually happened on 3DO!
+ // I'm not sure if it happens because the door is pure black (0, 0, 0) and it's because
+ // of transparency - or if the animation itself is bad. We will definitely have to adjust
+ // the animation data to fix it.
+ if (finished)
+ finished = _animation->play3DO("14NOTE", true, 1, false, 3);
+
+ if (finished) {
+ // Fade out
+ _screen->_backBuffer1.clear();
+ _screen->fadeIntoScreen3DO(4);
+ }
+
+ return finished;
+}
+
+bool ScalpelEngine::showOfficeCutscene3DO() {
+ bool finished = _music->waitUntilMSec(151000, 0, 0, 1000);
+
+ if (finished)
+ finished = _animation->play3DO("COFF1", true, 1, false, 3);
+
+ if (finished)
+ finished = _animation->play3DO("COFF2", true, 1, false, 3);
+
+ if (finished)
+ finished = _music->waitUntilMSec(182400, 0, 0, 1000);
+
+ if (finished) {
+ // Show the note
+ ImageFile3DO titleImage_CoffeeNote("note.cel", kImageFile3DOType_Cel);
+
+ _screen->clear();
+ _screen->transBlitFrom(titleImage_CoffeeNote[0]._frame, Common::Point(0, 0));
+
+ if (_sound->_voices) {
+ finished = _sound->playSound("prologue/sounds/note.aiff", WAIT_KBD_OR_FINISH);
+ } else
+ finished = _events->delay(19000);
+
+ if (finished)
+ finished = _music->waitUntilMSec(218800, 0, 0, 1000);
+
+ // Fade out
+ _screen->clear();
+ }
+
+ if (finished)
+ finished = _music->waitUntilMSec(222200, 0, 0, 1000);
+
+ if (finished)
+ finished = _animation->play3DO("COFF3", true, 1, false, 3);
+
+ if (finished)
+ finished = _animation->play3DO("COFF4", true, 1, false, 3);
+
+ if (finished) {
+ finished = _music->waitUntilMSec(244500, 0, 0, 2000);
+
+ // TODO: Brighten the image, possibly by doing a partial fade
+ // to white.
+
+ _screen->_backBuffer1.blitFrom(*_screen);
+
+ for (int nr = 1; finished && nr <= 4; nr++) {
+ char filename[15];
+ sprintf(filename, "credits%d.cel", nr);
+ ImageFile3DO *creditsImage = new ImageFile3DO(filename, kImageFile3DOType_Cel);
+ ImageFrame *creditsFrame = &(*creditsImage)[0];
+ for (int i = 0; finished && i < 200 + creditsFrame->_height; i++) {
+ _screen->blitFrom(_screen->_backBuffer1);
+ _screen->transBlitFrom(creditsFrame->_frame, Common::Point((320 - creditsFrame->_width) / 2, 200 - i));
+ if (!_events->delay(70, true))
+ finished = false;
+ }
+ delete creditsImage;
+ }
+ }
- _animation->_gfxLibraryFilename = "";
- _animation->_soundLibraryFilename = "";
return finished;
}
void ScalpelEngine::loadInventory() {
+ ScalpelFixedText &fixedText = *(ScalpelFixedText *)_fixedText;
Inventory &inv = *_inventory;
+ Common::String fixedText_Message = fixedText.getText(kFixedText_InitInventory_Message);
+ Common::String fixedText_HolmesCard = fixedText.getText(kFixedText_InitInventory_HolmesCard);
+ Common::String fixedText_Tickets = fixedText.getText(kFixedText_InitInventory_Tickets);
+ Common::String fixedText_CuffLink = fixedText.getText(kFixedText_InitInventory_CuffLink);
+ Common::String fixedText_WireHook = fixedText.getText(kFixedText_InitInventory_WireHook);
+ Common::String fixedText_Note = fixedText.getText(kFixedText_InitInventory_Note);
+ Common::String fixedText_OpenWatch = fixedText.getText(kFixedText_InitInventory_OpenWatch);
+ Common::String fixedText_Paper = fixedText.getText(kFixedText_InitInventory_Paper);
+ Common::String fixedText_Letter = fixedText.getText(kFixedText_InitInventory_Letter);
+ Common::String fixedText_Tarot = fixedText.getText(kFixedText_InitInventory_Tarot);
+ Common::String fixedText_OrnateKey = fixedText.getText(kFixedText_InitInventory_OrnateKey);
+ Common::String fixedText_PawnTicket = fixedText.getText(kFixedText_InitInventory_PawnTicket);
+
// Initial inventory
inv._holdings = 2;
- inv.push_back(InventoryItem(0, "Message", "A message requesting help", "_ITEM03A"));
- inv.push_back(InventoryItem(0, "Holmes Card", "A number of business cards", "_ITEM07A"));
+ inv.push_back(InventoryItem(0, "Message", fixedText_Message, "_ITEM03A"));
+ inv.push_back(InventoryItem(0, "Holmes Card", fixedText_HolmesCard, "_ITEM07A"));
// Hidden items
- inv.push_back(InventoryItem(95, "Tickets", "Opera Tickets", "_ITEM10A"));
- inv.push_back(InventoryItem(138, "Cuff Link", "Cuff Link", "_ITEM04A"));
- inv.push_back(InventoryItem(138, "Wire Hook", "Wire Hook", "_ITEM06A"));
- inv.push_back(InventoryItem(150, "Note", "Note", "_ITEM13A"));
- inv.push_back(InventoryItem(481, "Open Watch", "An open pocket watch", "_ITEM62A"));
- inv.push_back(InventoryItem(481, "Paper", "A piece of paper with numbers on it", "_ITEM44A"));
- inv.push_back(InventoryItem(532, "Letter", "A letter folded many times", "_ITEM68A"));
- inv.push_back(InventoryItem(544, "Tarot", "Tarot Cards", "_ITEM71A"));
- inv.push_back(InventoryItem(544, "Ornate Key", "An ornate key", "_ITEM70A"));
- inv.push_back(InventoryItem(586, "Pawn ticket", "A pawn ticket", "_ITEM16A"));
+ inv.push_back(InventoryItem(95, "Tickets", fixedText_Tickets, "_ITEM10A"));
+ inv.push_back(InventoryItem(138, "Cuff Link", fixedText_CuffLink, "_ITEM04A"));
+ inv.push_back(InventoryItem(138, "Wire Hook", fixedText_WireHook, "_ITEM06A"));
+ inv.push_back(InventoryItem(150, "Note", fixedText_Note, "_ITEM13A"));
+ inv.push_back(InventoryItem(481, "Open Watch", fixedText_OpenWatch, "_ITEM62A"));
+ inv.push_back(InventoryItem(481, "Paper", fixedText_Paper, "_ITEM44A"));
+ inv.push_back(InventoryItem(532, "Letter", fixedText_Letter, "_ITEM68A"));
+ inv.push_back(InventoryItem(544, "Tarot", fixedText_Tarot, "_ITEM71A"));
+ inv.push_back(InventoryItem(544, "Ornate Key", fixedText_OrnateKey, "_ITEM70A"));
+ inv.push_back(InventoryItem(586, "Pawn ticket", fixedText_PawnTicket, "_ITEM16A"));
}
void ScalpelEngine::showLBV(const Common::String &filename) {
@@ -682,8 +926,8 @@ void ScalpelEngine::startScene() {
_scene->_goToScene = _map->show();
_music->freeSong();
- _people->_hSavedPos = Common::Point(-1, -1);
- _people->_hSavedFacing = -1;
+ _people->_savedPos = Common::Point(-1, -1);
+ _people->_savedPos._facing = -1;
}
// Some rooms are prologue cutscenes, rather than normal game scenes. These are:
@@ -705,8 +949,8 @@ void ScalpelEngine::startScene() {
// Blackwood's capture
_res->addToCache("final2.vda", "epilogue.lib");
_res->addToCache("final2.vdx", "epilogue.lib");
- _animation->play("final1", 1, 3, true, 4);
- _animation->play("final2", 1, 0, false, 4);
+ _animation->play("final1", false, 1, 3, true, 4);
+ _animation->play("final2", false, 1, 0, false, 4);
break;
case RESCUE_ANNA:
@@ -722,8 +966,8 @@ void ScalpelEngine::startScene() {
_res->addToCache("finale4.vda", "EPILOG2.lib");
_res->addToCache("finale4.vdx", "EPILOG2.lib");
- _animation->play("finalr1", 1, 3, true, 4);
- _animation->play("finalr2", 1, 0, false, 4);
+ _animation->play("finalr1", false, 1, 3, true, 4);
+ _animation->play("finalr2", false, 1, 0, false, 4);
if (!_res->isInCache("finale2.vda")) {
// Finale file isn't cached
@@ -735,12 +979,12 @@ void ScalpelEngine::startScene() {
_res->addToCache("finale4.vdx", "EPILOG2.lib");
}
- _animation->play("finale1", 1, 0, false, 4);
- _animation->play("finale2", 1, 0, false, 4);
- _animation->play("finale3", 1, 0, false, 4);
+ _animation->play("finale1", false, 1, 0, false, 4);
+ _animation->play("finale2", false, 1, 0, false, 4);
+ _animation->play("finale3", false, 1, 0, false, 4);
_useEpilogue2 = true;
- _animation->play("finale4", 1, 0, false, 4);
+ _animation->play("finale4", false, 1, 0, false, 4);
_useEpilogue2 = false;
break;
@@ -751,9 +995,9 @@ void ScalpelEngine::startScene() {
_res->addToCache("SUBWAY3.vda", "epilogue.lib");
_res->addToCache("SUBWAY3.vdx", "epilogue.lib");
- _animation->play("SUBWAY1", 1, 3, true, 4);
- _animation->play("SUBWAY2", 1, 0, false, 4);
- _animation->play("SUBWAY3", 1, 0, false, 4);
+ _animation->play("SUBWAY1", false, 1, 3, true, 4);
+ _animation->play("SUBWAY2", false, 1, 0, false, 4);
+ _animation->play("SUBWAY3", false, 1, 0, false, 4);
// Set fading to direct fade temporary so the transition goes quickly.
_scene->_tempFadeStyle = _screen->_fadeStyle ? 257 : 256;
@@ -762,7 +1006,7 @@ void ScalpelEngine::startScene() {
case BRUMWELL_SUICIDE:
// Brumwell suicide
- _animation->play("suicid", 1, 3, true, 4);
+ _animation->play("suicid", false, 1, 3, true, 4);
break;
default:
break;
@@ -822,8 +1066,8 @@ void ScalpelEngine::startScene() {
_mapResult = _scene->_goToScene;
}
-void ScalpelEngine::eraseMirror12() {
- Common::Point pt((*_people)[AL]._position.x / 100, (*_people)[AL]._position.y / 100);
+void ScalpelEngine::eraseBrumwellMirror() {
+ Common::Point pt((*_people)[HOLMES]._position.x / FIXED_INT_MULTIPLIER, (*_people)[HOLMES]._position.y / FIXED_INT_MULTIPLIER);
// 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)) {
@@ -832,15 +1076,15 @@ void ScalpelEngine::eraseMirror12() {
}
}
-void ScalpelEngine::doMirror12() {
+void ScalpelEngine::doBrumwellMirror() {
People &people = *_people;
- Person &player = people._player;
+ Person &player = people[HOLMES];
- Common::Point pt((*_people)[AL]._position.x / 100, (*_people)[AL]._position.y / 100);
+ Common::Point pt((*_people)[HOLMES]._position.x / FIXED_INT_MULTIPLIER, (*_people)[HOLMES]._position.y / FIXED_INT_MULTIPLIER);
int frameNum = player._walkSequences[player._sequenceNumber][player._frameNumber] +
player._walkSequences[player._sequenceNumber][0] - 2;
- switch ((*_people)[AL]._sequenceNumber) {
+ switch ((*_people)[HOLMES]._sequenceNumber) {
case WALK_DOWN:
frameNum -= 7;
break;
@@ -883,12 +1127,12 @@ void ScalpelEngine::doMirror12() {
if (Common::Rect(80, 100, 145, 138).contains(pt)) {
// Get the frame of Sherlock to draw
- ImageFrame &imageFrame = (*people[AL]._images)[frameNum];
+ ImageFrame &imageFrame = (*people[HOLMES]._images)[frameNum];
// Draw the mirror image of Holmes
- bool flipped = people[AL]._sequenceNumber == WALK_LEFT || people[AL]._sequenceNumber == STOP_LEFT
- || people[AL]._sequenceNumber == WALK_UPRIGHT || people[AL]._sequenceNumber == STOP_UPRIGHT
- || people[AL]._sequenceNumber == WALK_DOWNLEFT || people[AL]._sequenceNumber == STOP_DOWNLEFT;
+ 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);
// Redraw the mirror borders to prevent the drawn image of Holmes from appearing outside of the mirror
@@ -907,8 +1151,8 @@ void ScalpelEngine::doMirror12() {
}
}
-void ScalpelEngine::flushMirror12() {
- Common::Point pt((*_people)[AL]._position.x / 100, (*_people)[AL]._position.y / 100);
+void ScalpelEngine::flushBrumwellMirror() {
+ Common::Point pt((*_people)[HOLMES]._position.x / FIXED_INT_MULTIPLIER, (*_people)[HOLMES]._position.y / FIXED_INT_MULTIPLIER);
// If player is in range of the mirror, then draw the entire mirror area to the screen
if (Common::Rect(70, 100, 200, 200).contains(pt))
@@ -917,4 +1161,4 @@ void ScalpelEngine::flushMirror12() {
} // End of namespace Scalpel
-} // End of namespace Scalpel
+} // End of namespace Sherlock
diff --git a/engines/sherlock/scalpel/scalpel.h b/engines/sherlock/scalpel/scalpel.h
index 8743bfb7a9..cb1cb20492 100644
--- a/engines/sherlock/scalpel/scalpel.h
+++ b/engines/sherlock/scalpel/scalpel.h
@@ -24,40 +24,56 @@
#define SHERLOCK_SCALPEL_H
#include "sherlock/sherlock.h"
-#include "sherlock/scalpel/darts.h"
+#include "sherlock/scalpel/scalpel_darts.h"
namespace Sherlock {
namespace Scalpel {
-enum { BLACKWOOD_CAPTURE = 2, BAKER_STREET = 4, DRAWING_ROOM = 12, STATION = 17, PUB_INTERIOR = 19,
- LAWYER_OFFICE = 27, BAKER_ST_EXTERIOR = 39, RESCUE_ANNA = 52, MOOREHEAD_DEATH = 53, EXIT_GAME = 55,
- BRUMWELL_SUICIDE = 70, OVERHEAD_MAP2 = 98, DARTS_GAME = 99, OVERHEAD_MAP = 100 };
+enum {
+ BUTTON_TOP = 233,
+ BUTTON_MIDDLE = 244,
+ BUTTON_BOTTOM = 248,
+ COMMAND_FOREGROUND = 15,
+ COMMAND_HIGHLIGHTED = 10,
+ COMMAND_NULL = 248,
+ INFO_FOREGROUND = 11,
+ INFO_BACKGROUND = 1,
+ INV_FOREGROUND = 14,
+ INV_BACKGROUND = 1,
+ PEN_COLOR = 250
+};
class ScalpelEngine : public SherlockEngine {
private:
Darts *_darts;
int _mapResult;
+ bool show3DOSplash();
+
/**
* Show the starting city cutscene which shows the game title
*/
bool showCityCutscene();
+ bool showCityCutscene3DO();
/**
* Show the back alley where the initial murder takes place
*/
bool showAlleyCutscene();
+ bool showAlleyCutscene3DO();
/**
* Show the Baker Street outside cutscene
*/
bool showStreetCutscene();
+ bool showStreetCutscene3DO();
/**
* Show Holmes and Watson at the breakfast table, lestrade's note, and then the scrolling credits
*/
bool showOfficeCutscene();
+ bool showOfficeCutscene3DO();
/**
* Show the game credits
@@ -97,17 +113,17 @@ public:
/**
* Takes care of clearing the mirror in scene 12 (mansion drawing room), in case anything drew over it
*/
- void eraseMirror12();
+ void eraseBrumwellMirror();
/**
* Takes care of drawing Holme's reflection onto the mirror in scene 12 (mansion drawing room)
*/
- void doMirror12();
+ void doBrumwellMirror();
/**
* This clears the mirror in scene 12 (mansion drawing room) in case anything messed draw over it
*/
- void flushMirror12();
+ void flushBrumwellMirror();
};
} // End of namespace Scalpel
diff --git a/engines/sherlock/scalpel/darts.cpp b/engines/sherlock/scalpel/scalpel_darts.cpp
index 8d78335a55..87f4566837 100644
--- a/engines/sherlock/scalpel/darts.cpp
+++ b/engines/sherlock/scalpel/scalpel_darts.cpp
@@ -20,7 +20,7 @@
*
*/
-#include "sherlock/scalpel/darts.h"
+#include "sherlock/scalpel/scalpel_darts.h"
#include "sherlock/scalpel/scalpel.h"
namespace Sherlock {
@@ -117,7 +117,7 @@ void Darts::playDarts() {
if (playerNumber == 0) {
screen.print(Common::Point(DART_INFO_X, DART_INFO_Y + 30), PLAYER_COLOR, "Holmes Wins!");
if (_level < OPPONENTS_COUNT)
- setFlagsForDarts(318 + _level);
+ _vm->setFlagsDirect(318 + _level);
} else {
screen.print(Common::Point(DART_INFO_X, DART_INFO_Y + 30), PLAYER_COLOR, "%s Wins!", _opponent.c_str());
}
@@ -366,8 +366,8 @@ void Darts::drawDartThrow(const Common::Point &pt) {
void Darts::erasePowerBars() {
Screen &screen = *_vm->_screen;
- screen._backBuffer1.fillRect(Common::Rect(DARTBARHX, DARTHORIZY, DARTBARHX + DARTBARSIZE, DARTHORIZY + 10), 0);
- screen._backBuffer1.fillRect(Common::Rect(DARTBARVX, DARTHEIGHTY, DARTBARVX + 10, DARTHEIGHTY + DARTBARSIZE), 0);
+ 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.slamArea(DARTBARHX - 1, DARTHORIZY - 1, DARTBARSIZE + 3, 11);
@@ -377,15 +377,11 @@ void Darts::erasePowerBars() {
int Darts::doPowerBar(const Common::Point &pt, byte color, int goToPower, bool isVertical) {
Events &events = *_vm->_events;
Screen &screen = *_vm->_screen;
- Music &music = *_vm->_music;
bool done;
int idx = 0;
events.clearEvents();
- if (music._musicOn)
- music.waitTimerRoland(10);
- else
- events.delay(100);
+ events.delay(100);
// Display loop
do {
@@ -395,7 +391,7 @@ int Darts::doPowerBar(const Common::Point &pt, byte color, int goToPower, bool i
// Reached target power for a computer player
done = true;
else if (goToPower == 0) {
- // Check for pres
+ // Check for press
if (dartHit())
done = true;
}
@@ -410,10 +406,7 @@ int Darts::doPowerBar(const Common::Point &pt, byte color, int goToPower, bool i
screen.slamArea(pt.x + idx, pt.y, 1, 8);
}
- if (music._musicOn) {
- if (!(idx % 3))
- music.waitTimerRoland(1);
- } else if (!(idx % 8))
+ if (!(idx % 8))
events.wait(1);
++idx;
@@ -422,16 +415,16 @@ int Darts::doPowerBar(const Common::Point &pt, byte color, int goToPower, bool i
return MIN(idx * 100 / DARTBARSIZE, 100);
}
-bool Darts::dartHit() {
+int Darts::dartHit() {
Events &events = *_vm->_events;
// Process pending events
events.pollEventsAndWait();
if (events.kbHit()) {
- // Key was pressed, so discard it and return true
- events.clearKeyboard();
- return true;
+ // Key was pressed, so return it
+ Common::KeyState keyState = events.getKey();
+ return keyState.keycode;
}
_oldDartButtons = events._pressed;
@@ -548,10 +541,6 @@ bool Darts::findNumberOnBoard(int aim, Common::Point &pt) {
return done;
}
-void Darts::setFlagsForDarts(int flagNum) {
- _vm->_flags[ABS(flagNum)] = flagNum >= 0;
-}
-
} // End of namespace Scalpel
-} // End of namespace Scalpel
+} // End of namespace Sherlock
diff --git a/engines/sherlock/scalpel/darts.h b/engines/sherlock/scalpel/scalpel_darts.h
index 42990f8056..483a163510 100644
--- a/engines/sherlock/scalpel/darts.h
+++ b/engines/sherlock/scalpel/scalpel_darts.h
@@ -20,10 +20,10 @@
*
*/
-#ifndef SHERLOCK_DARTS_H
-#define SHERLOCK_DARTS_H
+#ifndef SHERLOCK_SCALPEL_DARTS_H
+#define SHERLOCK_SCALPEL_DARTS_H
-#include "sherlock/resources.h"
+#include "sherlock/image_file.h"
namespace Sherlock {
@@ -97,7 +97,7 @@ private:
/**
* Returns true if a mouse button or key is pressed.
*/
- bool dartHit();
+ int dartHit();
/**
* Return the score of the given location on the dart-board
@@ -114,12 +114,6 @@ private:
* Returns the center position for the area of the dartboard with a given number
*/
bool findNumberOnBoard(int aim, Common::Point &pt);
-
- /**
- * Set a global flag to 0 or 1 depending on whether the passed flag is negative or positive.
- * @remarks We don't use the global setFlags method because we don't want to check scene flags
- */
- void setFlagsForDarts(int flagNum);
public:
Darts(ScalpelEngine *vm);
diff --git a/engines/sherlock/scalpel/scalpel_debugger.cpp b/engines/sherlock/scalpel/scalpel_debugger.cpp
new file mode 100644
index 0000000000..7f5e1efa69
--- /dev/null
+++ b/engines/sherlock/scalpel/scalpel_debugger.cpp
@@ -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.
+ *
+ */
+
+#include "sherlock/scalpel/scalpel_debugger.h"
+#include "sherlock/sherlock.h"
+#include "audio/mixer.h"
+#include "audio/decoders/3do.h"
+#include "audio/decoders/aiff.h"
+#include "audio/decoders/wave.h"
+
+namespace Sherlock {
+
+namespace Scalpel {
+
+ScalpelDebugger::ScalpelDebugger(SherlockEngine *vm) : Debugger(vm) {
+ registerCmd("3do_playmovie", WRAP_METHOD(ScalpelDebugger, cmd3DO_PlayMovie));
+ registerCmd("3do_playaudio", WRAP_METHOD(ScalpelDebugger, cmd3DO_PlayAudio));
+}
+
+bool ScalpelDebugger::cmd3DO_PlayMovie(int argc, const char **argv) {
+ if (argc != 2) {
+ debugPrintf("Format: 3do_playmovie <3do-movie-file>\n");
+ return true;
+ }
+
+ // play gets postboned until debugger is closed
+ Common::String filename = argv[1];
+ _3doPlayMovieFile = filename;
+
+ return cmdExit(0, 0);
+}
+
+bool ScalpelDebugger::cmd3DO_PlayAudio(int argc, const char **argv) {
+ if (argc != 2) {
+ debugPrintf("Format: 3do_playaudio <3do-audio-file>\n");
+ return true;
+ }
+
+ Common::File *file = new Common::File();
+ if (!file->open(argv[1])) {
+ debugPrintf("can not open specified audio file\n");
+ return true;
+ }
+
+ Audio::AudioStream *testStream;
+ Audio::SoundHandle testHandle;
+
+ // Try to load the given file as AIFF/AIFC
+ testStream = Audio::makeAIFFStream(file, DisposeAfterUse::YES);
+
+ if (testStream) {
+ g_system->getMixer()->playStream(Audio::Mixer::kPlainSoundType, &testHandle, testStream);
+ _vm->_events->clearEvents();
+
+ while ((!_vm->shouldQuit()) && g_system->getMixer()->isSoundHandleActive(testHandle)) {
+ _vm->_events->pollEvents();
+ g_system->delayMillis(10);
+ if (_vm->_events->kbHit()) {
+ break;
+ }
+ }
+
+ debugPrintf("playing completed\n");
+ g_system->getMixer()->stopHandle(testHandle);
+ }
+
+ return true;
+}
+
+} // End of namespace Scalpel
+
+} // End of namespace Sherlock
diff --git a/engines/sherlock/scalpel/scalpel_debugger.h b/engines/sherlock/scalpel/scalpel_debugger.h
new file mode 100644
index 0000000000..17a84779f0
--- /dev/null
+++ b/engines/sherlock/scalpel/scalpel_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 SHERLOCK_SCALPEL_DEBUGGER_H
+#define SHERLOCK_SCALPEL_DEBUGGER_H
+
+#include "sherlock/debugger.h"
+
+namespace Sherlock {
+
+class SherlockEngine;
+
+namespace Scalpel {
+
+class ScalpelDebugger : public Debugger {
+private:
+ /**
+ * Plays a 3DO movie
+ */
+ bool cmd3DO_PlayMovie(int argc, const char **argv);
+
+ /**
+ * Plays a 3DO audio
+ */
+ bool cmd3DO_PlayAudio(int argc, const char **argv);
+public:
+ ScalpelDebugger(SherlockEngine *vm);
+ virtual ~ScalpelDebugger() {}
+};
+
+} // End of namespace Scalpel
+
+} // End of namespace Sherlock
+
+#endif /* SHERLOCK_DEBUGGER_H */
diff --git a/engines/sherlock/scalpel/scalpel_fixed_text.cpp b/engines/sherlock/scalpel/scalpel_fixed_text.cpp
new file mode 100644
index 0000000000..63f84d68c6
--- /dev/null
+++ b/engines/sherlock/scalpel/scalpel_fixed_text.cpp
@@ -0,0 +1,377 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public 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_fixed_text.h"
+#include "sherlock/sherlock.h"
+
+namespace Sherlock {
+
+namespace Scalpel {
+
+static const char *const fixedTextEN[] = {
+ // SH1: Window buttons
+ "Exit",
+ "Up",
+ "Down",
+ // SH1: Inventory buttons
+ "Exit",
+ "Look",
+ "Use",
+ "Give",
+ // 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",
+ // SH1: Journal search
+ "Exit",
+ "Backward",
+ "Forward",
+ "Text Not Found !",
+ // SH1: Initial Inventory
+ "A message requesting help",
+ "A number of business cards",
+ "Opera Tickets",
+ "Cuff Link",
+ "Wire Hook",
+ "Note",
+ "An open pocket watch",
+ "A piece of paper with numbers on it",
+ "A letter folded many times",
+ "Tarot Cards",
+ "An ornate key",
+ "A pawn ticket",
+ // SH2: Verbs
+ "Open",
+ "Look",
+ "Talk",
+ "Journal"
+};
+
+// sharp-s : 0xE1 / octal 341
+// small a-umlaut: 0x84 / octal 204
+// small o-umlaut: 0x94 / octal 224
+// small u-umlaut: 0x81 / octal 201
+static const char *const fixedTextDE[] = {
+ // SH1: Window buttons
+ "Zur\201ck",
+ "Hoch",
+ "Runter",
+ // SH1: Inventory buttons
+ "Zur\201ck",
+ "Schau",
+ "Benutze",
+ "Gib",
+ // 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",
+ // SH1: Journal search
+ "Zur\201ck",
+ "R\201ckw\204rts", // original: "Backward"
+ "Vorw\204rts", // original: "Forward"
+ "Text nicht gefunden!",
+ // SH1: Initial Inventory
+ "Ein Hilferuf von Lestrade",
+ "Holmes' Visitenkarten",
+ "Karten f\201rs Opernhaus",
+ "Manschettenkn\224pfe",
+ "Zum Haken verbogener Drahtkorb",
+ "Mitteilung am Epstein",
+ "Eine offene Taschenuhr",
+ "Ein Zettel mit Zahlen drauf",
+ "Ein mehrfach gefalteter Briefbogen",
+ "Ein Tarock-Kartenspiel", // [sic]
+ "Ein verzierter Schl\201ssel",
+ "Ein Pfandschein",
+ // SH2: Verbs
+ "\231ffne",
+ "Schau",
+ "Rede",
+ "Tagebuch"
+};
+
+// 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
+static const char *const fixedTextES[] = {
+ // SH1: Window buttons
+ "Exit",
+ "Subir",
+ "Bajar",
+ // SH1: Inventory buttons
+ "Exit",
+ "Mirar",
+ "Usar",
+ "Dar",
+ // SH1: Journal text
+ "Diario de Watson",
+ "Pagina %d",
+ // SH1: Journal buttons
+ "Exit",
+ "Retroceder",
+ "Subir",
+ "baJar",
+ "Adelante",
+ "Buscar",
+ "1a pagina",
+ "Ult pagina",
+ "Imprimir",
+ // SH1: Journal search
+ "Exit",
+ "Retroceder",
+ "Avanzar",
+ "Texto no encontrado!",
+ // SH1: Initial Inventory
+ "Un mensaje solicitando ayuda",
+ "Unas cuantas tarjetas de visita",
+ "Entradas para la opera",
+ "Unos gemelos",
+ "Un gancho de alambre",
+ "Una nota",
+ "Un reloj de bolsillo abierto",
+ "Un trozo de papel con unos numeros",
+ "Un carta muy plegada",
+ "Unas cartas de Tarot",
+ "Una llave muy vistosa",
+ "Una papeleta de empe\244o",
+};
+
+// =========================================
+
+// === Sherlock Holmes 1: Serrated Scalpel ===
+static const char *const fixedTextEN_ActionOpen[] = {
+ "This cannot be opened",
+ "It is already open",
+ "It is locked",
+ "Wait for Watson",
+ " ",
+ "."
+};
+
+static const char *const fixedTextDE_ActionOpen[] = {
+ "Das kann man nicht \224ffnen",
+ "Ist doch schon offen!",
+ "Leider verschlossen",
+ "Warte auf Watson",
+ " ",
+ "."
+};
+
+static const char *const fixedTextES_ActionOpen[] = {
+ "No puede ser abierto",
+ "Ya esta abierto",
+ "Esta cerrado",
+ "Espera a Watson",
+ " ",
+ "."
+};
+
+static const char *const fixedTextEN_ActionClose[] = {
+ "This cannot be closed",
+ "It is already closed",
+ "The safe door is in the way"
+};
+
+static const char *const fixedTextDE_ActionClose[] = {
+ "Das kann man nicht schlie\341en",
+ "Ist doch schon zu!",
+ "Die safet\201r ist Weg"
+};
+
+static const char *const fixedTextES_ActionClose[] = {
+ "No puede ser cerrado",
+ "Ya esta cerrado",
+ "La puerta de seguridad esta entre medias"
+};
+
+static const char *const fixedTextEN_ActionMove[] = {
+ "This cannot be moved",
+ "It is bolted to the floor",
+ "It is too heavy",
+ "The other crate is in the way"
+};
+
+
+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]
+};
+
+static const char *const fixedTextES_ActionMove[] = {
+ "No puede moverse",
+ "Esta sujeto a la pared",
+ "Es demasiado pesado",
+ "El otro cajon esta en mitad"
+};
+
+static const char *const fixedTextEN_ActionPick[] = {
+ "Nothing of interest here",
+ "It is bolted down",
+ "It is too big to carry",
+ "It is too heavy",
+ "I think a girl would be more your type",
+ "Those flowers belong to Penny",
+ "She's far too young for you!",
+ "I think a girl would be more your type!",
+ "Government property for official use only"
+};
+
+static const char *const fixedTextDE_ActionPick[] = {
+ "Nichts Interessantes da",
+ "Zu gut befestigt",
+ "Ist ja wohl ein bi\341chen zu gro\341, oder ?",
+ "Oha, VIEL zu schwer",
+ "Ich denke, Du stehst mehr auf M\204dchen ?",
+ "Diese Blumen geh\224ren Penny",
+ "Sie ist doch viel zu jung f\201r Dich!",
+ "Ich denke, Du stehst mehr auf M\204dchen ?",
+ "Staatseigentum - Nur f\201r den Dienstgebrauch !"
+};
+
+static const char *const fixedTextES_ActionPick[] = {
+ "No hay nada interesante",
+ "Esta anclado al suelo",
+ "Es muy grande para llevarlo",
+ "Pesa demasiado",
+ "Creo que una chica sera mas tu tipo",
+ "Esas flores pertenecen a Penny",
+ "\255Es demasiado joven para ti!",
+ "\255Creo que una chica sera mas tu tipo!",
+ "Propiedad del gobierno para uso oficial"
+};
+
+static const char *const fixedTextEN_ActionUse[] = {
+ "You can't do that",
+ "It had no effect",
+ "You can't reach it",
+ "OK, the door looks bigger! Happy?",
+ "Doors don't smoke"
+};
+
+static const char *const fixedTextDE_ActionUse[] = {
+ "Nein, das geht wirklich nicht",
+ "Tja keinerlei Wirkung",
+ "Da kommst du nicht dran",
+ "Na gut, die T\201r sieht jetzt gr\224\341er aus. Zufrieden?",
+ "T\201ren sind Nichtraucher!"
+};
+
+static const char *const fixedTextES_ActionUse[] = {
+ "No puedes hacerlo",
+ "No tuvo ningun efecto",
+ "No puedes alcanzarlo",
+ "Bien, \255es enorme! \250Feliz?",
+ "Las puertas no fuman"
+};
+
+#define FIXEDTEXT_GETCOUNT(_name_) sizeof(_name_) / sizeof(byte *)
+#define FIXEDTEXT_ENTRY(_name_) _name_, FIXEDTEXT_GETCOUNT(_name_)
+
+static const FixedTextActionEntry fixedTextEN_Actions[] = {
+ { FIXEDTEXT_ENTRY(fixedTextEN_ActionOpen) },
+ { FIXEDTEXT_ENTRY(fixedTextEN_ActionClose) },
+ { FIXEDTEXT_ENTRY(fixedTextEN_ActionMove) },
+ { FIXEDTEXT_ENTRY(fixedTextEN_ActionPick) },
+ { FIXEDTEXT_ENTRY(fixedTextEN_ActionUse) }
+};
+
+static const FixedTextActionEntry fixedTextDE_Actions[] = {
+ { FIXEDTEXT_ENTRY(fixedTextDE_ActionOpen) },
+ { FIXEDTEXT_ENTRY(fixedTextDE_ActionClose) },
+ { FIXEDTEXT_ENTRY(fixedTextDE_ActionMove) },
+ { FIXEDTEXT_ENTRY(fixedTextDE_ActionPick) },
+ { FIXEDTEXT_ENTRY(fixedTextDE_ActionUse) }
+};
+
+static const FixedTextActionEntry fixedTextES_Actions[] = {
+ { FIXEDTEXT_ENTRY(fixedTextES_ActionOpen) },
+ { FIXEDTEXT_ENTRY(fixedTextES_ActionClose) },
+ { FIXEDTEXT_ENTRY(fixedTextES_ActionMove) },
+ { FIXEDTEXT_ENTRY(fixedTextES_ActionPick) },
+ { FIXEDTEXT_ENTRY(fixedTextES_ActionUse) }
+};
+
+// =========================================
+
+// 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 },
+ { Common::EN_ANY, fixedTextEN, fixedTextEN_Actions },
+ { Common::UNK_LANG, fixedTextEN, fixedTextEN_Actions }
+};
+
+// =========================================
+
+// =========================================
+
+ScalpelFixedText::ScalpelFixedText(SherlockEngine *vm) : FixedText(vm) {
+ // 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 *ScalpelFixedText::getText(int fixedTextId) {
+ return _curLanguageEntry->fixedTextArray[fixedTextId];
+}
+
+const Common::String ScalpelFixedText::getActionMessage(FixedTextActionId actionId, int messageIndex) {
+ assert(actionId >= 0);
+ assert(messageIndex >= 0);
+ const FixedTextActionEntry *curActionEntry = &_curLanguageEntry->actionArray[actionId];
+
+ assert(messageIndex < curActionEntry->fixedTextArrayCount);
+ return Common::String(curActionEntry->fixedTextArray[messageIndex]);
+}
+
+} // End of namespace Scalpel
+
+} // End of namespace Sherlock
diff --git a/engines/sherlock/scalpel/scalpel_fixed_text.h b/engines/sherlock/scalpel/scalpel_fixed_text.h
new file mode 100644
index 0000000000..eae86b8f27
--- /dev/null
+++ b/engines/sherlock/scalpel/scalpel_fixed_text.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.
+ *
+ */
+
+#ifndef SHERLOCK_SCALPEL_FIXED_TEXT_H
+#define SHERLOCK_SCALPEL_FIXED_TEXT_H
+
+#include "sherlock/fixed_text.h"
+
+namespace Sherlock {
+
+namespace Scalpel {
+
+enum FixedTextId {
+ // Window buttons
+ kFixedText_Window_Exit = 0,
+ kFixedText_Window_Up,
+ kFixedText_Window_Down,
+ // Inventory buttons
+ kFixedText_Inventory_Exit,
+ kFixedText_Inventory_Look,
+ kFixedText_Inventory_Use,
+ kFixedText_Inventory_Give,
+ // Journal text
+ kFixedText_Journal_WatsonsJournal,
+ kFixedText_Journal_Page,
+ // Journal buttons
+ kFixedText_Journal_Exit,
+ kFixedText_Journal_Back10,
+ kFixedText_Journal_Up,
+ kFixedText_Journal_Down,
+ kFixedText_Journal_Ahead10,
+ kFixedText_Journal_Search,
+ kFixedText_Journal_FirstPage,
+ kFixedText_Journal_LastPage,
+ kFixedText_Journal_PrintText,
+ // Journal search
+ kFixedText_JournalSearch_Exit,
+ kFixedText_JournalSearch_Backward,
+ kFixedText_JournalSearch_Forward,
+ kFixedText_JournalSearch_NotFound,
+ // Initial inventory
+ kFixedText_InitInventory_Message,
+ kFixedText_InitInventory_HolmesCard,
+ kFixedText_InitInventory_Tickets,
+ kFixedText_InitInventory_CuffLink,
+ kFixedText_InitInventory_WireHook,
+ kFixedText_InitInventory_Note,
+ kFixedText_InitInventory_OpenWatch,
+ kFixedText_InitInventory_Paper,
+ kFixedText_InitInventory_Letter,
+ kFixedText_InitInventory_Tarot,
+ kFixedText_InitInventory_OrnateKey,
+ kFixedText_InitInventory_PawnTicket
+};
+
+struct FixedTextActionEntry {
+ const char *const *fixedTextArray;
+ int fixedTextArrayCount;
+};
+
+struct FixedTextLanguageEntry {
+ Common::Language language;
+ const char *const *fixedTextArray;
+ const FixedTextActionEntry *actionArray;
+};
+
+class ScalpelFixedText: public FixedText {
+private:
+ const FixedTextLanguageEntry *_curLanguageEntry;
+public:
+ ScalpelFixedText(SherlockEngine *vm);
+ virtual ~ScalpelFixedText() {}
+
+ /**
+ * Gets text
+ */
+ virtual const char *getText(int fixedTextId);
+
+ /**
+ * Get action message
+ */
+ virtual const Common::String getActionMessage(FixedTextActionId actionId, int messageIndex);
+};
+
+} // End of namespace Scalpel
+
+} // End of namespace Sherlock
+
+#endif
diff --git a/engines/sherlock/scalpel/scalpel_inventory.cpp b/engines/sherlock/scalpel/scalpel_inventory.cpp
new file mode 100644
index 0000000000..e19a43238c
--- /dev/null
+++ b/engines/sherlock/scalpel/scalpel_inventory.cpp
@@ -0,0 +1,296 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public 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_inventory.h"
+#include "sherlock/scalpel/scalpel_fixed_text.h"
+#include "sherlock/scalpel/scalpel_screen.h"
+#include "sherlock/scalpel/scalpel_user_interface.h"
+#include "sherlock/scalpel/scalpel.h"
+
+namespace Sherlock {
+
+namespace Scalpel {
+
+ScalpelInventory::ScalpelInventory(SherlockEngine *vm) : Inventory(vm) {
+ _invShapes.resize(6);
+}
+
+ScalpelInventory::~ScalpelInventory() {
+}
+
+void ScalpelInventory::drawInventory(InvNewMode mode) {
+ FixedText &fixedText = *_vm->_fixedText;
+ ScalpelScreen &screen = *(ScalpelScreen *)_vm->_screen;
+ UserInterface &ui = *_vm->_ui;
+ InvNewMode tempMode = mode;
+
+ loadInv();
+
+ if (mode == INVENTORY_DONT_DISPLAY) {
+ screen._backBuffer = &screen._backBuffer2;
+ }
+
+ // Draw the window background
+ Surface &bb = *screen._backBuffer;
+ 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,
+ SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT), BORDER_COLOR);
+ bb.fillRect(Common::Rect(0, SHERLOCK_SCREEN_HEIGHT - 2, SHERLOCK_SCREEN_WIDTH,
+ SHERLOCK_SCREEN_HEIGHT), BORDER_COLOR);
+ bb.fillRect(Common::Rect(2, CONTROLS_Y1 + 10, SHERLOCK_SCREEN_WIDTH - 2, SHERLOCK_SCREEN_HEIGHT - 2),
+ 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);
+ 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);
+ 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);
+ 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);
+ 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
+ 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
+ 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
+ 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
+
+ if (tempMode == INVENTORY_DONT_DISPLAY)
+ mode = LOOK_INVENTORY_MODE;
+ _invMode = (InvMode)((int)mode);
+
+ if (mode != PLAIN_INVENTORY) {
+ ui._oldKey = INVENTORY_COMMANDS[(int)mode];
+ } else {
+ ui._oldKey = -1;
+ }
+
+ invCommands(0);
+ putInv(SLAM_DONT_DISPLAY);
+
+ if (tempMode != INVENTORY_DONT_DISPLAY) {
+ if (!ui._slideWindows) {
+ screen.slamRect(Common::Rect(0, CONTROLS_Y1, SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT));
+ } else {
+ ui.summonWindow(false, CONTROLS_Y1);
+ }
+
+ ui._windowOpen = true;
+ } else {
+ // Reset the screen back buffer to the first buffer now that drawing is done
+ screen._backBuffer = &screen._backBuffer1;
+ }
+
+ assert(IS_SERRATED_SCALPEL);
+ ((ScalpelUserInterface *)_vm->_ui)->_oldUse = -1;
+}
+
+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);
+ screen.buttonPrint(Common::Point(INVENTORY_POINTS[1][2], CONTROLS_Y1),
+ _invMode == INVMODE_LOOK ? COMMAND_HIGHLIGHTED :COMMAND_FOREGROUND,
+ true, fixedText_Look);
+ screen.buttonPrint(Common::Point(INVENTORY_POINTS[2][2], CONTROLS_Y1),
+ _invMode == INVMODE_USE ? COMMAND_HIGHLIGHTED : COMMAND_FOREGROUND,
+ true, fixedText_Use);
+ screen.buttonPrint(Common::Point(INVENTORY_POINTS[3][2], CONTROLS_Y1),
+ _invMode == INVMODE_GIVE ? COMMAND_HIGHLIGHTED : COMMAND_FOREGROUND,
+ true, fixedText_Give);
+ screen.print(Common::Point(INVENTORY_POINTS[4][2], CONTROLS_Y1 + 1),
+ _invIndex == 0 ? COMMAND_NULL : COMMAND_FOREGROUND,
+ "^^"); // 2 arrows pointing to the left
+ screen.print(Common::Point(INVENTORY_POINTS[5][2], CONTROLS_Y1 + 1),
+ _invIndex == 0 ? COMMAND_NULL : COMMAND_FOREGROUND,
+ "^"); // 2 arrows pointing to the left
+ screen.print(Common::Point(INVENTORY_POINTS[6][2], CONTROLS_Y1 + 1),
+ (_holdings - _invIndex <= 6) ? COMMAND_NULL : COMMAND_FOREGROUND,
+ "_"); // 1 arrow pointing to the right
+ screen.print(Common::Point(INVENTORY_POINTS[7][2], CONTROLS_Y1 + 1),
+ (_holdings - _invIndex <= 6) ? COMMAND_NULL : COMMAND_FOREGROUND,
+ "__"); // 2 arrows pointing to the right
+ if (_invMode != INVMODE_LOOK)
+ ui.clearInfo();
+ } else {
+ screen.buttonPrint(Common::Point(INVENTORY_POINTS[0][2], CONTROLS_Y1),
+ _invMode == INVMODE_EXIT ? COMMAND_HIGHLIGHTED : COMMAND_FOREGROUND,
+ false, fixedText_Exit);
+ screen.buttonPrint(Common::Point(INVENTORY_POINTS[1][2], CONTROLS_Y1),
+ _invMode == INVMODE_LOOK ? COMMAND_HIGHLIGHTED : COMMAND_FOREGROUND,
+ false, fixedText_Look);
+ screen.buttonPrint(Common::Point(INVENTORY_POINTS[2][2], CONTROLS_Y1),
+ _invMode == INVMODE_USE ? COMMAND_HIGHLIGHTED : COMMAND_FOREGROUND,
+ false, fixedText_Use);
+ screen.buttonPrint(Common::Point(INVENTORY_POINTS[3][2], CONTROLS_Y1),
+ _invMode == INVMODE_GIVE ? COMMAND_HIGHLIGHTED : COMMAND_FOREGROUND,
+ false, fixedText_Give);
+ screen.gPrint(Common::Point(INVENTORY_POINTS[4][2], CONTROLS_Y1),
+ _invIndex == 0 ? COMMAND_NULL : COMMAND_FOREGROUND,
+ "^^"); // 2 arrows pointing to the left
+ screen.gPrint(Common::Point(INVENTORY_POINTS[5][2], CONTROLS_Y1),
+ _invIndex == 0 ? COMMAND_NULL : COMMAND_FOREGROUND,
+ "^"); // 1 arrow pointing to the left
+ screen.gPrint(Common::Point(INVENTORY_POINTS[6][2], CONTROLS_Y1),
+ (_holdings - _invIndex < 7) ? COMMAND_NULL : COMMAND_FOREGROUND,
+ "_"); // 1 arrow pointing to the right
+ screen.gPrint(Common::Point(INVENTORY_POINTS[7][2], CONTROLS_Y1),
+ (_holdings - _invIndex < 7) ? COMMAND_NULL : COMMAND_FOREGROUND,
+ "__"); // 2 arrows pointing to the right
+ }
+}
+
+void ScalpelInventory::highlight(int index, byte color) {
+ Screen &screen = *_vm->_screen;
+ Surface &bb = *screen._backBuffer;
+ 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),
+ 163 + ((33 - frame._height) / 2)));
+ screen.slamArea(8 + slot * 52, 165, 44, 30);
+}
+
+void ScalpelInventory::refreshInv() {
+ Screen &screen = *_vm->_screen;
+ Talk &talk = *_vm->_talk;
+ ScalpelUserInterface &ui = *(ScalpelUserInterface *)_vm->_ui;
+
+ ui._invLookFlag = true;
+ freeInv();
+
+ ui._infoFlag = true;
+ ui.clearInfo();
+
+ screen._backBuffer2.blitFrom(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));
+ loadInv();
+ }
+}
+
+void ScalpelInventory::putInv(InvSlamMode slamIt) {
+ ScalpelScreen &screen = *(ScalpelScreen *)_vm->_screen;
+ UserInterface &ui = *_vm->_ui;
+
+ // If an inventory item has disappeared (due to using it or giving it),
+ // a blank space slot may have appeared. If so, adjust the inventory
+ if (_invIndex > 0 && _invIndex > (_holdings - (int)_invShapes.size())) {
+ --_invIndex;
+ freeGraphics();
+ loadGraphics();
+ }
+
+ if (slamIt != SLAM_SECONDARY_BUFFER) {
+ screen.makePanel(Common::Rect(6, 163, 54, 197));
+ screen.makePanel(Common::Rect(58, 163, 106, 197));
+ screen.makePanel(Common::Rect(110, 163, 158, 197));
+ screen.makePanel(Common::Rect(162, 163, 210, 197));
+ screen.makePanel(Common::Rect(214, 163, 262, 197));
+ screen.makePanel(Common::Rect(266, 163, 314, 197));
+ }
+
+ // Iterate through displaying up to 6 objects at a time
+ for (int idx = _invIndex; idx < _holdings && (idx - _invIndex) < (int)_invShapes.size(); ++idx) {
+ int itemNum = idx - _invIndex;
+ Surface &bb = slamIt == SLAM_SECONDARY_BUFFER ? screen._backBuffer2 : screen._backBuffer1;
+ Common::Rect r(8 + itemNum * 52, 165, 51 + itemNum * 52, 194);
+
+ // Draw the background
+ if (idx == ui._selector) {
+ bb.fillRect(r, BUTTON_BACKGROUND);
+ }
+ else if (slamIt == SLAM_SECONDARY_BUFFER) {
+ bb.fillRect(r, BUTTON_MIDDLE);
+ }
+
+ // Draw the item image
+ ImageFrame &frame = (*_invShapes[itemNum])[0];
+ bb.transBlitFrom(frame, Common::Point(6 + itemNum * 52 + ((47 - frame._width) / 2),
+ 163 + ((33 - frame._height) / 2)));
+ }
+
+ if (slamIt == SLAM_DISPLAY)
+ screen.slamArea(6, 163, 308, 34);
+
+ if (slamIt != SLAM_SECONDARY_BUFFER)
+ ui.clearInfo();
+
+ if (slamIt == 0) {
+ invCommands(0);
+ }
+ else if (slamIt == SLAM_SECONDARY_BUFFER) {
+ screen._backBuffer = &screen._backBuffer2;
+ invCommands(0);
+ screen._backBuffer = &screen._backBuffer1;
+ }
+}
+
+void ScalpelInventory::loadInv() {
+ // Exit if the inventory names are already loaded
+ if (_names.size() > 0)
+ return;
+
+ // Load the inventory names
+ Common::SeekableReadStream *stream = _vm->_res->load("invent.txt");
+
+ int streamSize = stream->size();
+ while (stream->pos() < streamSize) {
+ Common::String name;
+ char c;
+ while ((c = stream->readByte()) != 0)
+ name += c;
+
+ _names.push_back(name);
+ }
+
+ delete stream;
+
+ loadGraphics();
+}
+
+} // End of namespace Scalpel
+
+} // End of namespace Sherlock
diff --git a/engines/sherlock/scalpel/scalpel_inventory.h b/engines/sherlock/scalpel/scalpel_inventory.h
new file mode 100644
index 0000000000..afafb0b94a
--- /dev/null
+++ b/engines/sherlock/scalpel/scalpel_inventory.h
@@ -0,0 +1,74 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public 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_INVENTORY_H
+#define SHERLOCK_SCALPEL_INVENTORY_H
+
+#include "sherlock/inventory.h"
+
+namespace Sherlock {
+
+namespace Scalpel {
+
+class ScalpelInventory : public Inventory {
+public:
+ ScalpelInventory(SherlockEngine *vm);
+ ~ScalpelInventory();
+
+ /**
+ * Put the game into inventory mode and open the interface window.
+ */
+ void drawInventory(InvNewMode flag);
+
+ /**
+ * Prints the line of inventory commands at the top of an inventory window with
+ * the correct highlighting
+ */
+ void invCommands(bool slamIt);
+
+ /**
+ * Set the highlighting color of a given inventory item
+ */
+ void highlight(int index, byte color);
+
+ /**
+ * Support method for refreshing the display of the inventory
+ */
+ void refreshInv();
+
+ /**
+ * Display the character's inventory. The slamIt parameter specifies:
+ */
+ void putInv(InvSlamMode slamIt);
+
+ /**
+ * Load the list of names the inventory items correspond to, if not already loaded,
+ * and then calls loadGraphics to load the associated graphics
+ */
+ virtual void loadInv();
+};
+
+} // End of namespace Scalpel
+
+} // End of namespace Sherlock
+
+#endif
diff --git a/engines/sherlock/scalpel/scalpel_journal.cpp b/engines/sherlock/scalpel/scalpel_journal.cpp
new file mode 100644
index 0000000000..787d899aee
--- /dev/null
+++ b/engines/sherlock/scalpel/scalpel_journal.cpp
@@ -0,0 +1,636 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public 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/journal.h"
+#include "sherlock/sherlock.h"
+#include "sherlock/scalpel/scalpel_fixed_text.h"
+#include "sherlock/scalpel/scalpel_journal.h"
+#include "sherlock/scalpel/scalpel_screen.h"
+#include "sherlock/scalpel/scalpel.h"
+#include "sherlock/tattoo/tattoo_journal.h"
+
+namespace Sherlock {
+
+namespace Scalpel {
+
+#define JOURNAL_BUTTONS_Y 178
+#define JOURNAL_SEARCH_LEFT 15
+#define JOURNAL_SEARCH_TOP 186
+#define JOURNAL_SEARCH_RIGHT 296
+#define JOURNAL_SEACRH_MAX_CHARS 50
+
+// Positioning of buttons in the journal view
+static const int JOURNAL_POINTS[9][3] = {
+ { 6, 68, 37 },
+ { 69, 131, 100 },
+ { 132, 192, 162 },
+ { 193, 250, 221 },
+ { 251, 313, 281 },
+ { 6, 82, 44 },
+ { 83, 159, 121 },
+ { 160, 236, 198 },
+ { 237, 313, 275 }
+};
+
+static const int SEARCH_POINTS[3][3] = {
+ { 51, 123, 86 },
+ { 124, 196, 159 },
+ { 197, 269, 232 }
+};
+
+/*----------------------------------------------------------------*/
+
+ScalpelJournal::ScalpelJournal(SherlockEngine *vm) : Journal(vm) {
+ if (_vm->_interactiveFl) {
+ // Load the journal directory and location names
+ loadLocations();
+ }
+}
+
+void ScalpelJournal::loadLocations() {
+ Resources &res = *_vm->_res;
+
+ _directory.clear();
+ _locations.clear();
+
+
+ Common::SeekableReadStream *dir = res.load("talk.lib");
+ dir->skip(4); // Skip header
+
+ // Get the numer of entries
+ _directory.resize(dir->readUint16LE());
+
+ // Read in each entry
+ char buffer[17];
+ for (uint idx = 0; idx < _directory.size(); ++idx) {
+ dir->read(buffer, 17);
+ buffer[16] = '\0';
+
+ _directory[idx] = Common::String(buffer);
+ }
+
+ delete dir;
+
+ if (IS_3DO) {
+ // 3DO: storage of locations is currently unknown TODO
+ return;
+ }
+
+ // Load in the locations stored in journal.txt
+ Common::SeekableReadStream *loc = res.load("journal.txt");
+
+ while (loc->pos() < loc->size()) {
+ Common::String line;
+ char c;
+ while ((c = loc->readByte()) != 0)
+ line += c;
+
+ _locations.push_back(line);
+ }
+
+ delete loc;
+}
+
+void ScalpelJournal::drawFrame() {
+ FixedText &fixedText = *_vm->_fixedText;
+ Resources &res = *_vm->_res;
+ ScalpelScreen &screen = *(ScalpelScreen *)_vm->_screen;
+ byte palette[PALETTE_SIZE];
+
+ // Load in the journal background
+ Common::SeekableReadStream *bg = res.load("journal.lbv");
+ bg->read(screen._backBuffer1.getPixels(), SHERLOCK_SCREEN_WIDTH * SHERLOCK_SCREEN_HEIGHT);
+ bg->read(palette, PALETTE_SIZE);
+ delete bg;
+
+ // Translate the palette for display
+ 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());
+
+ // 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);
+ 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);
+ 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);
+ 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);
+ 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);
+ 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);
+ 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);
+ 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);
+
+ // 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);
+ screen.buttonPrint(Common::Point(JOURNAL_POINTS[8][2], JOURNAL_BUTTONS_Y + 11),
+ COMMAND_NULL, false, fixedText_PrintText);
+}
+
+void ScalpelJournal::drawInterface() {
+ ScalpelScreen &screen = *(ScalpelScreen *)_vm->_screen;
+
+ drawFrame();
+
+ if (_journal.empty()) {
+ _up = _down = 0;
+ } else {
+ drawJournal(0, 0);
+ }
+
+ doArrows();
+
+ // Show the entire screen
+ screen.slamArea(0, 0, SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT);
+}
+
+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);
+
+ 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);
+
+ 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);
+
+ color = _page > 1 ? COMMAND_FOREGROUND : COMMAND_NULL;
+ screen.buttonPrint(Common::Point(JOURNAL_POINTS[6][2], JOURNAL_BUTTONS_Y + 11), color, false, fixedText_FirstPage);
+}
+
+JournalButton ScalpelJournal::getHighlightedButton(const Common::Point &pt) {
+ if (pt.x > JOURNAL_POINTS[0][0] && pt.x < JOURNAL_POINTS[0][1] && pt.y >= JOURNAL_BUTTONS_Y &&
+ pt.y < (JOURNAL_BUTTONS_Y + 10))
+ return BTN_EXIT;
+
+ if (pt.x > JOURNAL_POINTS[1][0] && pt.x < JOURNAL_POINTS[1][1] && pt.y >= JOURNAL_BUTTONS_Y &&
+ pt.y < (JOURNAL_BUTTONS_Y + 10) && _page > 1)
+ return BTN_BACK10;
+
+ if (pt.x > JOURNAL_POINTS[2][0] && pt.x < JOURNAL_POINTS[2][1] && pt.y >= JOURNAL_BUTTONS_Y &&
+ pt.y < (JOURNAL_BUTTONS_Y + 10) && _up)
+ return BTN_UP;
+
+ if (pt.x > JOURNAL_POINTS[3][0] && pt.x < JOURNAL_POINTS[3][1] && pt.y >= JOURNAL_BUTTONS_Y &&
+ pt.y < (JOURNAL_BUTTONS_Y + 10) && _down)
+ return BTN_DOWN;
+
+ if (pt.x > JOURNAL_POINTS[4][0] && pt.x < JOURNAL_POINTS[4][1] && pt.y >= JOURNAL_BUTTONS_Y &&
+ pt.y < (JOURNAL_BUTTONS_Y + 10) && _down)
+ return BTN_AHEAD110;
+
+ if (pt.x > JOURNAL_POINTS[5][0] && pt.x < JOURNAL_POINTS[5][1] && pt.y >= (JOURNAL_BUTTONS_Y + 11) &&
+ pt.y < (JOURNAL_BUTTONS_Y + 20) && !_journal.empty())
+ return BTN_SEARCH;
+
+ if (pt.x > JOURNAL_POINTS[6][0] && pt.x < JOURNAL_POINTS[6][1] && pt.y >= (JOURNAL_BUTTONS_Y + 11) &&
+ pt.y < (JOURNAL_BUTTONS_Y + 20) && _up)
+ return BTN_FIRST_PAGE;
+
+ if (pt.x > JOURNAL_POINTS[7][0] && pt.x < JOURNAL_POINTS[7][1] && pt.y >= (JOURNAL_BUTTONS_Y + 11) &&
+ pt.y < (JOURNAL_BUTTONS_Y + 20) && _down)
+ return BTN_LAST_PAGE;
+
+ if (pt.x > JOURNAL_POINTS[8][0] && pt.x < JOURNAL_POINTS[8][1] && pt.y >= (JOURNAL_BUTTONS_Y + 11) &&
+ pt.y < (JOURNAL_BUTTONS_Y + 20) && !_journal.empty())
+ return BTN_PRINT_TEXT;
+
+ return BTN_NONE;
+}
+
+bool ScalpelJournal::handleEvents(int key) {
+ Events &events = *_vm->_events;
+ FixedText &fixedText = *_vm->_fixedText;
+ ScalpelScreen &screen = *(ScalpelScreen *)_vm->_screen;
+ bool doneFlag = false;
+
+ Common::Point pt = events.mousePos();
+ JournalButton btn = getHighlightedButton(pt);
+ 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);
+
+ // Back 10 button
+ if (btn == BTN_BACK10) {
+ screen.buttonPrint(Common::Point(JOURNAL_POINTS[1][2], JOURNAL_BUTTONS_Y), COMMAND_HIGHLIGHTED, true, fixedText_Back10);
+ } else if (_page > 1) {
+ screen.buttonPrint(Common::Point(JOURNAL_POINTS[1][2], JOURNAL_BUTTONS_Y), COMMAND_FOREGROUND, true, fixedText_Back10);
+ }
+
+ // Up button
+ if (btn == BTN_UP) {
+ screen.buttonPrint(Common::Point(JOURNAL_POINTS[2][2], JOURNAL_BUTTONS_Y), COMMAND_HIGHLIGHTED, true, fixedText_Up);
+ } else if (_up) {
+ screen.buttonPrint(Common::Point(JOURNAL_POINTS[2][2], JOURNAL_BUTTONS_Y), COMMAND_FOREGROUND, true, fixedText_Up);
+ }
+
+ // Down button
+ if (btn == BTN_DOWN) {
+ screen.buttonPrint(Common::Point(JOURNAL_POINTS[3][2], JOURNAL_BUTTONS_Y), COMMAND_HIGHLIGHTED, true, fixedText_Down);
+ } else if (_down) {
+ screen.buttonPrint(Common::Point(JOURNAL_POINTS[3][2], JOURNAL_BUTTONS_Y), COMMAND_FOREGROUND, true, fixedText_Down);
+ }
+
+ // Ahead 10 button
+ if (btn == BTN_AHEAD110) {
+ screen.buttonPrint(Common::Point(JOURNAL_POINTS[4][2], JOURNAL_BUTTONS_Y), COMMAND_HIGHLIGHTED, true, fixedText_Ahead10);
+ } else if (_down) {
+ screen.buttonPrint(Common::Point(JOURNAL_POINTS[4][2], JOURNAL_BUTTONS_Y), COMMAND_FOREGROUND, true, fixedText_Ahead10);
+ }
+
+ // Search button
+ if (btn == BTN_SEARCH) {
+ color = COMMAND_HIGHLIGHTED;
+ } else if (_journal.empty()) {
+ color = COMMAND_NULL;
+ } else {
+ color = COMMAND_FOREGROUND;
+ }
+ screen.buttonPrint(Common::Point(JOURNAL_POINTS[5][2], JOURNAL_BUTTONS_Y + 11), color, true, fixedText_Search);
+
+ // First Page button
+ if (btn == BTN_FIRST_PAGE) {
+ color = COMMAND_HIGHLIGHTED;
+ } else if (_up) {
+ color = COMMAND_FOREGROUND;
+ } else {
+ color = COMMAND_NULL;
+ }
+ screen.buttonPrint(Common::Point(JOURNAL_POINTS[6][2], JOURNAL_BUTTONS_Y + 11), color, true, fixedText_FirstPage);
+
+ // Last Page button
+ if (btn == BTN_LAST_PAGE) {
+ color = COMMAND_HIGHLIGHTED;
+ } else if (_down) {
+ color = COMMAND_FOREGROUND;
+ } else {
+ color = COMMAND_NULL;
+ }
+ screen.buttonPrint(Common::Point(JOURNAL_POINTS[7][2], JOURNAL_BUTTONS_Y + 11), color, true, fixedText_LastPage);
+
+ // Print Text button
+ screen.buttonPrint(Common::Point(JOURNAL_POINTS[8][2], JOURNAL_BUTTONS_Y + 11), COMMAND_NULL, true, fixedText_PrintText);
+ }
+
+ if (btn == BTN_EXIT && events._released) {
+ // Exit button pressed
+ doneFlag = true;
+
+ } else if (((btn == BTN_BACK10 && events._released) || key == 'B') && (_page > 1)) {
+ // Scrolll up 10 pages
+ if (_page < 11)
+ drawJournal(1, (_page - 1) * LINES_PER_PAGE);
+ else
+ drawJournal(1, 10 * LINES_PER_PAGE);
+
+ doArrows();
+ screen.slamArea(0, 0, SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT);
+
+ } else if (((btn == BTN_UP && events._released) || key == 'U') && _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) {
+ // 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) {
+ // Scroll down 10 pages
+ if ((_page + 10) > _maxPage)
+ drawJournal(2, (_maxPage - _page) * LINES_PER_PAGE);
+ else
+ drawJournal(2, 10 * LINES_PER_PAGE);
+
+ 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");
+ bool notFound = false;
+
+ do {
+ int dir;
+ if ((dir = getSearchString(notFound)) != 0) {
+ int savedIndex = _index;
+ int savedSub = _sub;
+ int savedPage = _page;
+
+ if (drawJournal(dir + 2, 1000 * LINES_PER_PAGE) == 0) {
+ _index = savedIndex;
+ _sub = savedSub;
+ _page = savedPage;
+
+ drawFrame();
+ drawJournal(0, 0);
+ notFound = true;
+ } else {
+ doneFlag = true;
+ }
+
+ doArrows();
+ screen.slamArea(0, 0, SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT);
+ } else {
+ doneFlag = true;
+ }
+ } while (!doneFlag);
+ doneFlag = false;
+
+ } else if (((btn == BTN_FIRST_PAGE && events._released) || key == 'F') && _up) {
+ // First page
+ _index = _sub = 0;
+ _up = _down = false;
+ _page = 1;
+
+ drawFrame();
+ drawJournal(0, 0);
+ doArrows();
+ screen.slamArea(0, 0, SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT);
+
+ } else if (((btn == BTN_LAST_PAGE && events._released) || key == 'L') && _down) {
+ // Last page
+ if ((_page + 10) > _maxPage)
+ drawJournal(2, (_maxPage - _page) * LINES_PER_PAGE);
+ else
+ drawJournal(2, 1000 * LINES_PER_PAGE);
+
+ doArrows();
+ screen.slamArea(0, 0, SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT);
+ }
+
+ events.wait(2);
+
+ return doneFlag;
+}
+
+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;
+ int yp = 174;
+ bool flag = false;
+ Common::String name;
+ 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);
+ 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);
+ 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]);
+
+ 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());
+ } 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());
+ name = _find;
+ }
+
+ screen.slamArea(6, 171, 307, 28);
+
+ if (printError) {
+ // Give time for user to see the message
+ events.setButtonState();
+ for (int idx = 0; idx < 40 && !_vm->shouldQuit() && !events.kbHit() && !events._released; ++idx) {
+ events.pollEvents();
+ events.setButtonState();
+ events.wait(2);
+ }
+
+ events.clearKeyboard();
+ screen._backBuffer1.fillRect(Common::Rect(13, 186, 306, 195), BUTTON_MIDDLE);
+
+ if (!_find.empty()) {
+ screen.gPrint(Common::Point(15, 185), TALK_FOREGROUND, "%s", _find.c_str());
+ name = _find;
+ }
+
+ screen.slamArea(0, 0, SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT);
+ }
+
+ xp = JOURNAL_SEARCH_LEFT + screen.stringWidth(name);
+ yp = JOURNAL_SEARCH_TOP;
+
+ do {
+ events._released = false;
+ Button found = BTN_NONE;
+
+ while (!_vm->shouldQuit() && !events.kbHit() && !events._released) {
+ found = BTN_NONE;
+ if (talk._talkToAbort)
+ return 0;
+
+ // Check if key or mouse button press has occurred
+ events.setButtonState();
+ Common::Point pt = events.mousePos();
+
+ flag = !flag;
+ screen.vgaBar(Common::Rect(xp, yp, xp + 8, yp + 9), flag ? INV_FOREGROUND : BUTTON_MIDDLE);
+
+ if (events._pressed || events._released) {
+ if (pt.x > SEARCH_POINTS[0][0] && pt.x < SEARCH_POINTS[0][1] && pt.y > 174 && pt.y < 183) {
+ found = BTN_EXIT;
+ color = COMMAND_HIGHLIGHTED;
+ } else {
+ color = COMMAND_FOREGROUND;
+ }
+ screen.print(Common::Point(SEARCH_POINTS[0][2] - screen.stringWidth(fixedText_Exit) / 2, 175), color, "%s", fixedText_Exit.c_str());
+
+ if (pt.x > SEARCH_POINTS[1][0] && pt.x < SEARCH_POINTS[1][1] && pt.y > 174 && pt.y < 183) {
+ found = BTN_BACKWARD;
+ color = COMMAND_HIGHLIGHTED;
+ } else {
+ color = COMMAND_FOREGROUND;
+ }
+ screen.print(Common::Point(SEARCH_POINTS[1][2] - screen.stringWidth(fixedText_Backward) / 2, 175), color, "%s", fixedText_Backward.c_str());
+
+ if (pt.x > SEARCH_POINTS[2][0] && pt.x < SEARCH_POINTS[2][1] && pt.y > 174 && pt.y < 183) {
+ found = BTN_FORWARD;
+ color = COMMAND_HIGHLIGHTED;
+ } else {
+ color = COMMAND_FOREGROUND;
+ }
+ screen.print(Common::Point(SEARCH_POINTS[2][2] - screen.stringWidth(fixedText_Forward) / 2, 175), color, "%s", fixedText_Forward.c_str());
+ }
+
+ events.wait(2);
+ }
+
+ if (events.kbHit()) {
+ Common::KeyState keyState = events.getKey();
+
+ if ((keyState.keycode == Common::KEYCODE_BACKSPACE) && (name.size() > 0)) {
+ screen.vgaBar(Common::Rect(xp - screen.charWidth(name.lastChar()), yp, xp + 8, yp + 9), BUTTON_MIDDLE);
+ xp -= screen.charWidth(name.lastChar());
+ screen.vgaBar(Common::Rect(xp, yp, xp + 8, yp + 9), INV_FOREGROUND);
+ name.deleteLastChar();
+
+ } else if (keyState.keycode == Common::KEYCODE_RETURN) {
+ done = 1;
+
+ } else if (keyState.keycode == Common::KEYCODE_ESCAPE) {
+ screen.vgaBar(Common::Rect(xp, yp, xp + 8, yp + 9), BUTTON_MIDDLE);
+ done = -1;
+
+ } else if (keyState.ascii >= ' ' && keyState.ascii <= 'z' && keyState.keycode != Common::KEYCODE_AT &&
+ name.size() < JOURNAL_SEACRH_MAX_CHARS && (xp + screen.charWidth(keyState.ascii)) < JOURNAL_SEARCH_RIGHT) {
+ char ch = toupper(keyState.ascii);
+ screen.vgaBar(Common::Rect(xp, yp, xp + 8, yp + 9), BUTTON_MIDDLE);
+ screen.print(Common::Point(xp, yp), TALK_FOREGROUND, "%c", ch);
+ xp += screen.charWidth(ch);
+ name += ch;
+ }
+ }
+
+ if (events._released) {
+ switch (found) {
+ case BTN_EXIT:
+ done = -1; break;
+ case BTN_BACKWARD:
+ done = 2; break;
+ case BTN_FORWARD:
+ done = 1; break;
+ default:
+ break;
+ }
+ }
+ } while (!done && !_vm->shouldQuit());
+
+ if (done != -1) {
+ _find = name;
+ } else {
+ done = 0;
+ }
+
+ // Redisplay the journal screen
+ drawFrame();
+ drawJournal(0, 0);
+ screen.slamArea(0, 0, SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT);
+
+ return done;
+}
+
+void ScalpelJournal::resetPosition() {
+ _index = _sub = _up = _down = 0;
+ _page = 1;
+}
+
+void ScalpelJournal::record(int converseNum, int statementNum, bool replyOnly) {
+ // there seems to be no journal in the 3DO version
+ if (!IS_3DO)
+ Journal::record(converseNum, statementNum, replyOnly);
+}
+
+} // End of namespace Scalpel
+
+} // End of namespace Sherlock
diff --git a/engines/sherlock/scalpel/scalpel_journal.h b/engines/sherlock/scalpel/scalpel_journal.h
new file mode 100644
index 0000000000..c8e9c01739
--- /dev/null
+++ b/engines/sherlock/scalpel/scalpel_journal.h
@@ -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.
+ *
+ */
+
+#ifndef SHERLOCK_SCALPEL_JOURNAL_H
+#define SHERLOCK_SCALPEL_JOURNAL_H
+
+#include "sherlock/journal.h"
+#include "sherlock/saveload.h"
+#include "common/scummsys.h"
+#include "common/array.h"
+#include "common/rect.h"
+#include "common/str-array.h"
+#include "common/stream.h"
+
+namespace Sherlock {
+
+namespace Scalpel {
+
+enum JournalButton {
+ BTN_NONE, BTN_EXIT, BTN_BACK10, BTN_UP, BTN_DOWN, BTN_AHEAD110, BTN_SEARCH,
+ BTN_FIRST_PAGE, BTN_LAST_PAGE, BTN_PRINT_TEXT
+};
+
+class ScalpelJournal: public Journal {
+private:
+ /**
+ * Load the list of journal locations
+ */
+ void loadLocations();
+
+ /**
+ * Display the arrows that can be used to scroll up and down pages
+ */
+ void doArrows();
+
+ /**
+ * Show the search submenu and allow the player to enter a search string
+ */
+ int getSearchString(bool printError);
+
+ /**
+ * Returns the button, if any, that is under the specified position
+ */
+ JournalButton getHighlightedButton(const Common::Point &pt);
+public:
+ ScalpelJournal(SherlockEngine *vm);
+ virtual ~ScalpelJournal() {}
+
+ /**
+ * Display the journal
+ */
+ void drawInterface();
+
+ /**
+ * Handle events whilst the journal is being displayed
+ */
+ bool handleEvents(int key);
+public:
+ /**
+ * Draw the journal background, frame, and interface buttons
+ */
+ virtual void drawFrame();
+
+ /**
+ * Reset viewing position to the start of the journal
+ */
+ virtual void resetPosition();
+
+ /**
+ * Records statements that are said, in the order which they are said. The player
+ * can then read the journal to review them
+ */
+ virtual void record(int converseNum, int statementNum, bool replyOnly = false);
+};
+
+} // End of namespace Scalpel
+
+} // End of namespace Sherlock
+
+#endif
diff --git a/engines/sherlock/scalpel/scalpel_map.cpp b/engines/sherlock/scalpel/scalpel_map.cpp
new file mode 100644
index 0000000000..369822ba02
--- /dev/null
+++ b/engines/sherlock/scalpel/scalpel_map.cpp
@@ -0,0 +1,596 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public 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 "sherlock/scalpel/scalpel_map.h"
+#include "sherlock/events.h"
+#include "sherlock/people.h"
+#include "sherlock/screen.h"
+#include "sherlock/sherlock.h"
+
+namespace Sherlock {
+
+namespace Scalpel {
+
+MapPaths::MapPaths() {
+ _numLocations = 0;
+}
+
+void MapPaths::load(int numLocations, Common::SeekableReadStream &s) {
+ _numLocations = numLocations;
+ _paths.resize(_numLocations * _numLocations);
+
+ for (int idx = 0; idx < (numLocations * numLocations); ++idx) {
+ Common::Array<byte> &path = _paths[idx];
+ int v;
+
+ do {
+ v = s.readByte();
+ path.push_back(v);
+ } while (v && v < 254);
+ }
+}
+
+const byte *MapPaths::getPath(int srcLocation, int destLocation) {
+ return &_paths[srcLocation * _numLocations + destLocation][0];
+}
+
+/*----------------------------------------------------------------*/
+
+ScalpelMap::ScalpelMap(SherlockEngine *vm): Map(vm), _topLine(g_system->getWidth(), 12) {
+ _mapCursors = nullptr;
+ _shapes = nullptr;
+ _iconShapes = nullptr;
+ _point = 0;
+ _placesShown = false;
+ _cursorIndex = -1;
+ _drawMap = false;
+ _overPos = Point32(130 * FIXED_INT_MULTIPLIER, 126 * FIXED_INT_MULTIPLIER);
+ _frameChangeFlag = false;
+
+ // Initialise the initial walk sequence set
+ _walkSequences.resize(MAX_HOLMES_SEQUENCE);
+ for (int idx = 0; idx < MAX_HOLMES_SEQUENCE; ++idx) {
+ _walkSequences[idx]._sequences.resize(MAX_FRAME);
+ Common::fill(&_walkSequences[idx]._sequences[0], &_walkSequences[idx]._sequences[0] + MAX_FRAME, 0);
+ }
+
+ if (!_vm->isDemo())
+ loadData();
+}
+
+void ScalpelMap::loadPoints(int count, const int *xList, const int *yList, const int *transList) {
+ for (int idx = 0; idx < count; ++idx, ++xList, ++yList, ++transList) {
+ _points.push_back(MapEntry(*xList, *yList, *transList));
+ }
+}
+
+void ScalpelMap::loadSequences(int count, const byte *seq) {
+ for (int idx = 0; idx < count; ++idx, seq += MAX_FRAME)
+ Common::copy(seq, seq + MAX_FRAME, &_walkSequences[idx]._sequences[0]);
+}
+
+void ScalpelMap::loadData() {
+ // Load the list of location names
+ Common::SeekableReadStream *txtStream = _vm->_res->load("chess.txt");
+
+ int streamSize = txtStream->size();
+ while (txtStream->pos() < streamSize) {
+ Common::String line;
+ char c;
+ while ((c = txtStream->readByte()) != '\0')
+ line += c;
+
+ _locationNames.push_back(line);
+ }
+
+ delete txtStream;
+
+ // Load the path data
+ Common::SeekableReadStream *pathStream = _vm->_res->load("chess.pth");
+
+ // Get routes between different locations on the map
+ _paths.load(31, *pathStream);
+
+ // Load in the co-ordinates that the paths refer to
+ _pathPoints.resize(208);
+ for (uint idx = 0; idx < _pathPoints.size(); ++idx) {
+ _pathPoints[idx].x = pathStream->readSint16LE();
+ _pathPoints[idx].y = pathStream->readSint16LE();
+ }
+
+ delete pathStream;
+}
+
+int ScalpelMap::show() {
+ Debugger &debugger = *_vm->_debugger;
+ Events &events = *_vm->_events;
+ People &people = *_vm->_people;
+ Screen &screen = *_vm->_screen;
+ bool changed = false, exitFlag = false;
+ _active = true;
+
+ // Set font and custom cursor for the map
+ int oldFont = screen.fontNumber();
+ screen.setFont(0);
+
+ // Initial screen clear
+ screen._backBuffer1.clear();
+ screen.clear();
+
+ // Load the entire map
+ ImageFile *bigMap = NULL;
+ if (!IS_3DO) {
+ // PC
+ bigMap = new ImageFile("bigmap.vgs");
+ screen.setPalette(bigMap->_palette);
+ } else {
+ // 3DO
+ bigMap = new ImageFile3DO("overland.cel", kImageFile3DOType_Cel);
+ }
+
+ // Load need sprites
+ 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));
+ } else {
+ screen._backBuffer1.blitFrom((*bigMap)[0], Common::Point(-_bigPos.x, -_bigPos.y));
+ screen.blitFrom((*bigMap)[0], Common::Point(-_bigPos.x, -_bigPos.y));
+ }
+
+ _drawMap = true;
+ _charPoint = -1;
+ _point = -1;
+ people[HOLMES]._position = _lDrawnPos = _overPos;
+
+ // Show place icons
+ showPlaces();
+ saveTopLine();
+ _placesShown = true;
+
+ // Keep looping until either a location is picked, or the game is ended
+ while (!_vm->shouldQuit() && !exitFlag) {
+ events.pollEventsAndWait();
+ events.setButtonState();
+
+ if (debugger._showAllLocations == LOC_REFRESH) {
+ showPlaces();
+ screen.slamArea(screen._currentScroll.x, screen._currentScroll.y, SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_WIDTH);
+ }
+
+ // Keyboard handling
+ if (events.kbHit()) {
+ Common::KeyState keyState = events.getKey();
+
+ if (keyState.keycode == Common::KEYCODE_RETURN || keyState.keycode == Common::KEYCODE_SPACE) {
+ // Both space and enter simulate a mouse release
+ events._pressed = false;
+ events._released = true;
+ events._oldButtons = 0;
+ }
+ }
+
+ // Ignore scrolling attempts until the screen is drawn
+ if (!_drawMap) {
+ Common::Point pt = events.mousePos();
+
+ // Check for vertical map scrolling
+ if ((pt.y > (SHERLOCK_SCREEN_HEIGHT - 10) && _bigPos.y < 200) || (pt.y < 10 && _bigPos.y > 0)) {
+ if (pt.y > (SHERLOCK_SCREEN_HEIGHT - 10))
+ _bigPos.y += 10;
+ else
+ _bigPos.y -= 10;
+
+ changed = true;
+ }
+
+ // Check for horizontal map scrolling
+ if ((pt.x > (SHERLOCK_SCREEN_WIDTH - 10) && _bigPos.x < 315) || (pt.x < 10 && _bigPos.x > 0)) {
+ if (pt.x > (SHERLOCK_SCREEN_WIDTH - 10))
+ _bigPos.x += 15;
+ else
+ _bigPos.x -= 15;
+
+ changed = true;
+ }
+ }
+
+ if (changed) {
+ // Map has scrolled, so redraw new map view
+ 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));
+ } else {
+ screen._backBuffer1.blitFrom((*bigMap)[0], Common::Point(-_bigPos.x, -_bigPos.y));
+ }
+
+ showPlaces();
+ _placesShown = false;
+
+ saveTopLine();
+ _savedPos.x = -1;
+ updateMap(true);
+ } else if (!_drawMap) {
+ if (!_placesShown) {
+ showPlaces();
+ _placesShown = true;
+ }
+
+ if (_cursorIndex == 0) {
+ Common::Point pt = events.mousePos();
+ highlightIcon(Common::Point(pt.x - 4 + _bigPos.x, pt.y + _bigPos.y));
+ }
+ updateMap(false);
+ }
+
+ if ((events._released || events._rightReleased) && _point != -1) {
+ if (people[HOLMES]._walkCount == 0) {
+ people[HOLMES]._walkDest = _points[_point] + Common::Point(4, 9);
+ _charPoint = _point;
+
+ // Start walking to selected location
+ walkTheStreets();
+
+ // Show wait cursor
+ _cursorIndex = 1;
+ events.setCursor((*_mapCursors)[_cursorIndex]._frame);
+ }
+ }
+
+ // Check if a scene has beeen selected and we've finished "moving" to it
+ if (people[HOLMES]._walkCount == 0) {
+ if (_charPoint >= 1 && _charPoint < (int)_points.size())
+ exitFlag = true;
+ }
+
+ if (_drawMap) {
+ _drawMap = false;
+
+ if (screen._fadeStyle)
+ screen.randomTransition();
+ else
+ screen.slamArea(0, 0, SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT);
+ }
+
+ // Wait for a frame
+ events.wait(1);
+ }
+
+ freeSprites();
+ _overPos = people[HOLMES]._position;
+
+ // Reset font
+ screen.setFont(oldFont);
+
+ // Free map graphic
+ delete bigMap;
+
+ _active = false;
+ return _charPoint;
+}
+
+void ScalpelMap::setupSprites() {
+ Events &events = *_vm->_events;
+ People &people = *_vm->_people;
+ Scene &scene = *_vm->_scene;
+ _savedPos.x = -1;
+
+ if (!IS_3DO) {
+ // PC
+ _mapCursors = new ImageFile("omouse.vgs");
+ _shapes = new ImageFile("mapicon.vgs");
+ _iconShapes = new ImageFile("overicon.vgs");
+ } else {
+ // 3DO
+ _mapCursors = new ImageFile3DO("omouse.vgs", kImageFile3DOType_RoomFormat);
+ _shapes = new ImageFile3DO("mapicon.vgs", kImageFile3DOType_RoomFormat);
+ _iconShapes = new ImageFile3DO("overicon.vgs", kImageFile3DOType_RoomFormat);
+ }
+
+ _cursorIndex = 0;
+ events.setCursor((*_mapCursors)[_cursorIndex]._frame);
+
+ _iconSave.create((*_shapes)[4]._width, (*_shapes)[4]._height);
+ Person &p = people[HOLMES];
+ p._description = " ";
+ p._type = CHARACTER;
+ p._position = Common::Point(12400, 5000);
+ p._sequenceNumber = 0;
+ p._images = _shapes;
+ p._imageFrame = nullptr;
+ p._frameNumber = 0;
+ p._delta = Common::Point(0, 0);
+ p._oldSize = Common::Point(0, 0);
+ p._oldSize = Common::Point(0, 0);
+ p._misc = 0;
+ p._walkCount = 0;
+ p._allow = 0;
+ p._noShapeSize = Common::Point(0, 0);
+ p._goto = Common::Point(28000, 15000);
+ p._status = 0;
+ p._walkSequences = _walkSequences;
+ p.setImageFrame();
+ scene._bgShapes.clear();
+}
+
+void ScalpelMap::freeSprites() {
+ delete _mapCursors;
+ delete _shapes;
+ delete _iconShapes;
+ _iconSave.free();
+}
+
+void ScalpelMap::showPlaces() {
+ Debugger &debugger = *_vm->_debugger;
+ Screen &screen = *_vm->_screen;
+
+ for (uint idx = 0; idx < _points.size(); ++idx) {
+ const MapEntry &pt = _points[idx];
+
+ if (pt.x != 0 && pt.y != 0) {
+ if (debugger._showAllLocations != LOC_DISABLED)
+ _vm->setFlagsDirect(idx);
+
+ 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],
+ Common::Point(pt.x - _bigPos.x - 6, pt.y - _bigPos.y - 12));
+ }
+ }
+ }
+ }
+
+ if (debugger._showAllLocations == LOC_REFRESH)
+ debugger._showAllLocations = LOC_ALL;
+}
+
+void ScalpelMap::saveTopLine() {
+ _topLine.blitFrom(_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());
+}
+
+void ScalpelMap::showPlaceName(int idx, bool highlighted) {
+ People &people = *_vm->_people;
+ Screen &screen = *_vm->_screen;
+
+ Common::String name = _locationNames[idx];
+ int width = screen.stringWidth(name);
+
+ if (!_cursorIndex) {
+ saveIcon(people[HOLMES]._imageFrame, _lDrawnPos);
+
+ 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);
+ }
+
+ if (highlighted) {
+ int xp = (SHERLOCK_SCREEN_WIDTH - screen.stringWidth(name)) / 2;
+ screen.gPrint(Common::Point(xp + 2, 2), BLACK, "%s", name.c_str());
+ screen.gPrint(Common::Point(xp + 1, 1), BLACK, "%s", name.c_str());
+ screen.gPrint(Common::Point(xp, 0), 12, "%s", name.c_str());
+
+ screen.slamArea(xp, 0, width + 2, 15);
+ }
+}
+
+void ScalpelMap::updateMap(bool flushScreen) {
+ Events &events = *_vm->_events;
+ People &people = *_vm->_people;
+ Screen &screen = *_vm->_screen;
+ Common::Point osPos = _savedPos;
+ Common::Point osSize = _savedSize;
+ Common::Point hPos;
+
+ if (_cursorIndex >= 1) {
+ if (++_cursorIndex > (1 + 8))
+ _cursorIndex = 1;
+
+ events.setCursor((*_mapCursors)[(_cursorIndex + 1) / 2]._frame);
+ }
+
+ if (!_drawMap && !flushScreen)
+ restoreIcon();
+ else
+ _savedPos.x = -1;
+
+ people[HOLMES].adjustSprite();
+
+ _lDrawnPos.x = hPos.x = people[HOLMES]._position.x / FIXED_INT_MULTIPLIER - _bigPos.x;
+ _lDrawnPos.y = hPos.y = people[HOLMES]._position.y / FIXED_INT_MULTIPLIER - people[HOLMES].frameHeight() - _bigPos.y;
+
+ // Draw the person icon
+ 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);
+ else
+ screen._backBuffer1.transBlitFrom(*people[HOLMES]._imageFrame, hPos, false);
+
+ if (flushScreen) {
+ screen.slamArea(0, 0, SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT);
+ } else if (!_drawMap) {
+ if (hPos.x > 0 && hPos.y >= 0 && hPos.x < SHERLOCK_SCREEN_WIDTH && hPos.y < SHERLOCK_SCREEN_HEIGHT)
+ screen.flushImage(people[HOLMES]._imageFrame, Common::Point(people[HOLMES]._position.x / FIXED_INT_MULTIPLIER - _bigPos.x,
+ people[HOLMES]._position.y / FIXED_INT_MULTIPLIER - people[HOLMES].frameHeight() - _bigPos.y),
+ &people[HOLMES]._oldPosition.x, &people[HOLMES]._oldPosition.y, &people[HOLMES]._oldSize.x, &people[HOLMES]._oldSize.y);
+
+ if (osPos.x != -1)
+ screen.slamArea(osPos.x, osPos.y, osSize.x, osSize.y);
+ }
+}
+
+void ScalpelMap::walkTheStreets() {
+ People &people = *_vm->_people;
+ Common::Array<Common::Point> tempPath;
+
+ // Get indexes into the path lists for the start and destination scenes
+ int start = _points[_oldCharPoint]._translate;
+ int dest = _points[_charPoint]._translate;
+
+ // Get pointer to start of path
+ const byte *path = _paths.getPath(start, dest);
+
+ // Add in destination position
+ people[HOLMES]._walkTo.clear();
+ Common::Point destPos = people[HOLMES]._walkDest;
+
+ // Check for any intermediate points between the two locations
+ if (path[0] || _charPoint > 50 || _oldCharPoint > 50) {
+ people[HOLMES]._sequenceNumber = -1;
+
+ if (_charPoint == 51 || _oldCharPoint == 51) {
+ people[HOLMES].setWalking();
+ } else {
+ bool reversePath = false;
+
+ // Check for moving the path backwards or forwards
+ if (path[0] == 255) {
+ reversePath = true;
+ SWAP(start, dest);
+ path = _paths.getPath(start, dest);
+ }
+
+ do {
+ int idx = *path++;
+ tempPath.push_back(_pathPoints[idx - 1] + Common::Point(4, 4));
+ } while (*path != 254);
+
+ // Load up the path to use
+ people[HOLMES]._walkTo.clear();
+
+ if (reversePath) {
+ for (int idx = (int)tempPath.size() - 1; idx >= 0; --idx)
+ people[HOLMES]._walkTo.push(tempPath[idx]);
+ } else {
+ for (int idx = 0; idx < (int)tempPath.size(); ++idx)
+ people[HOLMES]._walkTo.push(tempPath[idx]);
+ }
+
+ people[HOLMES]._walkDest = people[HOLMES]._walkTo.pop() + Common::Point(12, 6);
+ people[HOLMES].setWalking();
+ }
+ } else {
+ people[HOLMES]._walkCount = 0;
+ }
+
+ // Store the final destination icon position
+ people[HOLMES]._walkTo.push(destPos);
+}
+
+void ScalpelMap::saveIcon(ImageFrame *src, const Common::Point &pt) {
+ Screen &screen = *_vm->_screen;
+ Common::Point size(src->_width, src->_height);
+ Common::Point pos = pt;
+
+ if (pos.x < 0) {
+ size.x += pos.x;
+ pos.x = 0;
+ }
+
+ if (pos.y < 0) {
+ size.y += pos.y;
+ pos.y = 0;
+ }
+
+ if ((pos.x + size.x) > SHERLOCK_SCREEN_WIDTH)
+ size.x -= (pos.x + size.x) - SHERLOCK_SCREEN_WIDTH;
+
+ if ((pos.y + size.y) > SHERLOCK_SCREEN_HEIGHT)
+ size.y -= (pos.y + size.y) - SHERLOCK_SCREEN_HEIGHT;
+
+ if (size.x < 1 || size.y < 1 || pos.x >= SHERLOCK_SCREEN_WIDTH || pos.y >= SHERLOCK_SCREEN_HEIGHT || _drawMap) {
+ // Flag as the area not needing to be saved
+ _savedPos.x = -1;
+ return;
+ }
+
+ assert(size.x <= _iconSave.w() && size.y <= _iconSave.h());
+ _iconSave.blitFrom(screen._backBuffer1, Common::Point(0, 0),
+ Common::Rect(pos.x, pos.y, pos.x + size.x, pos.y + size.y));
+ _savedPos = pos;
+ _savedSize = size;
+}
+
+void ScalpelMap::restoreIcon() {
+ Screen &screen = *_vm->_screen;
+
+ 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));
+}
+
+void ScalpelMap::highlightIcon(const Common::Point &pt) {
+ int oldPoint = _point;
+
+ // Iterate through the icon list
+ bool done = false;
+ for (int idx = 0; idx < (int)_points.size(); ++idx) {
+ const MapEntry &entry = _points[idx];
+
+ // Check whether the mouse is over a given icon
+ if (entry.x != 0 && entry.y != 0) {
+ if (Common::Rect(entry.x - 8, entry.y - 8, entry.x + 9, entry.y + 9).contains(pt)) {
+ done = true;
+
+ if (_point != idx && _vm->readFlags(idx)) {
+ // Changed to a new valid (visible) location
+ eraseTopLine();
+ showPlaceName(idx, true);
+ _point = idx;
+ }
+ }
+ }
+ }
+
+ if (!done) {
+ // No icon was highlighted
+ if (_point != -1) {
+ // No longer highlighting previously highlighted icon, so erase it
+ showPlaceName(_point, false);
+ eraseTopLine();
+ }
+
+ _point = -1;
+ } else if (oldPoint != -1 && oldPoint != _point) {
+ showPlaceName(oldPoint, false);
+ eraseTopLine();
+ }
+}
+
+} // End of namespace Scalpel
+
+} // End of namespace Sherlock
diff --git a/engines/sherlock/scalpel/scalpel_map.h b/engines/sherlock/scalpel/scalpel_map.h
new file mode 100644
index 0000000000..b17677725c
--- /dev/null
+++ b/engines/sherlock/scalpel/scalpel_map.h
@@ -0,0 +1,173 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public 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_MAP_H
+#define SHERLOCK_SCALPEL_MAP_H
+
+#include "common/scummsys.h"
+#include "common/array.h"
+#include "common/rect.h"
+#include "common/str-array.h"
+#include "sherlock/surface.h"
+#include "sherlock/map.h"
+#include "sherlock/resources.h"
+
+namespace Sherlock {
+
+class SherlockEngine;
+
+namespace Scalpel {
+
+
+struct MapEntry : Common::Point {
+ int _translate;
+
+ MapEntry() : Common::Point(), _translate(-1) {}
+
+ MapEntry(int posX, int posY, int translate) : Common::Point(posX, posY), _translate(translate) {}
+};
+
+class MapPaths {
+private:
+ int _numLocations;
+ Common::Array< Common::Array<byte> > _paths;
+
+public:
+ MapPaths();
+
+ /**
+ * Load the data for the paths between locations on the map
+ */
+ void load(int numLocations, Common::SeekableReadStream &s);
+
+ /**
+ * Get the path between two locations on the map
+ */
+ const byte *getPath(int srcLocation, int destLocation);
+};
+
+class ScalpelMap: public Map {
+private:
+ Common::Array<MapEntry> _points; // Map locations for each scene
+ Common::StringArray _locationNames;
+ MapPaths _paths;
+ Common::Array<Common::Point> _pathPoints;
+ Common::Point _savedPos;
+ Common::Point _savedSize;
+ Surface _topLine;
+ ImageFile *_mapCursors;
+ ImageFile *_shapes;
+ ImageFile *_iconShapes;
+ WalkSequences _walkSequences;
+ Point32 _lDrawnPos;
+ int _point;
+ bool _placesShown;
+ int _cursorIndex;
+ bool _drawMap;
+ Surface _iconSave;
+protected:
+ /**
+ * Load data needed for the map
+ */
+ void loadData();
+
+ /**
+ * Load and initialize all the sprites that are needed for the map display
+ */
+ void setupSprites();
+
+ /**
+ * Free the sprites and data used by the map
+ */
+ void freeSprites();
+
+ /**
+ * Draws an icon for every place that's currently known
+ */
+ void showPlaces();
+
+ /**
+ * Makes a copy of the top rows of the screen that are used to display location names
+ */
+ void saveTopLine();
+
+ /**
+ * Erases anything shown in the top line by restoring the previously saved original map background
+ */
+ void eraseTopLine();
+
+ /**
+ * Prints the name of the specified icon
+ */
+ void showPlaceName(int idx, bool highlighted);
+
+ /**
+ * Update all on-screen sprites to account for any scrolling of the map
+ */
+ void updateMap(bool flushScreen);
+
+ /**
+ * Handle moving icon for player from their previous location on the map to a destination location
+ */
+ void walkTheStreets();
+
+ /**
+ * Save the area under the player's icon
+ */
+ void saveIcon(ImageFrame *src, const Common::Point &pt);
+
+ /**
+ * Restore the area under the player's icon
+ */
+ void restoreIcon();
+
+ /**
+ * Handles highlighting map icons, showing their names
+ */
+ void highlightIcon(const Common::Point &pt);
+public:
+ ScalpelMap(SherlockEngine *vm);
+ virtual ~ScalpelMap() {}
+
+ const MapEntry &operator[](int idx) { return _points[idx]; }
+
+ /**
+ * Loads the list of points for locations on the map for each scene
+ */
+ void loadPoints(int count, const int *xList, const int *yList, const int *transList);
+
+ /**
+ * Load the sequence data for player icon animations
+ */
+ void loadSequences(int count, const byte *seq);
+
+ /**
+ * Show the map
+ */
+ virtual int show();
+};
+
+} // End of namespace Scalpel
+
+} // End of namespace Sherlock
+
+#endif
diff --git a/engines/sherlock/scalpel/scalpel_people.cpp b/engines/sherlock/scalpel/scalpel_people.cpp
new file mode 100644
index 0000000000..924095cd50
--- /dev/null
+++ b/engines/sherlock/scalpel/scalpel_people.cpp
@@ -0,0 +1,567 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public 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_people.h"
+#include "sherlock/scalpel/scalpel_map.h"
+#include "sherlock/sherlock.h"
+
+namespace Sherlock {
+
+namespace Scalpel {
+
+// Walk speeds
+#define MWALK_SPEED 2
+#define XWALK_SPEED 4
+#define YWALK_SPEED 1
+
+/*----------------------------------------------------------------*/
+
+void ScalpelPerson::adjustSprite() {
+ Map &map = *_vm->_map;
+ People &people = *_vm->_people;
+ Scene &scene = *_vm->_scene;
+ Talk &talk = *_vm->_talk;
+
+ if (_type == INVALID || (_type == CHARACTER && scene._animating))
+ return;
+
+ if (!talk._talkCounter && _type == CHARACTER && _walkCount) {
+ // Handle active movement for the sprite
+ _position += _delta;
+ --_walkCount;
+
+ if (!_walkCount) {
+ // If there any points left for the character to walk to along the
+ // route to a destination, then move to the next point
+ if (!people[HOLMES]._walkTo.empty()) {
+ _walkDest = people[HOLMES]._walkTo.pop();
+ setWalking();
+ } else {
+ gotoStand();
+ }
+ }
+ }
+
+ if (_type == CHARACTER && !map._active) {
+ if ((_position.y / FIXED_INT_MULTIPLIER) > LOWER_LIMIT) {
+ _position.y = LOWER_LIMIT * FIXED_INT_MULTIPLIER;
+ gotoStand();
+ }
+
+ if ((_position.y / FIXED_INT_MULTIPLIER) < UPPER_LIMIT) {
+ _position.y = UPPER_LIMIT * FIXED_INT_MULTIPLIER;
+ gotoStand();
+ }
+
+ if ((_position.x / FIXED_INT_MULTIPLIER) < LEFT_LIMIT) {
+ _position.x = LEFT_LIMIT * FIXED_INT_MULTIPLIER;
+ gotoStand();
+ }
+
+ if ((_position.x / FIXED_INT_MULTIPLIER) > RIGHT_LIMIT) {
+ _position.x = RIGHT_LIMIT * FIXED_INT_MULTIPLIER;
+ gotoStand();
+ }
+ } else if (!map._active) {
+ _position.y = CLIP((int)_position.y, (int)UPPER_LIMIT, (int)LOWER_LIMIT);
+ _position.x = CLIP((int)_position.x, (int)LEFT_LIMIT, (int)RIGHT_LIMIT);
+ }
+
+ if (!map._active || (map._frameChangeFlag = !map._frameChangeFlag))
+ ++_frameNumber;
+
+ if (_frameNumber >= (int)_walkSequences[_sequenceNumber]._sequences.size() ||
+ _walkSequences[_sequenceNumber][_frameNumber] == 0) {
+ switch (_sequenceNumber) {
+ case STOP_UP:
+ case STOP_DOWN:
+ case STOP_LEFT:
+ case STOP_RIGHT:
+ case STOP_UPRIGHT:
+ case STOP_UPLEFT:
+ case STOP_DOWNRIGHT:
+ case STOP_DOWNLEFT:
+ // We're in a stop sequence, so reset back to the last frame, so
+ // the character is shown as standing still
+ --_frameNumber;
+ break;
+
+ default:
+ // Move 1 past the first frame - we need to compensate, since we
+ // already passed the frame increment
+ _frameNumber = 1;
+ break;
+ }
+ }
+
+ // Update the _imageFrame to point to the new frame's image
+ setImageFrame();
+
+ // Check to see if character has entered an exit zone
+ if (!_walkCount && scene._walkedInScene && scene._goToScene == -1) {
+ Common::Rect charRect(_position.x / FIXED_INT_MULTIPLIER - 5, _position.y / FIXED_INT_MULTIPLIER - 2,
+ _position.x / FIXED_INT_MULTIPLIER + 5, _position.y / FIXED_INT_MULTIPLIER + 2);
+ Exit *exit = scene.checkForExit(charRect);
+
+ if (exit) {
+ scene._goToScene = exit->_scene;
+
+ if (exit->_newPosition.x != 0) {
+ people._savedPos = exit->_newPosition;
+
+ if (people._savedPos._facing > 100 && people._savedPos.x < 1)
+ people._savedPos.x = 100;
+ }
+ }
+ }
+}
+
+void ScalpelPerson::gotoStand() {
+ ScalpelMap &map = *(ScalpelMap *)_vm->_map;
+ People &people = *_vm->_people;
+ _walkTo.clear();
+ _walkCount = 0;
+
+ switch (_sequenceNumber) {
+ case Scalpel::WALK_UP:
+ _sequenceNumber = STOP_UP;
+ break;
+ case WALK_DOWN:
+ _sequenceNumber = STOP_DOWN;
+ break;
+ case TALK_LEFT:
+ case WALK_LEFT:
+ _sequenceNumber = STOP_LEFT;
+ break;
+ case TALK_RIGHT:
+ case WALK_RIGHT:
+ _sequenceNumber = STOP_RIGHT;
+ break;
+ case WALK_UPRIGHT:
+ _sequenceNumber = STOP_UPRIGHT;
+ break;
+ case WALK_UPLEFT:
+ _sequenceNumber = STOP_UPLEFT;
+ break;
+ case WALK_DOWNRIGHT:
+ _sequenceNumber = STOP_DOWNRIGHT;
+ break;
+ case WALK_DOWNLEFT:
+ _sequenceNumber = STOP_DOWNLEFT;
+ break;
+ default:
+ break;
+ }
+
+ // Only restart frame at 0 if the sequence number has changed
+ if (_oldWalkSequence != -1 || _sequenceNumber == Scalpel::STOP_UP)
+ _frameNumber = 0;
+
+ if (map._active) {
+ _sequenceNumber = 0;
+ people[HOLMES]._position.x = (map[map._charPoint].x - 6) * FIXED_INT_MULTIPLIER;
+ people[HOLMES]._position.y = (map[map._charPoint].y + 10) * FIXED_INT_MULTIPLIER;
+ }
+
+ _oldWalkSequence = -1;
+ people._allowWalkAbort = true;
+}
+
+void ScalpelPerson::setWalking() {
+ Map &map = *_vm->_map;
+ Scene &scene = *_vm->_scene;
+ int oldDirection, oldFrame;
+ Common::Point speed, delta;
+
+ // Flag that player has now walked in the scene
+ scene._walkedInScene = true;
+
+ // Stop any previous walking, since a new dest is being set
+ _walkCount = 0;
+ oldDirection = _sequenceNumber;
+ oldFrame = _frameNumber;
+
+ // Set speed to use horizontal and vertical movement
+ if (map._active) {
+ speed = Common::Point(MWALK_SPEED, MWALK_SPEED);
+ } else {
+ speed = Common::Point(XWALK_SPEED, YWALK_SPEED);
+ }
+
+ // If the player is already close to the given destination that no
+ // walking is needed, move to the next straight line segment in the
+ // overall walking route, if there is one
+ for (;;) {
+ // Since we want the player to be centered on the destination they
+ // clicked, but characters draw positions start at their left, move
+ // the destination half the character width to draw him centered
+ int temp;
+ if (_walkDest.x >= (temp = _imageFrame->_frame.w / 2))
+ _walkDest.x -= temp;
+
+ delta = Common::Point(
+ ABS(_position.x / FIXED_INT_MULTIPLIER - _walkDest.x),
+ ABS(_position.y / FIXED_INT_MULTIPLIER - _walkDest.y)
+ );
+
+ // If we're ready to move a sufficient distance, that's it. Otherwise,
+ // move onto the next portion of the walk path, if there is one
+ if ((delta.x > 3 || delta.y > 0) || _walkTo.empty())
+ break;
+
+ // Pop next walk segment off the walk route stack
+ _walkDest = _walkTo.pop();
+ }
+
+ // If a sufficient move is being done, then start the move
+ if (delta.x > 3 || delta.y) {
+ // See whether the major movement is horizontal or vertical
+ if (delta.x >= delta.y) {
+ // Set the initial frame sequence for the left and right, as well
+ // as setting the delta x depending on direction
+ if (_walkDest.x < (_position.x / FIXED_INT_MULTIPLIER)) {
+ _sequenceNumber = (map._active ? (int)MAP_LEFT : (int)WALK_LEFT);
+ _delta.x = speed.x * -FIXED_INT_MULTIPLIER;
+ } else {
+ _sequenceNumber = (map._active ? (int)MAP_RIGHT : (int)WALK_RIGHT);
+ _delta.x = speed.x * FIXED_INT_MULTIPLIER;
+ }
+
+ // See if the x delta is too small to be divided by the speed, since
+ // this would cause a divide by zero error
+ if (delta.x >= speed.x) {
+ // Det the delta y
+ _delta.y = (delta.y * FIXED_INT_MULTIPLIER) / (delta.x / speed.x);
+ if (_walkDest.y < (_position.y / FIXED_INT_MULTIPLIER))
+ _delta.y = -_delta.y;
+
+ // Set how many times we should add the delta to the player's position
+ _walkCount = delta.x / speed.x;
+ } else {
+ // The delta x was less than the speed (ie. we're really close to
+ // the destination). So set delta to 0 so the player won't move
+ _delta = Point32(0, 0);
+ _position = Point32(_walkDest.x * FIXED_INT_MULTIPLIER, _walkDest.y * FIXED_INT_MULTIPLIER);
+
+ _walkCount = 1;
+ }
+
+ // See if the sequence needs to be changed for diagonal walking
+ if (_delta.y > 150) {
+ if (!map._active) {
+ switch (_sequenceNumber) {
+ case WALK_LEFT:
+ _sequenceNumber = WALK_DOWNLEFT;
+ break;
+ case WALK_RIGHT:
+ _sequenceNumber = WALK_DOWNRIGHT;
+ break;
+ }
+ }
+ } else if (_delta.y < -150) {
+ if (!map._active) {
+ switch (_sequenceNumber) {
+ case WALK_LEFT:
+ _sequenceNumber = WALK_UPLEFT;
+ break;
+ case WALK_RIGHT:
+ _sequenceNumber = WALK_UPRIGHT;
+ break;
+ }
+ }
+ }
+ } else {
+ // Major movement is vertical, so set the sequence for up and down,
+ // and set the delta Y depending on the direction
+ if (_walkDest.y < (_position.y / FIXED_INT_MULTIPLIER)) {
+ _sequenceNumber = WALK_UP;
+ _delta.y = speed.y * -FIXED_INT_MULTIPLIER;
+ } else {
+ _sequenceNumber = WALK_DOWN;
+ _delta.y = speed.y * FIXED_INT_MULTIPLIER;
+ }
+
+ // If we're on the overhead map, set the sequence so we keep moving
+ // in the same direction
+ if (map._active)
+ _sequenceNumber = (oldDirection == -1) ? MAP_RIGHT : oldDirection;
+
+ // Set the delta x
+ _delta.x = (delta.x * FIXED_INT_MULTIPLIER) / (delta.y / speed.y);
+ if (_walkDest.x < (_position.x / FIXED_INT_MULTIPLIER))
+ _delta.x = -_delta.x;
+
+ _walkCount = delta.y / speed.y;
+ }
+ }
+
+ // See if the new walk sequence is the same as the old. If it's a new one,
+ // we need to reset the frame number to zero so its animation starts at
+ // its beginning. Otherwise, if it's the same sequence, we can leave it
+ // as is, so it keeps the animation going at wherever it was up to
+ if (_sequenceNumber != _oldWalkSequence)
+ _frameNumber = 0;
+ _oldWalkSequence = _sequenceNumber;
+
+ if (!_walkCount)
+ gotoStand();
+
+ // If the sequence is the same as when we started, then Holmes was
+ // standing still and we're trying to re-stand him, so reset Holmes'
+ // rame to the old frame number from before it was reset to 0
+ if (_sequenceNumber == oldDirection)
+ _frameNumber = oldFrame;
+}
+
+void ScalpelPerson::walkToCoords(const Point32 &destPos, int destDir) {
+ Events &events = *_vm->_events;
+ People &people = *_vm->_people;
+ Scene &scene = *_vm->_scene;
+ Talk &talk = *_vm->_talk;
+
+ CursorId oldCursor = events.getCursor();
+ events.setCursor(WAIT);
+
+ _walkDest = Common::Point(destPos.x / FIXED_INT_MULTIPLIER + 10, destPos.y / FIXED_INT_MULTIPLIER);
+ people._allowWalkAbort = true;
+ goAllTheWay();
+
+ // Keep calling doBgAnim until the walk is done
+ do {
+ events.pollEventsAndWait();
+ scene.doBgAnim();
+ } while (!_vm->shouldQuit() && _walkCount);
+
+ if (!talk._talkToAbort) {
+ // Put character exactly on destination position, and set direction
+ _position = destPos;
+ _sequenceNumber = destDir;
+ gotoStand();
+
+ // Draw Holmes facing the new direction
+ scene.doBgAnim();
+
+ if (!talk._talkToAbort)
+ events.setCursor(oldCursor);
+ }
+}
+
+Common::Point ScalpelPerson::getSourcePoint() const {
+ return Common::Point(_position.x / FIXED_INT_MULTIPLIER + frameWidth() / 2,
+ _position.y / FIXED_INT_MULTIPLIER);
+}
+
+void ScalpelPerson::synchronize(Serializer &s) {
+ if (_walkCount)
+ gotoStand();
+
+ s.syncAsSint32LE(_position.x);
+ s.syncAsSint32LE(_position.y);
+}
+
+/*----------------------------------------------------------------*/
+
+ScalpelPeople::ScalpelPeople(SherlockEngine *vm) : People(vm) {
+ _data.push_back(new ScalpelPerson());
+}
+
+void ScalpelPeople::setTalking(int speaker) {
+ Resources &res = *_vm->_res;
+
+ // If no speaker is specified, then we can exit immediately
+ if (speaker == -1)
+ return;
+
+ if (_portraitsOn) {
+ delete _talkPics;
+ Common::String filename = Common::String::format("%s.vgs", _characters[speaker]._portrait);
+ _talkPics = new ImageFile(filename);
+
+ // Load portrait sequences
+ Common::SeekableReadStream *stream = res.load("sequence.txt");
+ stream->seek(speaker * MAX_FRAME);
+
+ int idx = 0;
+ do {
+ _portrait._sequences[idx] = stream->readByte();
+ ++idx;
+ } while (idx < 2 || _portrait._sequences[idx - 2] || _portrait._sequences[idx - 1]);
+
+ delete stream;
+
+ _portrait._maxFrames = idx;
+ _portrait._frameNumber = 0;
+ _portrait._sequenceNumber = 0;
+ _portrait._images = _talkPics;
+ _portrait._imageFrame = &(*_talkPics)[0];
+ _portrait._position = Common::Point(_portraitSide, 10);
+ _portrait._delta = Common::Point(0, 0);
+ _portrait._oldPosition = Common::Point(0, 0);
+ _portrait._goto = Common::Point(0, 0);
+ _portrait._flags = 5;
+ _portrait._status = 0;
+ _portrait._misc = 0;
+ _portrait._allow = 0;
+ _portrait._type = ACTIVE_BG_SHAPE;
+ _portrait._name = " ";
+ _portrait._description = " ";
+ _portrait._examine = " ";
+ _portrait._walkCount = 0;
+
+ if (_holmesFlip || _speakerFlip) {
+ _portrait._flags |= 2;
+
+ _holmesFlip = false;
+ _speakerFlip = false;
+ }
+
+ if (_portraitSide == 20)
+ _portraitSide = 220;
+ else
+ _portraitSide = 20;
+
+ _portraitLoaded = true;
+ }
+}
+
+void ScalpelPeople::synchronize(Serializer &s) {
+ (*this)[HOLMES].synchronize(s);
+ s.syncAsSint16LE(_holmesQuotient);
+ s.syncAsByte(_holmesOn);
+
+ if (s.isLoading()) {
+ _savedPos = _data[HOLMES]->_position;
+ _savedPos._facing = _data[HOLMES]->_sequenceNumber;
+ }
+}
+
+void ScalpelPeople::setTalkSequence(int speaker, int sequenceNum) {
+ People &people = *_vm->_people;
+ Scene &scene = *_vm->_scene;
+
+ // If no speaker is specified, then nothing needs to be done
+ if (speaker == -1)
+ return;
+
+ if (speaker) {
+ int objNum = people.findSpeaker(speaker);
+ if (objNum != -1) {
+ Object &obj = scene._bgShapes[objNum];
+
+ if (obj._seqSize < MAX_TALK_SEQUENCES) {
+ warning("Tried to copy too many talk frames");
+ } else {
+ for (int idx = 0; idx < MAX_TALK_SEQUENCES; ++idx) {
+ obj._sequences[idx] = people._characters[speaker]._talkSequences[idx];
+ if (idx > 0 && !obj._sequences[idx] && !obj._sequences[idx - 1])
+ return;
+
+ obj._frameNumber = 0;
+ obj._sequenceNumber = 0;
+ }
+ }
+ }
+ }
+}
+
+bool ScalpelPeople::loadWalk() {
+ bool result = false;
+
+ if (_data[HOLMES]->_walkLoaded) {
+ return false;
+ } else {
+ if (!IS_3DO) {
+ _data[HOLMES]->_images = new ImageFile("walk.vgs");
+ } else {
+ // Load walk.anim on 3DO, which is a cel animation file
+ _data[HOLMES]->_images = new ImageFile3DO("walk.anim", kImageFile3DOType_CelAnimation);
+ }
+ _data[HOLMES]->setImageFrame();
+ _data[HOLMES]->_walkLoaded = true;
+
+ result = true;
+ }
+
+ _forceWalkReload = false;
+ return result;
+}
+
+const Common::Point ScalpelPeople::restrictToZone(int zoneId, const Common::Point &destPos) {
+ Scene &scene = *_vm->_scene;
+ Common::Point walkDest = destPos;
+
+ // The destination isn't in a zone
+ if (walkDest.x >= (SHERLOCK_SCREEN_WIDTH - 1))
+ walkDest.x = SHERLOCK_SCREEN_WIDTH - 2;
+
+ // Trace a line between the centroid of the found closest zone to
+ // the destination, to find the point at which the zone will be left
+ const Common::Rect &destRect = scene._zones[zoneId];
+ const Common::Point destCenter((destRect.left + destRect.right) / 2,
+ (destRect.top + destRect.bottom) / 2);
+ const Common::Point delta = walkDest - destCenter;
+ Point32 pt(destCenter.x * FIXED_INT_MULTIPLIER, destCenter.y * FIXED_INT_MULTIPLIER);
+
+ // Move along the line until the zone is left
+ do {
+ pt += delta;
+ } while (destRect.contains(pt.x / FIXED_INT_MULTIPLIER, pt.y / FIXED_INT_MULTIPLIER));
+
+ // Set the new walk destination to the last point that was in the
+ // zone just before it was left
+ return Common::Point((pt.x - delta.x * 2) / FIXED_INT_MULTIPLIER,
+ (pt.y - delta.y * 2) / FIXED_INT_MULTIPLIER);
+}
+
+void ScalpelPeople::setListenSequence(int speaker, int sequenceNum) {
+ People &people = *_vm->_people;
+ Scene &scene = *_vm->_scene;
+
+ // Don't bother doing anything if no specific speaker is specified
+ if (speaker == -1)
+ return;
+
+ if (speaker) {
+ int objNum = people.findSpeaker(speaker);
+ if (objNum != -1) {
+ Object &obj = scene._bgShapes[objNum];
+
+ if (obj._seqSize < MAX_TALK_SEQUENCES) {
+ warning("Tried to copy too few still frames");
+ } else {
+ for (uint idx = 0; idx < MAX_TALK_SEQUENCES; ++idx) {
+ obj._sequences[idx] = people._characters[speaker]._stillSequences[idx];
+ if (idx > 0 && !people._characters[speaker]._talkSequences[idx] &&
+ !people._characters[speaker]._talkSequences[idx - 1])
+ break;
+ }
+
+ obj._frameNumber = 0;
+ obj._seqTo = 0;
+ }
+ }
+ }
+}
+
+} // End of namespace Scalpel
+
+} // End of namespace Sherlock
diff --git a/engines/sherlock/scalpel/scalpel_people.h b/engines/sherlock/scalpel/scalpel_people.h
new file mode 100644
index 0000000000..2ab6f5bc7d
--- /dev/null
+++ b/engines/sherlock/scalpel/scalpel_people.h
@@ -0,0 +1,130 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public 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_PEOPLE_H
+#define SHERLOCK_SCALPEL_PEOPLE_H
+
+#include "common/scummsys.h"
+#include "sherlock/people.h"
+
+namespace Sherlock {
+
+class SherlockEngine;
+
+namespace Scalpel {
+
+// Animation sequence identifiers for characters
+enum ScalpelSequences {
+ WALK_RIGHT = 0, WALK_DOWN = 1, WALK_LEFT = 2, WALK_UP = 3, STOP_LEFT = 4,
+ STOP_DOWN = 5, STOP_RIGHT = 6, STOP_UP = 7, WALK_UPRIGHT = 8,
+ WALK_DOWNRIGHT = 9, WALK_UPLEFT = 10, WALK_DOWNLEFT = 11,
+ STOP_UPRIGHT = 12, STOP_UPLEFT = 13, STOP_DOWNRIGHT = 14,
+ STOP_DOWNLEFT = 15, TALK_RIGHT = 6, TALK_LEFT = 4
+};
+
+class ScalpelPerson : public Person {
+public:
+ ScalpelPerson() : Person() {}
+ virtual ~ScalpelPerson() {}
+
+ /**
+ * Synchronize the data for a savegame
+ */
+ virtual void synchronize(Serializer &s);
+
+ /**
+ * This adjusts the sprites position, as well as its animation sequence:
+ */
+ virtual void adjustSprite();
+
+ /**
+ * Bring a moving character to a standing position
+ */
+ virtual void gotoStand();
+
+ /**
+ * Set the variables for moving a character from one poisition to another
+ * in a straight line
+ */
+ virtual void setWalking();
+
+ /**
+ * Walk to the co-ordinates passed, and then face the given direction
+ */
+ virtual void walkToCoords(const Point32 &destPos, int destDir);
+
+ /**
+ * Get the source position for a character potentially affected by scaling
+ */
+ virtual Common::Point getSourcePoint() const;
+};
+
+class ScalpelPeople : public People {
+public:
+ ScalpelPeople(SherlockEngine *vm);
+ virtual ~ScalpelPeople() {}
+
+ ScalpelPerson &operator[](PeopleId id) { return *(ScalpelPerson *)_data[id]; }
+ ScalpelPerson &operator[](int idx) { return *(ScalpelPerson *)_data[idx]; }
+
+ /**
+ * Setup the data for an animating speaker portrait at the top of the screen
+ */
+ void setTalking(int speaker);
+
+ /**
+ * Synchronize the data for a savegame
+ */
+ virtual void synchronize(Serializer &s);
+
+ /**
+ * Change the sequence of the scene background object associated with the specified speaker.
+ */
+ virtual void setTalkSequence(int speaker, int sequenceNum = 1);
+
+ /**
+ * Restrict passed point to zone using Sherlock's positioning rules
+ */
+ virtual const Common::Point restrictToZone(int zoneId, const Common::Point &destPos);
+
+ /**
+ * Load the walking images for Sherlock
+ */
+ virtual bool loadWalk();
+
+ /**
+ * If the specified speaker is a background object, it will set it so that it uses
+ * the Listen Sequence (specified by the sequence number). If the current sequence
+ * has an Allow Talk Code in it, the _gotoSeq field will be set so that the object
+ * begins listening as soon as it hits the Allow Talk Code. If there is no Abort Code,
+ * the Listen Sequence will begin immediately.
+ * @param speaker Who is speaking
+ * @param sequenceNum Which listen sequence to use
+ */
+ virtual void setListenSequence(int speaker, int sequenceNum = 1);
+};
+
+} // End of namespace Scalpel
+
+} // End of namespace Sherlock
+
+#endif
diff --git a/engines/sherlock/scalpel/scalpel_saveload.cpp b/engines/sherlock/scalpel/scalpel_saveload.cpp
new file mode 100644
index 0000000000..01ba149813
--- /dev/null
+++ b/engines/sherlock/scalpel/scalpel_saveload.cpp
@@ -0,0 +1,261 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public 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_saveload.h"
+#include "sherlock/scalpel/scalpel_screen.h"
+#include "sherlock/scalpel/scalpel.h"
+
+namespace Sherlock {
+
+namespace Scalpel {
+
+const int ENV_POINTS[6][3] = {
+ { 41, 80, 61 }, // Exit
+ { 81, 120, 101 }, // Load
+ { 121, 160, 141 }, // Save
+ { 161, 200, 181 }, // Up
+ { 201, 240, 221 }, // Down
+ { 241, 280, 261 } // Quit
+};
+
+/*----------------------------------------------------------------*/
+
+ScalpelSaveManager::ScalpelSaveManager(SherlockEngine *vm, const Common::String &target) : SaveManager(vm, target) {
+}
+
+void ScalpelSaveManager::drawInterface() {
+ ScalpelScreen &screen = *(ScalpelScreen *)_vm->_screen;
+ UserInterface &ui = *_vm->_ui;
+
+ // Create a list of savegame slots
+ createSavegameList();
+
+ screen._backBuffer1.fillRect(Common::Rect(0, CONTROLS_Y, SHERLOCK_SCREEN_WIDTH, CONTROLS_Y + 10), BORDER_COLOR);
+ screen._backBuffer1.fillRect(Common::Rect(0, CONTROLS_Y + 10, 2, SHERLOCK_SCREEN_HEIGHT), BORDER_COLOR);
+ screen._backBuffer1.fillRect(Common::Rect(318, CONTROLS_Y + 10, SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT), BORDER_COLOR);
+ screen._backBuffer1.fillRect(Common::Rect(0, 199, SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT), BORDER_COLOR);
+ 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");
+ 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");
+ 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");
+ 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");
+ 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");
+ 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");
+
+ if (!_savegameIndex)
+ screen.buttonPrint(Common::Point(ENV_POINTS[3][2], CONTROLS_Y), COMMAND_NULL, 0, "Up");
+
+ if (_savegameIndex == MAX_SAVEGAME_SLOTS - ONSCREEN_FILES_COUNT)
+ screen.buttonPrint(Common::Point(ENV_POINTS[4][2], CONTROLS_Y), COMMAND_NULL, 0, "Down");
+
+ for (int idx = _savegameIndex; idx < _savegameIndex + ONSCREEN_FILES_COUNT; ++idx) {
+ screen.gPrint(Common::Point(6, CONTROLS_Y + 11 + (idx - _savegameIndex) * 10),
+ INV_FOREGROUND, "%d.", idx + 1);
+ screen.gPrint(Common::Point(24, CONTROLS_Y + 11 + (idx - _savegameIndex) * 10),
+ INV_FOREGROUND, "%s", _savegames[idx].c_str());
+ }
+
+ if (!ui._slideWindows) {
+ screen.slamRect(Common::Rect(0, CONTROLS_Y, SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT));
+ } else {
+ ui.summonWindow();
+ }
+
+ _envMode = SAVEMODE_NONE;
+}
+
+int ScalpelSaveManager::getHighlightedButton() const {
+ Common::Point pt = _vm->_events->mousePos();
+
+ for (int idx = 0; idx < 6; ++idx) {
+ if (pt.x > ENV_POINTS[idx][0] && pt.x < ENV_POINTS[idx][1] && pt.y > CONTROLS_Y
+ && pt.y < (CONTROLS_Y + 10))
+ return idx;
+ }
+
+ return -1;
+}
+
+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");
+
+ if ((btnIndex == 1) || ((_envMode == SAVEMODE_LOAD) && (btnIndex != 2)))
+ screen.buttonPrint(Common::Point(ENV_POINTS[1][2], CONTROLS_Y), COMMAND_HIGHLIGHTED, true, "Load");
+ else
+ screen.buttonPrint(Common::Point(ENV_POINTS[1][2], CONTROLS_Y), COMMAND_FOREGROUND, true, "Load");
+
+ if ((btnIndex == 2) || ((_envMode == SAVEMODE_SAVE) && (btnIndex != 1)))
+ screen.buttonPrint(Common::Point(ENV_POINTS[2][2], CONTROLS_Y), COMMAND_HIGHLIGHTED, true, "Save");
+ else
+ screen.buttonPrint(Common::Point(ENV_POINTS[2][2], CONTROLS_Y), COMMAND_FOREGROUND, true, "Save");
+
+ if (btnIndex == 3 && _savegameIndex)
+ screen.buttonPrint(Common::Point(ENV_POINTS[3][2], CONTROLS_Y), COMMAND_HIGHLIGHTED, true, "Up");
+ else
+ if (_savegameIndex)
+ screen.buttonPrint(Common::Point(ENV_POINTS[3][2], CONTROLS_Y), COMMAND_FOREGROUND, true, "Up");
+
+ if ((btnIndex == 4) && (_savegameIndex < MAX_SAVEGAME_SLOTS - 5))
+ screen.buttonPrint(Common::Point(ENV_POINTS[4][2], CONTROLS_Y), COMMAND_HIGHLIGHTED, true, "Down");
+ else if (_savegameIndex < (MAX_SAVEGAME_SLOTS - 5))
+ screen.buttonPrint(Common::Point(ENV_POINTS[4][2], CONTROLS_Y), COMMAND_FOREGROUND, true, "Down");
+
+ color = (btnIndex == 5) ? COMMAND_HIGHLIGHTED : COMMAND_FOREGROUND;
+ screen.buttonPrint(Common::Point(ENV_POINTS[5][2], CONTROLS_Y), color, 1, "Quit");
+}
+
+bool ScalpelSaveManager::checkGameOnScreen(int slot) {
+ ScalpelScreen &screen = *(ScalpelScreen *)_vm->_screen;
+
+ // Check if it's already on-screen
+ if (slot != -1 && (slot < _savegameIndex || slot >= (_savegameIndex + ONSCREEN_FILES_COUNT))) {
+ _savegameIndex = slot;
+
+ screen._backBuffer1.fillRect(Common::Rect(3, CONTROLS_Y + 11, SHERLOCK_SCREEN_WIDTH - 2,
+ SHERLOCK_SCREEN_HEIGHT - 1), INV_BACKGROUND);
+
+ for (int idx = _savegameIndex; idx < (_savegameIndex + 5); ++idx) {
+ screen.gPrint(Common::Point(6, CONTROLS_Y + 11 + (idx - _savegameIndex) * 10),
+ INV_FOREGROUND, "%d.", idx + 1);
+ screen.gPrint(Common::Point(24, CONTROLS_Y + 11 + (idx - _savegameIndex) * 10),
+ INV_FOREGROUND, "%s", _savegames[idx].c_str());
+ }
+
+ 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");
+
+ color = (_savegameIndex == (MAX_SAVEGAME_SLOTS - 5)) ? COMMAND_NULL : COMMAND_FOREGROUND;
+ screen.buttonPrint(Common::Point(ENV_POINTS[4][2], CONTROLS_Y), color, 1, "Down");
+
+ return true;
+ }
+
+ return false;
+}
+
+bool ScalpelSaveManager::promptForDescription(int slot) {
+ Events &events = *_vm->_events;
+ Scene &scene = *_vm->_scene;
+ ScalpelScreen &screen = *(ScalpelScreen *)_vm->_screen;
+ Talk &talk = *_vm->_talk;
+ 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");
+
+ Common::String saveName = _savegames[slot];
+ if (isSlotEmpty(slot)) {
+ // It's an empty slot, so start off with an empty save name
+ saveName = "";
+
+ yp = CONTROLS_Y + 12 + (slot - _savegameIndex) * 10;
+ screen.vgaBar(Common::Rect(24, yp, 85, yp + 9), INV_BACKGROUND);
+ }
+
+ screen.print(Common::Point(6, CONTROLS_Y + 12 + (slot - _savegameIndex) * 10), TALK_FOREGROUND, "%d.", slot + 1);
+ screen.print(Common::Point(24, CONTROLS_Y + 12 + (slot - _savegameIndex) * 10), TALK_FOREGROUND, "%s", saveName.c_str());
+ xp = 24 + screen.stringWidth(saveName);
+ yp = CONTROLS_Y + 12 + (slot - _savegameIndex) * 10;
+
+ int done = 0;
+ do {
+ while (!_vm->shouldQuit() && !events.kbHit()) {
+ scene.doBgAnim();
+
+ if (talk._talkToAbort)
+ return false;
+
+ // Allow event processing
+ events.pollEventsAndWait();
+ events.setButtonState();
+
+ flag = !flag;
+ if (flag)
+ screen.vgaBar(Common::Rect(xp, yp - 1, xp + 8, yp + 9), INV_FOREGROUND);
+ else
+ screen.vgaBar(Common::Rect(xp, yp - 1, xp + 8, yp + 9), INV_BACKGROUND);
+ }
+ if (_vm->shouldQuit())
+ return false;
+
+ // Get the next keypress
+ Common::KeyState keyState = events.getKey();
+
+ if (keyState.keycode == Common::KEYCODE_BACKSPACE && saveName.size() > 0) {
+ // Delete character of save name
+ screen.vgaBar(Common::Rect(xp - screen.charWidth(saveName.lastChar()), yp - 1,
+ xp + 8, yp + 9), INV_BACKGROUND);
+ xp -= screen.charWidth(saveName.lastChar());
+ screen.vgaBar(Common::Rect(xp, yp - 1, xp + 8, yp + 9), INV_FOREGROUND);
+ saveName.deleteLastChar();
+
+ } else if (keyState.keycode == Common::KEYCODE_RETURN && saveName.compareToIgnoreCase(EMPTY_SAVEGAME_SLOT)) {
+ done = 1;
+
+ } else if (keyState.keycode == Common::KEYCODE_ESCAPE) {
+ screen.vgaBar(Common::Rect(xp, yp - 1, xp + 8, yp + 9), INV_BACKGROUND);
+ done = -1;
+
+ } else if (keyState.ascii >= ' ' && keyState.ascii <= 'z' && saveName.size() < 50
+ && (xp + screen.charWidth(keyState.ascii)) < 308) {
+ char c = (char)keyState.ascii;
+
+ screen.vgaBar(Common::Rect(xp, yp - 1, xp + 8, yp + 9), INV_BACKGROUND);
+ screen.print(Common::Point(xp, yp), TALK_FOREGROUND, "%c", c);
+ xp += screen.charWidth(c);
+ screen.vgaBar(Common::Rect(xp, yp - 1, xp + 8, yp + 9), INV_FOREGROUND);
+ saveName += c;
+ }
+ } while (!done);
+
+ if (done == 1) {
+ // Enter key perssed
+ _savegames[slot] = saveName;
+ } else {
+ done = 0;
+ _envMode = SAVEMODE_NONE;
+ highlightButtons(-1);
+ }
+
+ return done == 1;
+}
+
+} // End of namespace Scalpel
+
+} // End of namespace Sherlock
diff --git a/engines/sherlock/scalpel/scalpel_saveload.h b/engines/sherlock/scalpel/scalpel_saveload.h
new file mode 100644
index 0000000000..6b035cace3
--- /dev/null
+++ b/engines/sherlock/scalpel/scalpel_saveload.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 SHERLOCK_SCALPEL_SAVELOAD_H
+#define SHERLOCK_SCALPEL_SAVELOAD_H
+
+#include "sherlock/saveload.h"
+
+namespace Sherlock {
+
+namespace Scalpel {
+
+extern const int ENV_POINTS[6][3];
+
+class ScalpelSaveManager: public SaveManager {
+public:
+ SaveMode _envMode;
+public:
+ ScalpelSaveManager(SherlockEngine *vm, const Common::String &target);
+ virtual ~ScalpelSaveManager() {}
+
+ /**
+ * Shows the in-game dialog interface for loading and saving games
+ */
+ void drawInterface();
+
+ /**
+ * Return the index of the button the mouse is over, if any
+ */
+ int getHighlightedButton() const;
+
+ /**
+ * Handle highlighting buttons
+ */
+ void highlightButtons(int btnIndex);
+
+ /**
+ * Make sure that the selected savegame is on-screen
+ */
+ bool checkGameOnScreen(int slot);
+
+ /**
+ * Prompts the user to enter a description in a given slot
+ */
+ bool promptForDescription(int slot);
+};
+
+} // End of namespace Scalpel
+
+} // End of namespace Sherlock
+
+#endif
diff --git a/engines/sherlock/scalpel/scalpel_scene.cpp b/engines/sherlock/scalpel/scalpel_scene.cpp
index b6a42419d8..b2c7339363 100644
--- a/engines/sherlock/scalpel/scalpel_scene.cpp
+++ b/engines/sherlock/scalpel/scalpel_scene.cpp
@@ -21,18 +21,130 @@
*/
#include "sherlock/scalpel/scalpel_scene.h"
+#include "sherlock/scalpel/scalpel_map.h"
+#include "sherlock/scalpel/scalpel_people.h"
+#include "sherlock/scalpel/scalpel_user_interface.h"
#include "sherlock/scalpel/scalpel.h"
#include "sherlock/events.h"
#include "sherlock/people.h"
#include "sherlock/screen.h"
+#include "sherlock/sherlock.h"
namespace Sherlock {
namespace Scalpel {
+const int FS_TRANS[8] = {
+ STOP_UP, STOP_UPRIGHT, STOP_RIGHT, STOP_DOWNRIGHT, STOP_DOWN, STOP_DOWNLEFT, STOP_LEFT, STOP_UPLEFT
+};
+
+/*----------------------------------------------------------------*/
+
+bool ScalpelScene::loadScene(const Common::String &filename) {
+ ScalpelMap &map = *(ScalpelMap *)_vm->_map;
+ bool result = Scene::loadScene(filename);
+
+ if (!_vm->isDemo()) {
+ // Reset the previous map location and position on overhead map
+ map._oldCharPoint = _currentScene;
+
+ map._overPos.x = (map[_currentScene].x - 6) * FIXED_INT_MULTIPLIER;
+ map._overPos.y = (map[_currentScene].y + 9) * FIXED_INT_MULTIPLIER;
+
+ }
+
+ return result;
+}
+
+void ScalpelScene::drawAllShapes() {
+ People &people = *_vm->_people;
+ Screen &screen = *_vm->_screen;
+
+ // Restrict drawing window
+ screen.setDisplayBounds(Common::Rect(0, 0, SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCENE_HEIGHT));
+
+ // 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);
+ }
+
+ // 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);
+ }
+
+ // 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);
+ }
+
+ // 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);
+ }
+
+ // Draw any active characters
+ for (int idx = 0; idx < MAX_CHARACTERS; ++idx) {
+ Person &p = people[idx];
+ if (p._type == CHARACTER && p._walkLoaded) {
+ bool flipped = IS_SERRATED_SCALPEL && (
+ p._sequenceNumber == WALK_LEFT || p._sequenceNumber == STOP_LEFT ||
+ 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,
+ p._position.y / FIXED_INT_MULTIPLIER - p.frameHeight()), flipped);
+ }
+ }
+
+ // Draw all static and active shapes that are NORMAL and are in front of the player
+ 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,
+ _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);
+ }
+
+ // Draw all static and active shapes that are FORWARD
+ for (uint idx = 0; idx < _bgShapes.size(); ++idx) {
+ _bgShapes[idx]._oldPosition = _bgShapes[idx]._position;
+ _bgShapes[idx]._oldSize = Common::Point(_bgShapes[idx].frameWidth(),
+ _bgShapes[idx].frameHeight());
+
+ 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,
+ _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);
+ }
+
+ screen.resetDisplayBounds();
+}
+
void ScalpelScene::checkBgShapes() {
People &people = *_vm->_people;
- Person &holmes = people._player;
+ Person &holmes = people[HOLMES];
Common::Point pt(holmes._position.x / FIXED_INT_MULTIPLIER, holmes._position.y / FIXED_INT_MULTIPLIER);
// Call the base scene method to handle bg shapes
@@ -57,9 +169,9 @@ void ScalpelScene::checkBgShapes() {
void ScalpelScene::doBgAnimCheckCursor() {
Inventory &inv = *_vm->_inventory;
Events &events = *_vm->_events;
- Sound &sound = *_vm->_sound;
UserInterface &ui = *_vm->_ui;
Common::Point mousePos = events.mousePos();
+ events.animateCursorIfNeeded();
if (ui._menuMode == LOOK_MODE) {
if (mousePos.y > CONTROLS_Y1)
@@ -80,11 +192,6 @@ void ScalpelScene::doBgAnimCheckCursor() {
events.setCursor(ARROW);
}
}
-
- if (sound._diskSoundPlaying && !*sound._soundIsOn) {
- // Loaded sound just finished playing
- sound.freeDigiSound();
- }
}
void ScalpelScene::doBgAnim() {
@@ -94,6 +201,8 @@ void ScalpelScene::doBgAnim() {
Screen &screen = *_vm->_screen;
Talk &talk = *_vm->_talk;
+ doBgAnimCheckCursor();
+
screen.setDisplayBounds(Common::Rect(0, 0, SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCENE_HEIGHT));
talk._talkToAbort = false;
@@ -116,18 +225,18 @@ void ScalpelScene::doBgAnim() {
_canimShapes[idx].checkObject();
}
- if (_currentScene == 12)
- vm.eraseMirror12();
+ if (_currentScene == DRAWING_ROOM)
+ vm.eraseBrumwellMirror();
// Restore the back buffer from the back buffer 2 in the changed area
- Common::Rect bounds(people[AL]._oldPosition.x, people[AL]._oldPosition.y,
- people[AL]._oldPosition.x + people[AL]._oldSize.x,
- people[AL]._oldPosition.y + people[AL]._oldSize.y);
+ Common::Rect bounds(people[HOLMES]._oldPosition.x, people[HOLMES]._oldPosition.y,
+ people[HOLMES]._oldPosition.x + people[HOLMES]._oldSize.x,
+ people[HOLMES]._oldPosition.y + people[HOLMES]._oldSize.y);
Common::Point pt(bounds.left, bounds.top);
- if (people[AL]._type == CHARACTER)
+ if (people[HOLMES]._type == CHARACTER)
screen.restoreBackground(bounds);
- else if (people[AL]._type == REMOVE)
+ else if (people[HOLMES]._type == REMOVE)
screen._backBuffer->blitFrom(screen._backBuffer2, pt, bounds);
for (uint idx = 0; idx < _bgShapes.size(); ++idx) {
@@ -182,14 +291,14 @@ void ScalpelScene::doBgAnim() {
_canimShapes[idx].adjustObject();
}
- if (people[AL]._type == CHARACTER && people._holmesOn)
- people[AL].adjustSprite();
+ if (people[HOLMES]._type == CHARACTER && people._holmesOn)
+ people[HOLMES].adjustSprite();
// Flag the bg shapes which need to be redrawn
checkBgShapes();
- if (_currentScene == 12)
- vm.doMirror12();
+ if (_currentScene == DRAWING_ROOM)
+ vm.doBrumwellMirror();
// Draw all active shapes which are behind the person
for (uint idx = 0; idx < _bgShapes.size(); ++idx) {
@@ -222,16 +331,16 @@ void ScalpelScene::doBgAnim() {
}
// Draw the person if not animating
- if (people[AL]._type == CHARACTER && people[AL]._walkLoaded) {
+ if (people[HOLMES]._type == CHARACTER && people[HOLMES]._walkLoaded) {
// If Holmes is too far to the right, move him back so he's on-screen
- int xRight = SHERLOCK_SCREEN_WIDTH - 2 - people[AL]._imageFrame->_frame.w;
- int tempX = MIN(people[AL]._position.x / FIXED_INT_MULTIPLIER, xRight);
-
- bool flipped = people[AL]._sequenceNumber == WALK_LEFT || people[AL]._sequenceNumber == STOP_LEFT ||
- people[AL]._sequenceNumber == WALK_UPLEFT || people[AL]._sequenceNumber == STOP_UPLEFT ||
- people[AL]._sequenceNumber == WALK_DOWNRIGHT || people[AL]._sequenceNumber == STOP_DOWNRIGHT;
- screen._backBuffer->transBlitFrom(*people[AL]._imageFrame,
- Common::Point(tempX, people[AL]._position.y / FIXED_INT_MULTIPLIER - people[AL]._imageFrame->_frame.h), flipped);
+ int xRight = SHERLOCK_SCREEN_WIDTH - 2 - people[HOLMES]._imageFrame->_frame.w;
+ int tempX = MIN(people[HOLMES]._position.x / FIXED_INT_MULTIPLIER, xRight);
+
+ 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,
+ Common::Point(tempX, people[HOLMES]._position.y / FIXED_INT_MULTIPLIER - people[HOLMES]._imageFrame->_frame.h), flipped);
}
// Draw all static and active shapes are NORMAL and are in front of the person
@@ -281,25 +390,25 @@ void ScalpelScene::doBgAnim() {
_animating = 0;
screen.slamRect(Common::Rect(0, 0, SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCENE_HEIGHT));
} else {
- if (people[AL]._type != INVALID && ((_goToScene == -1 || _canimShapes.empty()))) {
- if (people[AL]._type == REMOVE) {
+ if (people[HOLMES]._type != INVALID && ((_goToScene == -1 || _canimShapes.empty()))) {
+ if (people[HOLMES]._type == REMOVE) {
screen.slamRect(Common::Rect(
- people[AL]._oldPosition.x, people[AL]._oldPosition.y,
- people[AL]._oldPosition.x + people[AL]._oldSize.x,
- people[AL]._oldPosition.y + people[AL]._oldSize.y
+ people[HOLMES]._oldPosition.x, people[HOLMES]._oldPosition.y,
+ people[HOLMES]._oldPosition.x + people[HOLMES]._oldSize.x,
+ people[HOLMES]._oldPosition.y + people[HOLMES]._oldSize.y
));
- people[AL]._type = INVALID;
+ people[HOLMES]._type = INVALID;
} else {
- screen.flushImage(people[AL]._imageFrame,
- Common::Point(people[AL]._position.x / FIXED_INT_MULTIPLIER,
- people[AL]._position.y / FIXED_INT_MULTIPLIER - people[AL].frameHeight()),
- &people[AL]._oldPosition.x, &people[AL]._oldPosition.y,
- &people[AL]._oldSize.x, &people[AL]._oldSize.y);
+ screen.flushImage(people[HOLMES]._imageFrame,
+ Common::Point(people[HOLMES]._position.x / FIXED_INT_MULTIPLIER,
+ people[HOLMES]._position.y / FIXED_INT_MULTIPLIER - people[HOLMES].frameHeight()),
+ &people[HOLMES]._oldPosition.x, &people[HOLMES]._oldPosition.y,
+ &people[HOLMES]._oldSize.x, &people[HOLMES]._oldSize.y);
}
}
- if (_currentScene == 12)
- vm.flushMirror12();
+ if (_currentScene == DRAWING_ROOM)
+ vm.flushBrumwellMirror();
for (uint idx = 0; idx < _bgShapes.size(); ++idx) {
Object &o = _bgShapes[idx];
@@ -376,6 +485,262 @@ void ScalpelScene::doBgAnim() {
}
}
+int ScalpelScene::startCAnim(int cAnimNum, int playRate) {
+ Events &events = *_vm->_events;
+ ScalpelMap &map = *(ScalpelMap *)_vm->_map;
+ People &people = *_vm->_people;
+ Resources &res = *_vm->_res;
+ Talk &talk = *_vm->_talk;
+ ScalpelUserInterface &ui = *(ScalpelUserInterface *)_vm->_ui;
+ Point32 tpPos, walkPos;
+ int tpDir, walkDir;
+ int tFrames = 0;
+ int gotoCode = -1;
+
+ // Validation
+ if (cAnimNum >= (int)_cAnim.size())
+ // number out of bounds
+ return -1;
+ if (_canimShapes.size() >= 3 || playRate == 0)
+ // Too many active animations, or invalid play rate
+ return 0;
+
+ CAnim &cAnim = _cAnim[cAnimNum];
+ if (playRate < 0) {
+ // Reverse direction
+ walkPos = cAnim._teleport[0];
+ walkDir = cAnim._teleport[0]._facing;
+ tpPos = cAnim._goto[0];
+ tpDir = cAnim._goto[0]._facing;
+ } else {
+ // Forward direction
+ walkPos = cAnim._goto[0];
+ walkDir = cAnim._goto[0]._facing;
+ tpPos = cAnim._teleport[0];
+ tpDir = cAnim._teleport[0]._facing;
+ }
+
+ CursorId oldCursor = events.getCursor();
+ events.setCursor(WAIT);
+
+ if (walkPos.x != -1) {
+ // Holmes must walk to the walk point before the cAnimation is started
+ if (people[HOLMES]._position != walkPos)
+ people[HOLMES].walkToCoords(walkPos, walkDir);
+ }
+
+ if (talk._talkToAbort)
+ return 1;
+
+ // Add new anim shape entry for displaying the animation
+ _canimShapes.push_back(Object());
+ Object &cObj = _canimShapes[_canimShapes.size() - 1];
+
+ // 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
+
+ // 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;
+
+ if (cAnim._name.size() > 0 && cAnim._type != NO_SHAPE) {
+ if (tpPos.x != -1)
+ people[HOLMES]._type = REMOVE;
+
+ Common::String fname = cAnim._name + ".vgs";
+ if (!res.isInCache(fname)) {
+ // Set up RRM scene data
+ Common::SeekableReadStream *roomStream = res.load(_roomFilename);
+ roomStream->seek(cAnim._dataOffset);
+ //rrmStream->seek(44 + cAnimNum * 4);
+ //rrmStream->seek(rrmStream->readUint32LE());
+
+ // Load the canimation into the cache
+ Common::SeekableReadStream *imgStream = !_compressed ? roomStream->readStream(cAnim._dataSize) :
+ Resources::decompressLZ(*roomStream, cAnim._dataSize);
+ res.addToCache(fname, *imgStream);
+
+ delete imgStream;
+ delete roomStream;
+ }
+
+ // Now load the resource as an image
+ if (!IS_3DO) {
+ cObj._images = new ImageFile(fname);
+ } else {
+ cObj._images = new ImageFile3DO(fname, kImageFile3DOType_RoomFormat);
+ }
+ 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])
+ ++frames;
+ } else {
+ // Forward direction
+ BaseObject::_countCAnimFrames = true;
+
+ while (cObj._type == ACTIVE_BG_SHAPE) {
+ cObj.checkObject();
+ ++frames;
+
+ if (frames >= 1000)
+ error("CAnim has infinite loop sequence");
+ }
+
+ if (frames > 1)
+ --frames;
+
+ BaseObject::_countCAnimFrames = false;
+
+ 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
+ if (frames == 0)
+ return -2;
+
+ ++frames;
+ int repeat = ABS(playRate);
+ int dir;
+
+ if (playRate < 0) {
+ // Play in reverse
+ dir = -2;
+ cObj._frameNumber = frames - 3;
+ } else {
+ dir = 0;
+ }
+
+ tFrames = frames - 1;
+ int pauseFrame = (_cAnimFramePause) ? frames - _cAnimFramePause : -1;
+
+ while (--frames) {
+ if (frames == pauseFrame)
+ ui.printObjectDesc();
+
+ doBgAnim();
+
+ // Repeat same frame
+ int temp = repeat;
+ while (--temp > 0) {
+ cObj._frameNumber--;
+ doBgAnim();
+
+ if (_vm->shouldQuit())
+ return 0;
+ }
+
+ cObj._frameNumber += dir;
+ }
+
+ people[HOLMES]._type = CHARACTER;
+ }
+
+ // Teleport to ending coordinates if necessary
+ if (tpPos.x != -1) {
+ people[HOLMES]._position = tpPos; // Place the player
+ people[HOLMES]._sequenceNumber = tpDir;
+ people[HOLMES].gotoStand();
+ }
+
+ if (playRate < 0)
+ // Reverse direction - set to end sequence
+ cObj._frameNumber = tFrames - 1;
+
+ 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();
+
+ if (gotoCode > 0 && !talk._talkToAbort) {
+ _goToScene = gotoCode;
+
+ if (_goToScene < 97 && map[_goToScene].x) {
+ map._overPos = map[_goToScene];
+ }
+ }
+
+ people.loadWalk();
+
+ if (tpPos.x != -1 && !talk._talkToAbort) {
+ // Teleport to ending coordinates
+ people[HOLMES]._position = tpPos;
+ people[HOLMES]._sequenceNumber = tpDir;
+
+ people[HOLMES].gotoStand();
+ }
+
+ events.setCursor(oldCursor);
+
+ return 1;
+}
+
+int ScalpelScene::closestZone(const Common::Point &pt) {
+ int dist = 1000;
+ int zone = -1;
+
+ for (uint idx = 0; idx < _zones.size(); ++idx) {
+ Common::Point zc((_zones[idx].left + _zones[idx].right) / 2,
+ (_zones[idx].top + _zones[idx].bottom) / 2);
+ int d = ABS(zc.x - pt.x) + ABS(zc.y - pt.y);
+
+ if (d < dist) {
+ // Found a closer zone
+ dist = d;
+ zone = idx;
+ }
+ }
+
+ return zone;
+}
+
+int ScalpelScene::findBgShape(const Common::Point &pt) {
+ if (!_doBgAnimDone)
+ // New frame hasn't been drawn yet
+ return -1;
+
+ for (int idx = (int)_bgShapes.size() - 1; idx >= 0; --idx) {
+ Object &o = _bgShapes[idx];
+ if (o._type != INVALID && o._type != NO_SHAPE && o._type != HIDDEN
+ && o._aType <= PERSON) {
+ if (o.getNewBounds().contains(pt))
+ return idx;
+ } else if (o._type == NO_SHAPE) {
+ if (o.getNoShapeBounds().contains(pt))
+ return idx;
+ }
+ }
+
+ return -1;
+}
+
} // End of namespace Scalpel
} // End of namespace Sherlock
diff --git a/engines/sherlock/scalpel/scalpel_scene.h b/engines/sherlock/scalpel/scalpel_scene.h
index e5a442f44f..8fe3b66b38 100644
--- a/engines/sherlock/scalpel/scalpel_scene.h
+++ b/engines/sherlock/scalpel/scalpel_scene.h
@@ -35,16 +35,43 @@ namespace Sherlock {
namespace Scalpel {
+extern const int FS_TRANS[8];
+
+enum { BLACKWOOD_CAPTURE = 2, BAKER_STREET = 4, DRAWING_ROOM = 12, STATION = 17, PUB_INTERIOR = 19,
+ LAWYER_OFFICE = 27, BAKER_ST_EXTERIOR = 39, RESCUE_ANNA = 52, MOOREHEAD_DEATH = 53, EXIT_GAME = 55,
+ BRUMWELL_SUICIDE = 70, OVERHEAD_MAP2 = 98, DARTS_GAME = 99, OVERHEAD_MAP = 100 };
+
class ScalpelScene : public Scene {
private:
void doBgAnimCheckCursor();
protected:
/**
+ * Loads the data associated for a given scene. The room resource file's format is:
+ * BGHEADER: Holds an index for the rest of the file
+ * STRUCTS: The objects for the scene
+ * IMAGES: The graphic information for the structures
+ *
+ * The _misc field of the structures contains the number of the graphic image
+ * that it should point to after loading; _misc is then set to 0.
+ */
+ virtual bool loadScene(const Common::String &filename);
+
+ /**
* Checks all the background shapes. If a background shape is animating,
* it will flag it as needing to be drawn. If a non-animating shape is
* colliding with another shape, it will also flag it as needing drawing
*/
virtual void checkBgShapes();
+
+ /**
+ * Draw all the shapes, people and NPCs in the correct order
+ */
+ virtual void drawAllShapes();
+
+ /**
+ * Returns the index of the closest zone to a given point.
+ */
+ virtual int closestZone(const Common::Point &pt);
public:
ScalpelScene(SherlockEngine *vm) : Scene(vm) {}
@@ -52,6 +79,22 @@ public:
* Draw all objects and characters.
*/
virtual void doBgAnim();
+
+ /**
+ * Attempt to start a canimation sequence. It will load the requisite graphics, and
+ * then copy the canim object into the _canimShapes array to start the animation.
+ *
+ * @param cAnimNum The canim object within the current scene
+ * @param playRate Play rate. 0 is invalid; 1=normal speed, 2=1/2 speed, etc.
+ * A negative playRate can also be specified to play the animation in reverse
+ */
+ virtual int startCAnim(int cAnimNum, int playRate = 1);
+
+ /**
+ * Attempts to find a background shape within the passed bounds. If found,
+ * it will return the shape number, or -1 on failure.
+ */
+ virtual int findBgShape(const Common::Point &pt);
};
} // End of namespace Scalpel
diff --git a/engines/sherlock/scalpel/scalpel_screen.cpp b/engines/sherlock/scalpel/scalpel_screen.cpp
new file mode 100644
index 0000000000..2096dabcdf
--- /dev/null
+++ b/engines/sherlock/scalpel/scalpel_screen.cpp
@@ -0,0 +1,93 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public 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"
+
+namespace Sherlock {
+
+namespace Scalpel {
+
+ScalpelScreen::ScalpelScreen(SherlockEngine *vm) : Screen(vm) {
+}
+
+void ScalpelScreen::makeButton(const Common::Rect &bounds, int textX,
+ const Common::String &str) {
+
+ 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);
+}
+
+void ScalpelScreen::buttonPrint(const Common::Point &pt, byte color, bool slamIt,
+ const Common::String &str) {
+ int xStart = pt.x - stringWidth(str) / 2;
+
+ 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());
+ } 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);
+}
+
+} // End of namespace Scalpel
+
+} // End of namespace Sherlock
diff --git a/engines/sherlock/scalpel/scalpel_screen.h b/engines/sherlock/scalpel/scalpel_screen.h
new file mode 100644
index 0000000000..472fe9e220
--- /dev/null
+++ b/engines/sherlock/scalpel/scalpel_screen.h
@@ -0,0 +1,66 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef SHERLOCK_SCALPEL_SCREEN_H
+#define SHERLOCK_SCALPEL_SCREEN_H
+
+#include "sherlock/screen.h"
+
+namespace Sherlock {
+
+class SherlockEngine;
+
+namespace Scalpel {
+
+class ScalpelScreen : public Screen {
+public:
+ ScalpelScreen(SherlockEngine *vm);
+ virtual ~ScalpelScreen() {}
+
+ /**
+ * Draws a button for use in the inventory, talk, and examine dialogs.
+ */
+ void makeButton(const Common::Rect &bounds, int textX, const Common::String &str);
+
+ /**
+ * Prints an interface command with the first letter highlighted to indicate
+ * what keyboard shortcut is associated with it
+ */
+ void buttonPrint(const Common::Point &pt, byte color, bool slamIt, const Common::String &str);
+
+ /**
+ * Draw a panel in the back buffer with a raised area effect around the edges
+ */
+ void makePanel(const Common::Rect &r);
+
+ /**
+ * Draw a field in the back buffer with a raised area effect around the edges,
+ * suitable for text input.
+ */
+ void makeField(const Common::Rect &r);
+};
+
+} // End of namespace Scalpel
+
+} // End of namespace Sherlock
+
+#endif
diff --git a/engines/sherlock/scalpel/scalpel_talk.cpp b/engines/sherlock/scalpel/scalpel_talk.cpp
new file mode 100644
index 0000000000..2dda817445
--- /dev/null
+++ b/engines/sherlock/scalpel/scalpel_talk.cpp
@@ -0,0 +1,935 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public 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_talk.h"
+#include "sherlock/scalpel/scalpel_fixed_text.h"
+#include "sherlock/scalpel/scalpel_map.h"
+#include "sherlock/scalpel/scalpel_people.h"
+#include "sherlock/scalpel/scalpel_scene.h"
+#include "sherlock/scalpel/scalpel_screen.h"
+#include "sherlock/scalpel/scalpel_user_interface.h"
+#include "sherlock/scalpel/scalpel.h"
+#include "sherlock/screen.h"
+#include "sherlock/scalpel/3do/movie_decoder.h"
+
+namespace Sherlock {
+
+namespace Scalpel {
+
+const byte SCALPEL_OPCODES[] = {
+ 128, // OP_SWITCH_SPEAKER
+ 129, // OP_RUN_CANIMATION
+ 130, // OP_ASSIGN_PORTRAIT_LOCATION
+ 131, // OP_PAUSE
+ 132, // OP_REMOVE_PORTRAIT
+ 133, // OP_CLEAR_WINDOW
+ 134, // OP_ADJUST_OBJ_SEQUENCE
+ 135, // OP_WALK_TO_COORDS
+ 136, // OP_PAUSE_WITHOUT_CONTROL
+ 137, // OP_BANISH_WINDOW
+ 138, // OP_SUMMON_WINDOW
+ 139, // OP_SET_FLAG
+ 140, // OP_SFX_COMMAND
+ 141, // OP_TOGGLE_OBJECT
+ 142, // OP_STEALTH_MODE_ACTIVE
+ 143, // OP_IF_STATEMENT
+ 144, // OP_ELSE_STATEMENT
+ 145, // OP_END_IF_STATEMENT
+ 146, // OP_STEALTH_MODE_DEACTIVATE
+ 147, // OP_TURN_HOLMES_OFF
+ 148, // OP_TURN_HOLMES_ON
+ 149, // OP_GOTO_SCENE
+ 150, // OP_PLAY_PROLOGUE
+ 151, // OP_ADD_ITEM_TO_INVENTORY
+ 152, // OP_SET_OBJECT
+ 153, // OP_CALL_TALK_FILE
+ 143, // OP_MOVE_MOUSE
+ 155, // OP_DISPLAY_INFO_LINE
+ 156, // OP_CLEAR_INFO_LINE
+ 157, // OP_WALK_TO_CANIMATION
+ 158, // OP_REMOVE_ITEM_FROM_INVENTORY
+ 159, // OP_ENABLE_END_KEY
+ 160, // OP_DISABLE_END_KEY
+ 161, // OP_END_TEXT_WINDOW
+ 0, // OP_MOUSE_ON_OFF
+ 0, // OP_SET_WALK_CONTROL
+ 0, // OP_SET_TALK_SEQUENCE
+ 0, // OP_PLAY_SONG
+ 0, // OP_WALK_HOLMES_AND_NPC_TO_CANIM
+ 0, // OP_SET_NPC_PATH_DEST
+ 0, // OP_NEXT_SONG
+ 0, // OP_SET_NPC_PATH_PAUSE
+ 0, // OP_PASSWORD
+ 0, // OP_SET_SCENE_ENTRY_FLAG
+ 0, // OP_WALK_NPC_TO_CANIM
+ 0, // OP_WALK_HOLMES_AND_NPC_TO_COORDS
+ 0, // OP_WALK_HOLMES_AND_NPC_TO_COORDS
+ 0, // OP_SET_NPC_TALK_FILE
+ 0, // OP_TURN_NPC_OFF
+ 0, // OP_TURN_NPC_ON
+ 0, // OP_NPC_DESC_ON_OFF
+ 0, // OP_NPC_PATH_PAUSE_TAKING_NOTES
+ 0, // OP_NPC_PATH_PAUSE_LOOKING_HOLMES
+ 0, // OP_ENABLE_TALK_INTERRUPTS
+ 0, // OP_DISABLE_TALK_INTERRUPTS
+ 0, // OP_SET_NPC_INFO_LINE
+ 0, // OP_SET_NPC_POSITION
+ 0, // OP_NPC_PATH_LABEL
+ 0, // OP_PATH_GOTO_LABEL
+ 0, // OP_PATH_IF_FLAG_GOTO_LABEL
+ 0, // OP_NPC_WALK_GRAPHICS
+ 0, // OP_NPC_VERB
+ 0, // OP_NPC_VERB_CANIM
+ 0, // OP_NPC_VERB_SCRIPT
+ 0, // OP_RESTORE_PEOPLE_SEQUENCE
+ 0, // OP_NPC_VERB_TARGET
+ 0, // OP_TURN_SOUNDS_OFF
+ 0 // OP_NULL
+};
+
+/*----------------------------------------------------------------*/
+
+ScalpelTalk::ScalpelTalk(SherlockEngine *vm) : Talk(vm) {
+ static OpcodeMethod OPCODE_METHODS[] = {
+ (OpcodeMethod)&ScalpelTalk::cmdSwitchSpeaker,
+ (OpcodeMethod)&ScalpelTalk::cmdRunCAnimation,
+ (OpcodeMethod)&ScalpelTalk::cmdAssignPortraitLocation,
+
+ (OpcodeMethod)&ScalpelTalk::cmdPause,
+ (OpcodeMethod)&ScalpelTalk::cmdRemovePortrait,
+ (OpcodeMethod)&ScalpelTalk::cmdClearWindow,
+ (OpcodeMethod)&ScalpelTalk::cmdAdjustObjectSequence,
+ (OpcodeMethod)&ScalpelTalk::cmdWalkToCoords,
+ (OpcodeMethod)&ScalpelTalk::cmdPauseWithoutControl,
+ (OpcodeMethod)&ScalpelTalk::cmdBanishWindow,
+ (OpcodeMethod)&ScalpelTalk::cmdSummonWindow,
+ (OpcodeMethod)&ScalpelTalk::cmdSetFlag,
+ (OpcodeMethod)&ScalpelTalk::cmdSfxCommand,
+
+ (OpcodeMethod)&ScalpelTalk::cmdToggleObject,
+ (OpcodeMethod)&ScalpelTalk::cmdStealthModeActivate,
+ (OpcodeMethod)&ScalpelTalk::cmdIf,
+ (OpcodeMethod)&ScalpelTalk::cmdElse,
+ nullptr,
+ (OpcodeMethod)&ScalpelTalk::cmdStealthModeDeactivate,
+ (OpcodeMethod)&ScalpelTalk::cmdHolmesOff,
+ (OpcodeMethod)&ScalpelTalk::cmdHolmesOn,
+ (OpcodeMethod)&ScalpelTalk::cmdGotoScene,
+ (OpcodeMethod)&ScalpelTalk::cmdPlayPrologue,
+
+ (OpcodeMethod)&ScalpelTalk::cmdAddItemToInventory,
+ (OpcodeMethod)&ScalpelTalk::cmdSetObject,
+ (OpcodeMethod)&ScalpelTalk::cmdCallTalkFile,
+ (OpcodeMethod)&ScalpelTalk::cmdMoveMouse,
+ (OpcodeMethod)&ScalpelTalk::cmdDisplayInfoLine,
+ (OpcodeMethod)&ScalpelTalk::cmdClearInfoLine,
+ (OpcodeMethod)&ScalpelTalk::cmdWalkToCAnimation,
+ (OpcodeMethod)&ScalpelTalk::cmdRemoveItemFromInventory,
+ (OpcodeMethod)&ScalpelTalk::cmdEnableEndKey,
+ (OpcodeMethod)&ScalpelTalk::cmdDisableEndKey,
+
+ (OpcodeMethod)&ScalpelTalk::cmdEndTextWindow,
+ nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
+ nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
+ nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
+ nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
+ nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
+ nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
+ nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr
+ };
+
+ _opcodeTable = OPCODE_METHODS;
+ _opcodes = SCALPEL_OPCODES;
+
+ if (vm->getLanguage() == Common::DE_DEU || vm->getLanguage() == Common::ES_ESP) {
+ // The German and Spanish versions use a different opcode range
+ static byte opcodes[sizeof(SCALPEL_OPCODES)];
+ for (uint idx = 0; idx < sizeof(SCALPEL_OPCODES); ++idx)
+ opcodes[idx] = SCALPEL_OPCODES[idx] ? SCALPEL_OPCODES[idx] + 47 : 0;
+
+ _opcodes = opcodes;
+ }
+
+}
+
+void ScalpelTalk::talkTo(const Common::String filename) {
+ ScalpelUserInterface &ui = *(ScalpelUserInterface *)_vm->_ui;
+
+ Talk::talkTo(filename);
+
+ if (filename == "Tube59c") {
+ // WORKAROUND: Original game bug causes the results of testing the powdery substance
+ // to disappear too quickly. Introduce a delay to allow it to be properly displayed
+ ui._menuCounter = 30;
+ }
+}
+
+void ScalpelTalk::talkInterface(const byte *&str) {
+ FixedText &fixedText = *_vm->_fixedText;
+ People &people = *_vm->_people;
+ ScalpelScreen &screen = *(ScalpelScreen *)_vm->_screen;
+ UserInterface &ui = *_vm->_ui;
+
+ // 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);
+ }
+ }
+
+ // If it's the first line, display the speaker
+ if (!_line && _speaker >= 0 && _speaker < (int)people._characters.size()) {
+ // If the window is open, display the name directly on-screen.
+ // Otherwise, simply draw it on the back buffer
+ if (ui._windowOpen) {
+ screen.print(Common::Point(16, _yp), TALK_FOREGROUND, "%s",
+ people._characters[_speaker & 127]._name);
+ } else {
+ screen.gPrint(Common::Point(16, _yp - 1), TALK_FOREGROUND, "%s",
+ people._characters[_speaker & 127]._name);
+ _openTalkWindow = true;
+ }
+
+ _yp += 9;
+ }
+
+ // Find amount of text that will fit on the line
+ int width = 0, idx = 0;
+ do {
+ width += screen.charWidth(str[idx]);
+ ++idx;
+ ++_charCount;
+ } while (width < 298 && str[idx] && str[idx] != '{' && (!isOpcode(str[idx])));
+
+ if (str[idx] || width >= 298) {
+ if ((!isOpcode(str[idx])) && str[idx] != '{') {
+ --idx;
+ --_charCount;
+ }
+ } else {
+ _endStr = true;
+ }
+
+ // If word wrap is needed, find the start of the current word
+ if (width >= 298) {
+ while (str[idx] != ' ') {
+ --idx;
+ --_charCount;
+ }
+ }
+
+ // Print the line
+ Common::String lineStr((const char *)str, (const char *)str + idx);
+
+ // If the speaker indicates a description file, print it in yellow
+ if (_speaker != -1) {
+ if (ui._windowOpen) {
+ screen.print(Common::Point(16, _yp), COMMAND_FOREGROUND, "%s", lineStr.c_str());
+ } else {
+ screen.gPrint(Common::Point(16, _yp - 1), COMMAND_FOREGROUND, "%s", lineStr.c_str());
+ _openTalkWindow = true;
+ }
+ } else {
+ if (ui._windowOpen) {
+ screen.print(Common::Point(16, _yp), COMMAND_FOREGROUND, "%s", lineStr.c_str());
+ } else {
+ screen.gPrint(Common::Point(16, _yp - 1), COMMAND_FOREGROUND, "%s", lineStr.c_str());
+ _openTalkWindow = true;
+ }
+ }
+
+ // Move to end of displayed line
+ str += idx;
+
+ // If line wrap occurred, then move to after the separating space between the words
+ if ((!isOpcode(str[0])) && str[0] != '{')
+ ++str;
+
+ _yp += 9;
+ ++_line;
+
+ // Certain different conditions require a wait
+ if ((_line == 4 && str < _scriptEnd && str[0] != _opcodes[OP_SFX_COMMAND] && str[0] != _opcodes[OP_PAUSE] && _speaker != -1) ||
+ (_line == 5 && str < _scriptEnd && str[0] != _opcodes[OP_PAUSE] && _speaker == -1) ||
+ _endStr) {
+ _wait = 1;
+ }
+
+ byte v = (str >= _scriptEnd ? 0 : str[0]);
+ if (v == _opcodes[OP_SWITCH_SPEAKER] || v == _opcodes[OP_ASSIGN_PORTRAIT_LOCATION] ||
+ v == _opcodes[OP_BANISH_WINDOW] || v == _opcodes[OP_IF_STATEMENT] ||
+ v == _opcodes[OP_ELSE_STATEMENT] || v == _opcodes[OP_END_IF_STATEMENT] ||
+ v == _opcodes[OP_GOTO_SCENE] || v == _opcodes[OP_CALL_TALK_FILE]) {
+ _wait = 1;
+ }
+}
+
+OpcodeReturn ScalpelTalk::cmdSwitchSpeaker(const byte *&str) {
+ ScalpelPeople &people = *(ScalpelPeople *)_vm->_people;
+ UserInterface &ui = *_vm->_ui;
+
+ if (!(_speaker & SPEAKER_REMOVE))
+ people.clearTalking();
+ if (_talkToAbort)
+ return RET_EXIT;
+
+ ui.clearWindow();
+ _yp = CONTROLS_Y + 12;
+ _charCount = _line = 0;
+
+ _speaker = *++str - 1;
+ people.setTalking(_speaker);
+ pullSequence();
+ pushSequence(_speaker);
+ people.setTalkSequence(_speaker);
+
+ return RET_SUCCESS;
+}
+
+OpcodeReturn ScalpelTalk::cmdGotoScene(const byte *&str) {
+ ScalpelMap &map = *(ScalpelMap *)_vm->_map;
+ People &people = *_vm->_people;
+ Scene &scene = *_vm->_scene;
+ scene._goToScene = str[1] - 1;
+
+ if (scene._goToScene != OVERHEAD_MAP) {
+ // Not going to the map overview
+ map._oldCharPoint = scene._goToScene;
+ map._overPos.x = (map[scene._goToScene].x - 6) * FIXED_INT_MULTIPLIER;
+ map._overPos.y = (map[scene._goToScene].y + 9) * FIXED_INT_MULTIPLIER;
+
+ // Run a canimation?
+ if (str[2] > 100) {
+ people._savedPos = PositionFacing(160, 100, str[2]);
+ } else {
+ int32 posX = (str[3] - 1) * 256 + str[4] - 1;
+ int32 posY = str[5] - 1;
+ people._savedPos = PositionFacing(posX, posY, str[2] - 1);
+ }
+ }
+
+ str += 6;
+
+ _scriptMoreFlag = (scene._goToScene == 100) ? 2 : 1;
+ _scriptSaveIndex = str - _scriptStart;
+ _endStr = true;
+ _wait = 0;
+
+ return RET_SUCCESS;
+}
+
+OpcodeReturn ScalpelTalk::cmdAssignPortraitLocation(const byte *&str) {
+ People &people = *_vm->_people;
+
+ ++str;
+ switch (str[0] & 15) {
+ case 1:
+ people._portraitSide = 20;
+ break;
+ case 2:
+ people._portraitSide = 220;
+ break;
+ case 3:
+ people._portraitSide = 120;
+ break;
+ default:
+ break;
+ }
+
+ if (str[0] > 15)
+ people._speakerFlip = true;
+
+ return RET_SUCCESS;
+}
+
+OpcodeReturn ScalpelTalk::cmdClearInfoLine(const byte *&str) {
+ UserInterface &ui = *_vm->_ui;
+
+ ui._infoFlag = true;
+ ui.clearInfo();
+
+ return RET_SUCCESS;
+}
+
+OpcodeReturn ScalpelTalk::cmdClearWindow(const byte *&str) {
+ UserInterface &ui = *_vm->_ui;
+
+ ui.clearWindow();
+ _yp = CONTROLS_Y + 12;
+ _charCount = _line = 0;
+
+ return RET_SUCCESS;
+}
+
+OpcodeReturn ScalpelTalk::cmdDisplayInfoLine(const byte *&str) {
+ Screen &screen = *_vm->_screen;
+ UserInterface &ui = *_vm->_ui;
+ Common::String tempString;
+
+ ++str;
+ for (int idx = 0; idx < str[0]; ++idx)
+ tempString += str[idx + 1];
+ str += str[0];
+
+ screen.print(Common::Point(0, INFO_LINE + 1), INFO_FOREGROUND, "%s", tempString.c_str());
+ ui._menuCounter = 30;
+
+ return RET_SUCCESS;
+}
+
+OpcodeReturn ScalpelTalk::cmdElse(const byte *&str) {
+ // If this is encountered here, it means that a preceeding IF statement was found,
+ // and evaluated to true. Now all the statements for the true block are finished,
+ // so skip over the block of code that would have executed if the result was false
+ _wait = 0;
+ do {
+ ++str;
+ } while (str[0] && str[0] != _opcodes[OP_END_IF_STATEMENT]);
+
+ return RET_SUCCESS;
+}
+
+OpcodeReturn ScalpelTalk::cmdIf(const byte *&str) {
+ ++str;
+ int flag = (str[0] - 1) * 256 + str[1] - 1 - (str[1] == 1 ? 1 : 0);
+ ++str;
+ _wait = 0;
+
+ bool result = flag < 0x8000;
+ if (_vm->readFlags(flag & 0x7fff) != result) {
+ do {
+ ++str;
+ } while (str[0] && str[0] != _opcodes[OP_ELSE_STATEMENT] && str[0] != _opcodes[OP_END_IF_STATEMENT]);
+
+ if (!str[0])
+ _endStr = true;
+ }
+
+ return RET_SUCCESS;
+}
+
+OpcodeReturn ScalpelTalk::cmdMoveMouse(const byte *&str) {
+ Events &events = *_vm->_events;
+
+ ++str;
+ events.warpMouse(Common::Point((str[0] - 1) * 256 + str[1] - 1, str[2]));
+ if (_talkToAbort)
+ return RET_EXIT;
+ str += 3;
+
+ return RET_SUCCESS;
+}
+
+OpcodeReturn ScalpelTalk::cmdPlayPrologue(const byte *&str) {
+ Animation &anim = *_vm->_animation;
+ Common::String tempString;
+
+ ++str;
+ for (int idx = 0; idx < 8 && str[idx] != '~'; ++idx)
+ tempString += str[idx];
+
+ anim.play(tempString, false, 1, 3, true, 4);
+
+ return RET_SUCCESS;
+}
+
+OpcodeReturn ScalpelTalk::cmdRemovePortrait(const byte *&str) {
+ People &people = *_vm->_people;
+
+ if (_speaker >= 0 && _speaker < SPEAKER_REMOVE)
+ people.clearTalking();
+ pullSequence();
+ if (_talkToAbort)
+ return RET_EXIT;
+
+ _speaker |= SPEAKER_REMOVE;
+ return RET_SUCCESS;
+}
+
+OpcodeReturn ScalpelTalk::cmdWalkToCoords(const byte *&str) {
+ People &people = *_vm->_people;
+ ++str;
+
+ people[HOLMES].walkToCoords(Point32(((str[0] - 1) * 256 + str[1] - 1) * FIXED_INT_MULTIPLIER,
+ str[2] * FIXED_INT_MULTIPLIER), str[3] - 1);
+ if (_talkToAbort)
+ return RET_EXIT;
+
+ str += 3;
+ return RET_SUCCESS;
+}
+
+OpcodeReturn ScalpelTalk::cmdSfxCommand(const byte *&str) {
+ Sound &sound = *_vm->_sound;
+ Common::String tempString;
+
+ ++str;
+ if (sound._voices) {
+ for (int idx = 0; idx < 8 && str[idx] != '~'; ++idx)
+ tempString += str[idx];
+ sound.playSpeech(tempString);
+
+ // Set voices to wait for more
+ sound._voices = 2;
+ }
+
+ _wait = 1;
+ str += 7;
+
+ return RET_SUCCESS;
+}
+
+OpcodeReturn ScalpelTalk::cmdSummonWindow(const byte *&str) {
+ Events &events = *_vm->_events;
+ FixedText &fixedText = *_vm->_fixedText;
+ ScalpelScreen &screen = *(ScalpelScreen *)_vm->_screen;
+
+ drawInterface();
+ events._pressed = events._released = false;
+ events.clearKeyboard();
+ _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);
+ }
+
+ return RET_SUCCESS;
+}
+
+void ScalpelTalk::talkWait(const byte *&str) {
+ UserInterface &ui = *_vm->_ui;
+ bool pauseFlag = _pauseFlag;
+
+ Talk::talkWait(str);
+
+ // Clear the window unless the wait was due to a PAUSE command
+ if (!pauseFlag && _wait != -1 && str < _scriptEnd && str[0] != _opcodes[OP_SFX_COMMAND]) {
+ if (!_talkStealth)
+ ui.clearWindow();
+ _yp = CONTROLS_Y + 12;
+ _charCount = _line = 0;
+ }
+}
+
+void ScalpelTalk::nothingToSay() {
+ error("Character had no talk options available");
+}
+
+void ScalpelTalk::switchSpeaker() {
+ // If it's the 3DO, pass on to start the actor's conversation movie
+ if (IS_3DO)
+ talk3DOMovieTrigger(_3doSpeechIndex++);
+}
+
+void ScalpelTalk::talk3DOMovieTrigger(int subIndex) {
+ // Find out a few things that we need
+ int userSelector = _vm->_ui->_selector;
+ int scriptSelector = _scriptSelect;
+ int selector = 0;
+ int roomNr = _vm->_scene->_currentScene;
+
+ if (userSelector >= 0) {
+ // User-selected dialog
+ selector = userSelector;
+ } else {
+ if (scriptSelector >= 0) {
+ // Script-selected dialog
+ selector = scriptSelector;
+ subIndex--; // for scripts we adjust subIndex, b/c we won't get called from doTalkControl()
+ } else {
+ warning("talk3DOMovieTrigger: unable to find selector");
+ return;
+ }
+ }
+
+ // Make a quick update, so that current text is shown on screen
+ _vm->_screen->update();
+
+ // Figure out that movie filename
+ Common::String movieFilename;
+
+ movieFilename = _scriptName;
+ movieFilename.deleteChar(1); // remove 2nd character of scriptname
+ // cut scriptname to 6 characters
+ while (movieFilename.size() > 6) {
+ movieFilename.deleteChar(6);
+ }
+
+ movieFilename.insertChar(selector + 'a', movieFilename.size());
+ movieFilename.insertChar(subIndex + 'a', movieFilename.size());
+ movieFilename = Common::String::format("movies/%02d/%s.stream", roomNr, movieFilename.c_str());
+
+ warning("3DO movie player:");
+ warning("room: %d", roomNr);
+ warning("script: %s", _scriptName.c_str());
+ warning("selector: %d", selector);
+ warning("subindex: %d", subIndex);
+
+ Scalpel3DOMoviePlay(movieFilename.c_str(), Common::Point(5, 5));
+
+ // Restore screen HACK
+ _vm->_screen->makeAllDirty();
+}
+
+void ScalpelTalk::drawInterface() {
+ FixedText &fixedText = *_vm->_fixedText;
+ ScalpelScreen &screen = *(ScalpelScreen *)_vm->_screen;
+ Surface &bb = *screen._backBuffer;
+
+ 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);
+ bb.fillRect(Common::Rect(SHERLOCK_SCREEN_WIDTH - 2, CONTROLS_Y + 10,
+ SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT), BORDER_COLOR);
+ bb.fillRect(Common::Rect(0, SHERLOCK_SCREEN_HEIGHT - 1, SHERLOCK_SCREEN_WIDTH - 2,
+ SHERLOCK_SCREEN_HEIGHT), BORDER_COLOR);
+ bb.fillRect(Common::Rect(2, CONTROLS_Y + 10, SHERLOCK_SCREEN_WIDTH - 2,
+ 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);
+
+ screen.makeButton(Common::Rect(99, CONTROLS_Y, 139, CONTROLS_Y + 10),
+ 119 - screen.stringWidth(fixedText_Exit) / 2, fixedText_Exit);
+ screen.makeButton(Common::Rect(140, CONTROLS_Y, 180, CONTROLS_Y + 10),
+ 159 - screen.stringWidth(fixedText_Up) / 2, fixedText_Up);
+ screen.makeButton(Common::Rect(181, CONTROLS_Y, 221, CONTROLS_Y + 10),
+ 200 - screen.stringWidth(fixedText_Down) / 2, fixedText_Down);
+ } else {
+ int strWidth = screen.stringWidth(Scalpel::PRESS_KEY_TO_CONTINUE);
+ 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");
+ }
+}
+
+bool ScalpelTalk::displayTalk(bool slamIt) {
+ FixedText &fixedText = *_vm->_fixedText;
+ ScalpelScreen &screen = *(ScalpelScreen *)_vm->_screen;
+ int yp = CONTROLS_Y + 14;
+ int lineY = -1;
+ _moreTalkDown = _moreTalkUp = false;
+
+ for (uint idx = 0; idx < _statements.size(); ++idx) {
+ _statements[idx]._talkPos.top = _statements[idx]._talkPos.bottom = -1;
+ }
+
+ if (_talkIndex) {
+ for (int idx = 0; idx < _talkIndex && !_moreTalkUp; ++idx) {
+ if (_statements[idx]._talkMap != -1)
+ _moreTalkUp = true;
+ }
+ }
+
+ // 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);
+ } else {
+ screen.gPrint(Common::Point(5, CONTROLS_Y + 12), INV_FOREGROUND, "~");
+ screen.buttonPrint(Common::Point(159, CONTROLS_Y), COMMAND_FOREGROUND, false, fixedText_Up);
+ }
+ } else {
+ if (slamIt) {
+ screen.buttonPrint(Common::Point(159, CONTROLS_Y), COMMAND_NULL, true, fixedText_Up);
+ 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._backBuffer1.fillRect(Common::Rect(5, CONTROLS_Y + 11,
+ 15, CONTROLS_Y + 22), INV_BACKGROUND);
+ }
+ }
+
+ // Loop through the statements
+ bool done = false;
+ for (uint idx = _talkIndex; idx < _statements.size() && !done; ++idx) {
+ Statement &statement = _statements[idx];
+
+ if (statement._talkMap != -1) {
+ bool flag = _talkHistory[_converseNum][idx];
+ lineY = talkLine(idx, statement._talkMap, flag ? (byte)TALK_NULL : (byte)INV_FOREGROUND,
+ yp, slamIt);
+
+ if (lineY != -1) {
+ statement._talkPos.top = yp;
+ yp = lineY;
+ statement._talkPos.bottom = yp;
+
+ if (yp == SHERLOCK_SCREEN_HEIGHT)
+ done = true;
+ } else {
+ done = true;
+ }
+ }
+ }
+
+ // Display the down arrow and enable down button if there are more statements available down off-screen
+ if (lineY == -1 || lineY == SHERLOCK_SCREEN_HEIGHT) {
+ _moreTalkDown = true;
+
+ if (slamIt) {
+ screen.print(Common::Point(5, 190), INV_FOREGROUND, "|");
+ screen.buttonPrint(Common::Point(200, CONTROLS_Y), COMMAND_FOREGROUND, true, fixedText_Down);
+ } else {
+ screen.gPrint(Common::Point(5, 189), INV_FOREGROUND, "|");
+ screen.buttonPrint(Common::Point(200, CONTROLS_Y), COMMAND_FOREGROUND, false, fixedText_Down);
+ }
+ } else {
+ if (slamIt) {
+ screen.buttonPrint(Common::Point(200, CONTROLS_Y), COMMAND_NULL, true, fixedText_Down);
+ screen.vgaBar(Common::Rect(5, 189, 16, 199), INV_BACKGROUND);
+ } else {
+ screen.buttonPrint(Common::Point(200, CONTROLS_Y), COMMAND_NULL, false, fixedText_Down);
+ screen._backBuffer1.fillRect(Common::Rect(5, 189, 16, 199), INV_BACKGROUND);
+ }
+ }
+
+ return done;
+}
+
+int ScalpelTalk::talkLine(int lineNum, int stateNum, byte color, int lineY, bool slamIt) {
+ Screen &screen = *_vm->_screen;
+ int idx = lineNum;
+ Common::String msg, number;
+ bool numberFlag = false;
+
+ // Get the statement to display as well as optional number prefix
+ if (idx < SPEAKER_REMOVE) {
+ number = Common::String::format("%d.", stateNum + 1);
+ numberFlag = true;
+ } else {
+ idx -= SPEAKER_REMOVE;
+ }
+ msg = _statements[idx]._statement;
+
+ // Handle potentially multiple lines needed to display entire statement
+ const char *lineStartP = msg.c_str();
+ int maxWidth = 298 - (numberFlag ? 18 : 0);
+ for (;;) {
+ // Get as much of the statement as possible will fit on the
+ Common::String sLine;
+ const char *lineEndP = lineStartP;
+ int width = 0;
+ do {
+ width += screen.charWidth(*lineEndP);
+ } while (*++lineEndP && width < maxWidth);
+
+ // Check if we need to wrap the line
+ if (width >= maxWidth) {
+ // Work backwards to the prior word's end
+ while (*--lineEndP != ' ')
+ ;
+
+ sLine = Common::String(lineStartP, lineEndP++);
+ } else {
+ // Can display remainder of the statement on the current line
+ sLine = Common::String(lineStartP);
+ }
+
+
+ if (lineY <= (SHERLOCK_SCREEN_HEIGHT - 10)) {
+ // Need to directly display on-screen?
+ if (slamIt) {
+ // See if a numer prefix is needed or not
+ if (numberFlag) {
+ // Are we drawing the first line?
+ if (lineStartP == msg.c_str()) {
+ // We are, so print the number and then the text
+ screen.print(Common::Point(16, lineY), color, "%s", number.c_str());
+ }
+
+ // Draw the line with an indent
+ screen.print(Common::Point(30, lineY), color, "%s", sLine.c_str());
+ } else {
+ screen.print(Common::Point(16, lineY), color, "%s", sLine.c_str());
+ }
+ } else {
+ if (numberFlag) {
+ if (lineStartP == msg.c_str()) {
+ screen.gPrint(Common::Point(16, lineY - 1), color, "%s", number.c_str());
+ }
+
+ screen.gPrint(Common::Point(30, lineY - 1), color, "%s", sLine.c_str());
+ } else {
+ screen.gPrint(Common::Point(16, lineY - 1), color, "%s", sLine.c_str());
+ }
+ }
+
+ // Move to next line, if any
+ lineY += 9;
+ lineStartP = lineEndP;
+
+ if (!*lineEndP)
+ break;
+ } else {
+ // We're close to the bottom of the screen, so stop display
+ lineY = -1;
+ break;
+ }
+ }
+
+ if (lineY == -1 && lineStartP != msg.c_str())
+ lineY = SHERLOCK_SCREEN_HEIGHT;
+
+ // Return the Y position of the next line to follow this one
+ return lineY;
+}
+
+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();
+ pushSequence(_talkTo);
+ people.setListenSequence(_talkTo);
+
+ ui._selector = ui._oldSelector = -1;
+
+ if (!ui._windowOpen) {
+ // Draw the talk interface on the back buffer
+ drawInterface();
+ displayTalk(false);
+ } else {
+ displayTalk(true);
+ }
+
+ // 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);
+ } else {
+ screen.buttonPrint(Common::Point(119, CONTROLS_Y), color, false, fixedText_Exit);
+
+ if (!ui._slideWindows) {
+ screen.slamRect(Common::Rect(0, CONTROLS_Y,
+ SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT));
+ } else {
+ ui.summonWindow();
+ }
+
+ ui._windowOpen = true;
+ }
+}
+
+OpcodeReturn ScalpelTalk::cmdCallTalkFile(const byte *&str) {
+ Common::String tempString;
+
+ ++str;
+ for (int idx = 0; idx < 8 && str[idx] != '~'; ++idx)
+ tempString += str[idx];
+ str += 8;
+
+ int scriptCurrentIndex = str - _scriptStart;
+
+ // Save the current script position and new talk file
+ if (_scriptStack.size() < 9) {
+ ScriptStackEntry rec1;
+ rec1._name = _scriptName;
+ rec1._currentIndex = scriptCurrentIndex;
+ rec1._select = _scriptSelect;
+ _scriptStack.push(rec1);
+
+ // Push the new talk file onto the stack
+ ScriptStackEntry rec2;
+ rec2._name = tempString;
+ rec2._currentIndex = 0;
+ rec2._select = 100;
+ _scriptStack.push(rec2);
+ } else {
+ error("Script stack overflow");
+ }
+
+ _scriptMoreFlag = 1;
+ _endStr = true;
+ _wait = 0;
+
+ return RET_SUCCESS;
+}
+
+void ScalpelTalk::pushSequenceEntry(Object *obj) {
+ Scene &scene = *_vm->_scene;
+ SequenceEntry seqEntry;
+ seqEntry._objNum = scene._bgShapes.indexOf(*obj);
+
+ if (seqEntry._objNum != -1) {
+ for (uint idx = 0; idx < MAX_TALK_SEQUENCES; ++idx)
+ seqEntry._sequences.push_back(obj->_sequences[idx]);
+
+ seqEntry._frameNumber = obj->_frameNumber;
+ seqEntry._seqTo = obj->_seqTo;
+ }
+
+ _sequenceStack.push(seqEntry);
+ if (_scriptStack.size() >= 5)
+ error("script stack overflow");
+}
+
+void ScalpelTalk::pullSequence(int slot) {
+ Scene &scene = *_vm->_scene;
+
+ if (_sequenceStack.empty())
+ return;
+
+ SequenceEntry seq = _sequenceStack.pop();
+ if (seq._objNum != -1) {
+ Object &obj = scene._bgShapes[seq._objNum];
+
+ if (obj._seqSize < MAX_TALK_SEQUENCES) {
+ warning("Tried to restore too few frames");
+ } else {
+ for (int idx = 0; idx < MAX_TALK_SEQUENCES; ++idx)
+ obj._sequences[idx] = seq._sequences[idx];
+
+ obj._frameNumber = seq._frameNumber;
+ obj._seqTo = seq._seqTo;
+ }
+ }
+}
+
+void ScalpelTalk::clearSequences() {
+ _sequenceStack.clear();
+}
+
+} // End of namespace Scalpel
+
+} // End of namespace Sherlock
diff --git a/engines/sherlock/scalpel/scalpel_talk.h b/engines/sherlock/scalpel/scalpel_talk.h
new file mode 100644
index 0000000000..31f78cbf85
--- /dev/null
+++ b/engines/sherlock/scalpel/scalpel_talk.h
@@ -0,0 +1,143 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public 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_TALK_H
+#define SHERLOCK_SCALPEL_TALK_H
+
+#include "common/scummsys.h"
+#include "common/array.h"
+#include "common/rect.h"
+#include "common/serializer.h"
+#include "common/stream.h"
+#include "common/stack.h"
+#include "sherlock/talk.h"
+
+namespace Sherlock {
+
+namespace Scalpel {
+
+class ScalpelTalk : public Talk {
+private:
+ Common::Stack<SequenceEntry> _sequenceStack;
+
+ OpcodeReturn cmdSwitchSpeaker(const byte *&str);
+ OpcodeReturn cmdAssignPortraitLocation(const byte *&str);
+ OpcodeReturn cmdGotoScene(const byte *&str);
+ OpcodeReturn cmdCallTalkFile(const byte *&str);
+ OpcodeReturn cmdClearInfoLine(const byte *&str);
+ OpcodeReturn cmdClearWindow(const byte *&str);
+ OpcodeReturn cmdDisplayInfoLine(const byte *&str);
+ OpcodeReturn cmdElse(const byte *&str);
+ OpcodeReturn cmdIf(const byte *&str);
+ OpcodeReturn cmdMoveMouse(const byte *&str);
+ OpcodeReturn cmdPlayPrologue(const byte *&str);
+ OpcodeReturn cmdRemovePortrait(const byte *&str);
+ OpcodeReturn cmdSfxCommand(const byte *&str);
+ OpcodeReturn cmdSummonWindow(const byte *&str);
+ OpcodeReturn cmdWalkToCoords(const byte *&str);
+protected:
+ /**
+ * Display the talk interface window
+ */
+ virtual void talkInterface(const byte *&str);
+
+ /**
+ * Pause when displaying a talk dialog on-screen
+ */
+ virtual void talkWait(const byte *&str);
+
+ /**
+ * Called when the active speaker is switched
+ */
+ virtual void switchSpeaker();
+
+ /**
+ * Called when a character being spoken to has no talk options to display
+ */
+ virtual void nothingToSay();
+
+ /**
+ * Show the talk display
+ */
+ virtual void showTalk();
+public:
+ ScalpelTalk(SherlockEngine *vm);
+ virtual ~ScalpelTalk() {}
+
+ /**
+ * Called whenever a conversation or item script needs to be run. For standard conversations,
+ * it opens up a description window similar to how 'talk' does, but shows a 'reply' directly
+ * instead of waiting for a statement option.
+ * @remarks It seems that at some point, all item scripts were set up to use this as well.
+ * In their case, the conversation display is simply suppressed, and control is passed on to
+ * doScript to implement whatever action is required.
+ */
+ virtual void talkTo(const Common::String filename);
+
+ /**
+ * Draws the interface for conversation display
+ */
+ void drawInterface();
+
+ /**
+ * Display a list of statements in a window at the bottom of the screen that the
+ * player can select from.
+ */
+ bool displayTalk(bool slamIt);
+
+ /**
+ * Prints a single conversation option in the interface window
+ */
+ int talkLine(int lineNum, int stateNum, byte color, int lineY, bool slamIt);
+
+ /**
+ * Trigger to play a 3DO talk dialog movie
+ */
+ void talk3DOMovieTrigger(int subIndex);
+
+ /**
+ * Push the details of a passed object onto the saved sequences stack
+ */
+ virtual void pushSequenceEntry(Object *obj);
+
+ /**
+ * Pulls a background object sequence from the sequence stack and restore's the
+ * object's sequence
+ */
+ virtual void pullSequence(int slot = -1);
+
+ /**
+ * Returns true if the script stack is empty
+ */
+ virtual bool isSequencesEmpty() const { return _scriptStack.empty(); }
+
+ /**
+ * Clears the stack of pending object sequences associated with speakers in the scene
+ */
+ virtual void clearSequences();
+};
+
+} // End of namespace Scalpel
+
+} // End of namespace Sherlock
+
+#endif
diff --git a/engines/sherlock/scalpel/scalpel_user_interface.cpp b/engines/sherlock/scalpel/scalpel_user_interface.cpp
index 295cddb3c9..a67d464a11 100644
--- a/engines/sherlock/scalpel/scalpel_user_interface.cpp
+++ b/engines/sherlock/scalpel/scalpel_user_interface.cpp
@@ -21,8 +21,16 @@
*/
#include "sherlock/scalpel/scalpel_user_interface.h"
-#include "sherlock/sherlock.h"
+#include "sherlock/scalpel/scalpel_fixed_text.h"
+#include "sherlock/scalpel/scalpel_inventory.h"
+#include "sherlock/scalpel/scalpel_journal.h"
+#include "sherlock/scalpel/scalpel_people.h"
+#include "sherlock/scalpel/scalpel_saveload.h"
+#include "sherlock/scalpel/scalpel_screen.h"
+#include "sherlock/scalpel/scalpel_talk.h"
#include "sherlock/scalpel/settings.h"
+#include "sherlock/scalpel/scalpel.h"
+#include "sherlock/sherlock.h"
namespace Sherlock {
@@ -60,33 +68,22 @@ const char COMMANDS[13] = "LMTPOCIUGJFS";
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 char *const MOPEN[] = {
- "This cannot be opened", "It is already open", "It is locked", "Wait for Watson", " ", "."
-};
-const char *const MCLOSE[] = {
- "This cannot be closed", "It is already closed", "The safe door is in the way"
-};
-const char *const MMOVE[] = {
- "This cannot be moved", "It is bolted to the floor", "It is too heavy", "The other crate is in the way"
-};
-const char *const MPICK[] = {
- "Nothing of interest here", "It is bolted down", "It is too big to carry", "It is too heavy",
- "I think a girl would be more your type", "Those flowers belong to Penny", "She's far too young for you!",
- "I think a girl would be more your type!", "Government property for official use only"
-};
-const char *const MUSE[] = {
- "You can't do that", "It had no effect", "You can't reach it", "OK, the door looks bigger! Happy?",
- "Doors don't smoke"
-};
+const int UI_OFFSET_3DO = 16; // (320 - 288) / 2
/*----------------------------------------------------------------*/
ScalpelUserInterface::ScalpelUserInterface(SherlockEngine *vm): UserInterface(vm) {
if (_vm->_interactiveFl) {
- _controls = new ImageFile("menu.all");
- _controlPanel = new ImageFile("controls.vgs");
+ if (!IS_3DO) {
+ // PC
+ _controls = new ImageFile("menu.all");
+ _controlPanel = new ImageFile("controls.vgs");
+ } else {
+ // 3DO
+ _controls = new ImageFile3DO("menu.all", kImageFile3DOType_RoomFormat);
+ _controlPanel = new ImageFile3DO("controls.vgs", kImageFile3DOType_RoomFormat);
+ }
} else {
_controls = nullptr;
_controlPanel = nullptr;
@@ -94,8 +91,6 @@ ScalpelUserInterface::ScalpelUserInterface(SherlockEngine *vm): UserInterface(vm
_keyPress = '\0';
_lookHelp = 0;
- _bgFound = 0;
- _oldBgFound = -1;
_help = _oldHelp = 0;
_key = _oldKey = '\0';
_temp = _oldTemp = 0;
@@ -113,18 +108,20 @@ ScalpelUserInterface::~ScalpelUserInterface() {
}
void ScalpelUserInterface::reset() {
- _oldKey = -1;
+ UserInterface::reset();
_help = _oldHelp = -1;
- _oldTemp = _temp = -1;
}
void ScalpelUserInterface::drawInterface(int bufferNum) {
Screen &screen = *_vm->_screen;
+ const ImageFrame &src = (*_controlPanel)[0];
+ int16 x = (!IS_3DO) ? 0 : UI_OFFSET_3DO;
+
if (bufferNum & 1)
- screen._backBuffer1.transBlitFrom((*_controlPanel)[0], Common::Point(0, CONTROLS_Y));
+ screen._backBuffer1.transBlitFrom(src, Common::Point(x, CONTROLS_Y));
if (bufferNum & 2)
- screen._backBuffer2.transBlitFrom((*_controlPanel)[0], Common::Point(0, CONTROLS_Y));
+ screen._backBuffer2.transBlitFrom(src, Common::Point(x, CONTROLS_Y));
if (bufferNum == 3)
screen._backBuffer2.fillRect(0, INFO_LINE, SHERLOCK_SCREEN_WIDTH, INFO_LINE + 10, INFO_BLACK);
}
@@ -141,7 +138,7 @@ void ScalpelUserInterface::handleInput() {
whileMenuCounter();
Common::Point pt = events.mousePos();
- _bgFound = scene.findBgShape(Common::Rect(pt.x, pt.y, pt.x + 1, pt.y + 1));
+ _bgFound = scene.findBgShape(pt);
_keyPress = '\0';
// Check kbd and set the mouse released flag if Enter or space is pressed.
@@ -279,7 +276,7 @@ void ScalpelUserInterface::handleInput() {
}
if (events._released && personFound)
- talk.talk(_bgFound);
+ talk.initTalk(_bgFound);
else if (personFound)
lookScreen(pt);
else if (_bgFound < 1000)
@@ -316,9 +313,9 @@ void ScalpelUserInterface::handleInput() {
// Mouse clicked in script zone
events._pressed = events._released = false;
} else {
- people._walkDest = pt;
people._allowWalkAbort = false;
- people.goAllTheWay();
+ people[HOLMES]._walkDest = pt;
+ people[HOLMES].goAllTheWay();
}
if (_oldKey != -1) {
@@ -385,6 +382,7 @@ void ScalpelUserInterface::handleInput() {
void ScalpelUserInterface::depressButton(int num) {
Screen &screen = *_vm->_screen;
Common::Point pt(MENU_POINTS[num][0], MENU_POINTS[num][1]);
+ offsetButton3DO(pt, num);
ImageFrame &frame = (*_controls)[num];
screen._backBuffer1.transBlitFrom(frame, pt);
@@ -392,10 +390,17 @@ void ScalpelUserInterface::depressButton(int num) {
}
void ScalpelUserInterface::restoreButton(int num) {
+ Events &events = *_vm->_events;
Screen &screen = *_vm->_screen;
Common::Point pt(MENU_POINTS[num][0], MENU_POINTS[num][1]);
+ offsetButton3DO(pt, num);
+
Graphics::Surface &frame = (*_controls)[num]._frame;
+ // Reset the cursor
+ events.setCursor(ARROW);
+
+ // Restore the UI on the back buffer
screen._backBuffer1.blitFrom(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);
@@ -441,6 +446,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.slamArea(pt.x, pt.y, pt.x + frame._width, pt.y + frame._height);
}
@@ -495,7 +501,7 @@ void ScalpelUserInterface::examine() {
scene.startCAnim(_cNum, canimSpeed);
} else if (obj._lookPosition.y != 0) {
// Need to walk to the object to be examined
- people.walkToCoords(Common::Point(obj._lookPosition.x, obj._lookPosition.y * 100), obj._lookFacing);
+ people[HOLMES].walkToCoords(obj._lookPosition, obj._lookPosition._facing);
}
if (!talk._talkToAbort) {
@@ -536,7 +542,7 @@ void ScalpelUserInterface::lookScreen(const Common::Point &pt) {
Common::String tempStr;
// Don't display anything for right button command
- if ((events._rightPressed || events._rightPressed) && !events._pressed)
+ if ((events._rightPressed || events._rightReleased) && !events._pressed)
return;
if (mousePos.y < CONTROLS_Y && (temp = _bgFound) != -1) {
@@ -666,9 +672,9 @@ void ScalpelUserInterface::lookInv() {
void ScalpelUserInterface::doEnvControl() {
Events &events = *_vm->_events;
- SaveManager &saves = *_vm->_saves;
+ ScalpelSaveManager &saves = *(ScalpelSaveManager *)_vm->_saves;
Scene &scene = *_vm->_scene;
- Screen &screen = *_vm->_screen;
+ ScalpelScreen &screen = *(ScalpelScreen *)_vm->_screen;
Talk &talk = *_vm->_talk;
Common::Point mousePos = events.mousePos();
static const char ENV_COMMANDS[7] = "ELSUDQ";
@@ -968,9 +974,10 @@ void ScalpelUserInterface::doEnvControl() {
void ScalpelUserInterface::doInvControl() {
Events &events = *_vm->_events;
- Inventory &inv = *_vm->_inventory;
+ FixedText &fixedText = *_vm->_fixedText;
+ ScalpelInventory &inv = *(ScalpelInventory *)_vm->_inventory;
Scene &scene = *_vm->_scene;
- Screen &screen = *_vm->_screen;
+ ScalpelScreen &screen = *(ScalpelScreen *)_vm->_screen;
Talk &talk = *_vm->_talk;
int colors[8];
Common::Point mousePos = events.mousePos();
@@ -993,15 +1000,20 @@ 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, "Exit");
+ screen.buttonPrint(Common::Point(INVENTORY_POINTS[0][2], CONTROLS_Y1), colors[0], true, fixedText_Exit);
if (found >= 0 && found <= 3) {
- screen.buttonPrint(Common::Point(INVENTORY_POINTS[1][2], CONTROLS_Y1), colors[1], true, "Look");
- screen.buttonPrint(Common::Point(INVENTORY_POINTS[2][2], CONTROLS_Y1), colors[2], true, "Use");
- screen.buttonPrint(Common::Point(INVENTORY_POINTS[3][2], CONTROLS_Y1), colors[3], true, "Give");
+ 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);
inv._invMode = (InvMode)found;
_selector = -1;
}
@@ -1063,7 +1075,7 @@ void ScalpelUserInterface::doInvControl() {
}
if (_selector != -1)
- inv.highlight(_selector, 235);
+ inv.highlight(_selector, BUTTON_BACKGROUND);
_oldSelector = _selector;
}
@@ -1177,10 +1189,10 @@ void ScalpelUserInterface::doInvControl() {
bool giveFl = (tempMode >= INVMODE_GIVE);
if (_selector >= 0)
// Use/Give inv object with scene object
- checkUseAction(&scene._bgShapes[_find]._use[0], inv[_selector]._name, MUSE, _find, giveFl);
+ checkUseAction(&scene._bgShapes[_find]._use[0], inv[_selector]._name, kFixedTextAction_Use, _find, giveFl);
else
// Now inv object has been highlighted
- checkUseAction(&scene._bgShapes[_find]._use[0], "*SELF*", MUSE, _find, giveFl);
+ checkUseAction(&scene._bgShapes[_find]._use[0], "*SELF*", kFixedTextAction_Use, _find, giveFl);
_selector = _oldSelector = -1;
}
@@ -1191,7 +1203,7 @@ void ScalpelUserInterface::doInvControl() {
void ScalpelUserInterface::doLookControl() {
Events &events = *_vm->_events;
- Inventory &inv = *_vm->_inventory;
+ ScalpelInventory &inv = *(ScalpelInventory *)_vm->_inventory;
Screen &screen = *_vm->_screen;
_key = _oldKey = -1;
@@ -1206,6 +1218,7 @@ void ScalpelUserInterface::doLookControl() {
} else if (!_lookHelp) {
// 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);
banishWindow(true);
@@ -1252,8 +1265,8 @@ void ScalpelUserInterface::doLookControl() {
void ScalpelUserInterface::doMainControl() {
Events &events = *_vm->_events;
- Inventory &inv = *_vm->_inventory;
- SaveManager &saves = *_vm->_saves;
+ ScalpelInventory &inv = *(ScalpelInventory *)_vm->_inventory;
+ ScalpelSaveManager &saves = *(ScalpelSaveManager *)_vm->_saves;
Common::Point pt = events.mousePos();
if ((events._pressed || events._released) && pt.y > CONTROLS_Y) {
@@ -1264,6 +1277,10 @@ void ScalpelUserInterface::doMainControl() {
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) {
+ r.left += UI_OFFSET_3DO - 1;
+ r.right += UI_OFFSET_3DO - 1;
+ }
if (r.contains(pt))
_key = COMMANDS[_temp];
}
@@ -1403,7 +1420,7 @@ void ScalpelUserInterface::doMiscControl(int allowed) {
switch (allowed) {
case ALLOW_OPEN:
- checkAction(obj._aOpen, MOPEN, _temp);
+ checkAction(obj._aOpen, _temp, kFixedTextAction_Open);
if (_menuMode != TALK_MODE && !talk._talkToAbort) {
_menuMode = STD_MODE;
restoreButton(OPEN_MODE - 1);
@@ -1412,7 +1429,7 @@ void ScalpelUserInterface::doMiscControl(int allowed) {
break;
case ALLOW_CLOSE:
- checkAction(obj._aClose, MCLOSE, _temp);
+ checkAction(obj._aClose, _temp, kFixedTextAction_Close);
if (_menuMode != TALK_MODE && !talk._talkToAbort) {
_menuMode = STD_MODE;
restoreButton(CLOSE_MODE - 1);
@@ -1421,7 +1438,7 @@ void ScalpelUserInterface::doMiscControl(int allowed) {
break;
case ALLOW_MOVE:
- checkAction(obj._aMove, MMOVE, _temp);
+ checkAction(obj._aMove, _temp, kFixedTextAction_Move);
if (_menuMode != TALK_MODE && !talk._talkToAbort) {
_menuMode = STD_MODE;
restoreButton(MOVE_MODE - 1);
@@ -1448,7 +1465,7 @@ void ScalpelUserInterface::doPickControl() {
// Don't allow characters to be picked up
if (_bgFound < 1000) {
- scene._bgShapes[_bgFound].pickUpObject(MPICK);
+ scene._bgShapes[_bgFound].pickUpObject(kFixedTextAction_Pick);
if (!talk._talkToAbort && _menuMode != TALK_MODE) {
_key = _oldKey = -1;
@@ -1462,34 +1479,39 @@ void ScalpelUserInterface::doPickControl() {
void ScalpelUserInterface::doTalkControl() {
Events &events = *_vm->_events;
- Journal &journal = *_vm->_journal;
- People &people = *_vm->_people;
- Screen &screen = *_vm->_screen;
+ FixedText &fixedText = *_vm->_fixedText;
+ ScalpelJournal &journal = *(ScalpelJournal *)_vm->_journal;
+ ScalpelPeople &people = *(ScalpelPeople *)_vm->_people;
+ ScalpelScreen &screen = *(ScalpelScreen *)_vm->_screen;
Sound &sound = *_vm->_sound;
- Talk &talk = *_vm->_talk;
+ ScalpelTalk &talk = *(ScalpelTalk *)_vm->_talk;
Common::Point mousePos = events.mousePos();
_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, "Exit");
+ screen.buttonPrint(Common::Point(119, CONTROLS_Y), COMMAND_HIGHLIGHTED, true, fixedText_Exit);
else if (_endKeyActive)
- screen.buttonPrint(Common::Point(119, CONTROLS_Y), COMMAND_FOREGROUND, true, "Exit");
+ screen.buttonPrint(Common::Point(119, CONTROLS_Y), COMMAND_FOREGROUND, true, fixedText_Exit);
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, "Up");
+ screen.buttonPrint(Common::Point(159, CONTROLS_Y), COMMAND_HIGHLIGHTED, true, fixedText_Up);
else if (talk._moreTalkUp)
- screen.buttonPrint(Common::Point(159, CONTROLS_Y), COMMAND_FOREGROUND, true, "Up");
+ screen.buttonPrint(Common::Point(159, CONTROLS_Y), COMMAND_FOREGROUND, true, fixedText_Up);
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, "Down");
+ screen.buttonPrint(Common::Point(200, CONTROLS_Y), COMMAND_HIGHLIGHTED, true, fixedText_Down);
else if (talk._moreTalkDown)
- screen.buttonPrint(Common::Point(200, CONTROLS_Y), COMMAND_FOREGROUND, true, "Down");
+ screen.buttonPrint(Common::Point(200, CONTROLS_Y), COMMAND_FOREGROUND, true, fixedText_Down);
bool found = false;
for (_selector = talk._talkIndex; _selector < (int)talk._statements.size() && !found; ++_selector) {
@@ -1574,9 +1596,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, "Exit");
- screen.buttonPrint(Common::Point(159, CONTROLS_Y), COMMAND_NULL, true, "Up");
- screen.buttonPrint(Common::Point(200, CONTROLS_Y), COMMAND_NULL, true, "Down");
+ 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);
// If the reply is new, add it to the journal
if (!talk._talkHistory[talk._converseNum][_selector]) {
@@ -1615,15 +1637,18 @@ void ScalpelUserInterface::doTalkControl() {
people.setTalking(0);
if (!talk._statements[_selector]._voiceFile.empty() && sound._voices) {
- sound.playSound(talk._statements[_selector]._voiceFile, WAIT_RETURN_IMMEDIATELY);
+ sound.playSpeech(talk._statements[_selector]._voiceFile);
// Set voices as an indicator for waiting
sound._voices = 2;
- sound._speechOn = *sound._soundIsOn;
} else {
- sound._speechOn = false;
+ sound._speechPlaying = false;
}
+ if (IS_3DO)
+ // Trigger to play 3DO movie
+ talk.talk3DOMovieTrigger(0);
+
talk.waitForMore(talk._statements[_selector]._statement.size());
if (talk._talkToAbort)
return;
@@ -1670,9 +1695,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, "Exit");
+ screen.buttonPrint(Common::Point(119, CONTROLS_Y), COMMAND_FOREGROUND, true, fixedText_Exit);
else
- screen.buttonPrint(Common::Point(119, CONTROLS_Y), COMMAND_NULL, true, "Exit");
+ screen.buttonPrint(Common::Point(119, CONTROLS_Y), COMMAND_NULL, true, fixedText_Exit);
talk.displayTalk(true);
events.setCursor(ARROW);
@@ -1714,7 +1739,7 @@ void ScalpelUserInterface::doTalkControl() {
void ScalpelUserInterface::journalControl() {
Events &events = *_vm->_events;
- Journal &journal = *_vm->_journal;
+ ScalpelJournal &journal = *(ScalpelJournal *)_vm->_journal;
Scene &scene = *_vm->_scene;
Screen &screen = *_vm->_screen;
bool doneFlag = false;
@@ -1762,8 +1787,8 @@ void ScalpelUserInterface::journalControl() {
void ScalpelUserInterface::printObjectDesc(const Common::String &str, bool firstTime) {
Events &events = *_vm->_events;
- Inventory &inv = *_vm->_inventory;
- Screen &screen = *_vm->_screen;
+ ScalpelInventory &inv = *(ScalpelInventory *)_vm->_inventory;
+ ScalpelScreen &screen = *(ScalpelScreen *)_vm->_screen;
Talk &talk = *_vm->_talk;
if (str.hasPrefix("_")) {
@@ -1787,6 +1812,7 @@ void ScalpelUserInterface::printObjectDesc(const Common::String &str, bool first
// menu area, and draw the controls onto it
Surface tempSurface((*_controls)[0]._frame.w, (*_controls)[0]._frame.h);
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()));
@@ -1975,8 +2001,7 @@ void ScalpelUserInterface::summonWindow(bool slideUp, int height) {
Screen &screen = *_vm->_screen;
// Extract the window that's been drawn on the back buffer
- Surface tempSurface(SHERLOCK_SCREEN_WIDTH,
- (SHERLOCK_SCREEN_HEIGHT - height));
+ 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);
@@ -2055,13 +2080,14 @@ void ScalpelUserInterface::banishWindow(bool slideUp) {
}
void ScalpelUserInterface::checkUseAction(const UseType *use, const Common::String &invName,
- const char *const messages[], int objNum, bool giveMode) {
+ FixedTextActionId fixedTextActionId, int objNum, bool giveMode) {
Events &events = *_vm->_events;
+ FixedText &fixedText = *_vm->_fixedText;
Inventory &inv = *_vm->_inventory;
Scene &scene = *_vm->_scene;
Screen &screen = *_vm->_screen;
Talk &talk = *_vm->_talk;
- bool printed = messages == nullptr;
+ bool printed = fixedTextActionId == kFixedTextAction_Invalid;
if (objNum >= 1000) {
// Holmes was specified, so do nothing
@@ -2113,7 +2139,7 @@ void ScalpelUserInterface::checkUseAction(const UseType *use, const Common::Stri
if (!talk._talkToAbort) {
Object &obj = scene._bgShapes[objNum];
for (int idx = 0; idx < NAMES_COUNT && !talk._talkToAbort; ++idx) {
- if (obj.checkNameForCodes(action._names[idx], messages)) {
+ if (obj.checkNameForCodes(action._names[idx], fixedTextActionId)) {
if (!talk._talkToAbort)
printed = true;
}
@@ -2134,10 +2160,11 @@ void ScalpelUserInterface::checkUseAction(const UseType *use, const Common::Stri
if (giveMode) {
screen.print(Common::Point(0, INFO_LINE + 1), INFO_FOREGROUND, "No, thank you.");
- } else if (messages == nullptr) {
+ } else if (fixedTextActionId == kFixedTextAction_Invalid) {
screen.print(Common::Point(0, INFO_LINE + 1), INFO_FOREGROUND, "You can't do that.");
} else {
- screen.print(Common::Point(0, INFO_LINE + 1), INFO_FOREGROUND, "%s", messages[0]);
+ Common::String errorMessage = fixedText.getActionMessage(fixedTextActionId, 0);
+ screen.print(Common::Point(0, INFO_LINE + 1), INFO_FOREGROUND, "%s", errorMessage.c_str());
}
_infoFlag = true;
@@ -2147,136 +2174,15 @@ void ScalpelUserInterface::checkUseAction(const UseType *use, const Common::Stri
events.setCursor(ARROW);
}
-void ScalpelUserInterface::checkAction(ActionType &action, const char *const messages[], int objNum) {
- Events &events = *_vm->_events;
- People &people = *_vm->_people;
- Scene &scene = *_vm->_scene;
- Screen &screen = *_vm->_screen;
- Talk &talk = *_vm->_talk;
- Common::Point pt(-1, -1);
-
- if (objNum >= 1000)
- // Ignore actions done on characters
- return;
-
- if (!action._cAnimSpeed) {
- // Invalid action, to print error message
- _infoFlag = true;
- clearInfo();
- screen.print(Common::Point(0, INFO_LINE + 1), INFO_FOREGROUND, "%s", messages[action._cAnimNum]);
- _infoFlag = true;
-
- // Set how long to show the message
- _menuCounter = 30;
- } else {
- Object &obj = scene._bgShapes[objNum];
-
- int cAnimNum;
- if (action._cAnimNum == 0)
- // Really a 10
- cAnimNum = 9;
- else
- cAnimNum = action._cAnimNum - 1;
-
- int dir = -1;
- if (action._cAnimNum != 99) {
- CAnim &anim = scene._cAnim[cAnimNum];
-
- if (action._cAnimNum != 99) {
- if (action._cAnimSpeed & REVERSE_DIRECTION) {
- pt = anim._teleportPos;
- dir = anim._teleportDir;
- } else {
- pt = anim._goto;
- dir = anim._gotoDir;
- }
- }
- } else {
- pt = Common::Point(-1, -1);
- dir = -1;
- }
-
- // Has a value, so do action
- // Show wait cursor whilst walking to object and doing action
- events.setCursor(WAIT);
- bool printed = false;
-
- for (int nameIdx = 0; nameIdx < NAMES_COUNT; ++nameIdx) {
- if (action._names[nameIdx].hasPrefix("*") && action._names[nameIdx].size() >= 2
- && toupper(action._names[nameIdx][1]) == 'W') {
- if (obj.checkNameForCodes(Common::String(action._names[nameIdx].c_str() + 2), messages)) {
- if (!talk._talkToAbort)
- printed = true;
- }
- }
- }
-
- bool doCAnim = true;
- for (int nameIdx = 0; nameIdx < NAMES_COUNT; ++nameIdx) {
- if (action._names[nameIdx].hasPrefix("*") && action._names[nameIdx].size() >= 2) {
- char ch = toupper(action._names[nameIdx][1]);
-
- if (ch == 'T' || ch == 'B') {
- printed = true;
- if (pt.x != -1)
- // Holmes needs to walk to object before the action is done
- people.walkToCoords(pt, dir);
-
- if (!talk._talkToAbort) {
- // Ensure Holmes is on the exact intended location
- people[AL]._position = pt;
- people[AL]._sequenceNumber = dir;
- people.gotoStand(people[AL]);
-
- talk.talkTo(action._names[nameIdx].c_str() + 2);
- if (ch == 'T')
- doCAnim = false;
- }
- }
- }
- }
-
- if (doCAnim && !talk._talkToAbort) {
- if (pt.x != -1)
- // Holmes needs to walk to object before the action is done
- people.walkToCoords(pt, dir);
- }
-
- for (int nameIdx = 0; nameIdx < NAMES_COUNT; ++nameIdx) {
- if (action._names[nameIdx].hasPrefix("*") && action._names[nameIdx].size() >= 2
- && toupper(action._names[nameIdx][1]) == 'F') {
- if (obj.checkNameForCodes(action._names[nameIdx].c_str() + 2, messages)) {
- if (!talk._talkToAbort)
- printed = true;
- }
- }
- }
-
- if (doCAnim && !talk._talkToAbort && action._cAnimNum != 99)
- scene.startCAnim(cAnimNum, action._cAnimSpeed);
-
- if (!talk._talkToAbort) {
- for (int nameIdx = 0; nameIdx < NAMES_COUNT && !talk._talkToAbort; ++nameIdx) {
- if (obj.checkNameForCodes(action._names[nameIdx], messages)) {
- if (!talk._talkToAbort)
- printed = true;
- }
- }
-
- // Unless we're leaving the scene, print a "Done" message unless the printed flag has been set
- if (scene._goToScene != 1 && !printed && !talk._talkToAbort) {
- _infoFlag = true;
- clearInfo();
- screen.print(Common::Point(0, INFO_LINE + 1), INFO_FOREGROUND, "Done...");
-
- // Set how long to show the message
- _menuCounter = 30;
- }
- }
+void ScalpelUserInterface::offsetButton3DO(Common::Point &pt, int num) {
+ if (IS_3DO) {
+ if (num >= 0 && num <= 2)
+ pt.x += 15;
+ else if (num >= 6 && num <= 8)
+ pt.x -= 4;
+ else if (num >= 9 && num <= 11)
+ pt.x -= 8;
}
-
- // Reset cursor back to arrow
- events.setCursor(ARROW);
}
} // End of namespace Scalpel
diff --git a/engines/sherlock/scalpel/scalpel_user_interface.h b/engines/sherlock/scalpel/scalpel_user_interface.h
index 552bcf00c5..9a55189a66 100644
--- a/engines/sherlock/scalpel/scalpel_user_interface.h
+++ b/engines/sherlock/scalpel/scalpel_user_interface.h
@@ -49,9 +49,8 @@ class ScalpelUserInterface: public UserInterface {
private:
char _keyPress;
int _lookHelp;
- int _bgFound, _oldBgFound;
int _help, _oldHelp;
- char _key, _oldKey;
+ int _key, _oldKey;
int _temp, _oldTemp;
int _oldLook;
bool _keyboardInput;
@@ -85,7 +84,7 @@ private:
void lookScreen(const Common::Point &pt);
/**
- * Gets the item in the inventory the mouse is on and display's it's description
+ * Gets the item in the inventory the mouse is on and display's its description
*/
void lookInv();
@@ -136,15 +135,10 @@ private:
/**
* Checks to see whether a USE action is valid on the given object
*/
- void checkUseAction(const UseType *use, const Common::String &invName, const char *const messages[],
+ void checkUseAction(const UseType *use, const Common::String &invName, FixedTextActionId fixedTextActionId,
int objNum, bool giveMode);
/**
- * Called for OPEN, CLOSE, and MOVE actions are being done
- */
- void checkAction(ActionType &action, const char *const messages[], int objNum);
-
- /**
* Print the previously selected object's decription
*/
void printObjectDesc(const Common::String &str, bool firstTime);
@@ -172,6 +166,8 @@ public:
* of the highlighted object
*/
void examine();
+
+ void offsetButton3DO(Common::Point &pt, int num);
public:
/**
* Resets the user interface
diff --git a/engines/sherlock/scalpel/settings.cpp b/engines/sherlock/scalpel/settings.cpp
index aa8033d25e..f6769a4b99 100644
--- a/engines/sherlock/scalpel/settings.cpp
+++ b/engines/sherlock/scalpel/settings.cpp
@@ -22,7 +22,9 @@
#include "sherlock/sherlock.h"
#include "sherlock/scalpel/settings.h"
+#include "sherlock/scalpel/scalpel_screen.h"
#include "sherlock/scalpel/scalpel_user_interface.h"
+#include "sherlock/scalpel/scalpel.h"
namespace Sherlock {
@@ -56,7 +58,7 @@ static const char *const SETUP_NAMES[12] = {
void Settings::drawInteface(bool flag) {
People &people = *_vm->_people;
- Screen &screen = *_vm->_screen;
+ ScalpelScreen &screen = *(ScalpelScreen *)_vm->_screen;
Sound &sound = *_vm->_sound;
Music &music = *_vm->_music;
UserInterface &ui = *_vm->_ui;
@@ -138,7 +140,7 @@ void Settings::drawInteface(bool flag) {
int Settings::drawButtons(const Common::Point &pt, int _key) {
Events &events = *_vm->_events;
People &people = *_vm->_people;
- Screen &screen = *_vm->_screen;
+ ScalpelScreen &screen = *(ScalpelScreen *)_vm->_screen;
Music &music = *_vm->_music;
Sound &sound = *_vm->_sound;
UserInterface &ui = *_vm->_ui;
diff --git a/engines/sherlock/scalpel/tsage/logo.cpp b/engines/sherlock/scalpel/tsage/logo.cpp
index 239543b017..64539b941a 100644
--- a/engines/sherlock/scalpel/tsage/logo.cpp
+++ b/engines/sherlock/scalpel/tsage/logo.cpp
@@ -156,11 +156,13 @@ ScalpelEngine *Object::_vm;
Object::Object() {
_vm = nullptr;
- _isAnimating = false;
+ _isAnimating = _finished = false;
_frame = 0;
_numFrames = 0;
_frameChange = 0;
_angle = _changeCtr = 0;
+ _walkStartFrame = 0;
+ _majorDiff = _minorDiff = 0;
}
void Object::setVisage(int visage, int strip) {
@@ -221,8 +223,15 @@ void Object::update() {
Screen &screen = *_vm->_screen;
if (_visage.isLoaded()) {
- if (isMoving())
- move();
+ if (isMoving()) {
+ uint32 currTime = _vm->_events->getFrameCounter();
+ if (_walkStartFrame <= currTime) {
+ int moveRate = 10;
+ int frameInc = 60 / moveRate;
+ _walkStartFrame = currTime + frameInc;
+ move();
+ }
+ }
if (_isAnimating) {
if (_frame < _visage.getFrameCount())
@@ -304,7 +313,6 @@ bool Object::isMoving() const {
void Object::move() {
Common::Point currPos = _position;
Common::Point moveDiff(5, 3);
- int yDiff = 0;
int percent = 100;
if (dontMove())
@@ -335,9 +343,7 @@ void Object::move() {
currPos.y += ySign;
_majorDiff -= ABS(xAmount);
-
- }
- else {
+ } else {
int yAmount = _moveSign.y * moveDiff.y * percent / 100;
if (!yAmount)
yAmount = _moveSign.y;
@@ -387,15 +393,16 @@ bool Logo::show(ScalpelEngine *vm) {
while (!logo->finished()) {
logo->nextFrame();
- events.wait(2);
- events.setButtonState();
-
// Erase areas from previous frame, and update and re-draw objects
for (int idx = 0; idx < 4; ++idx)
logo->_objects[idx].erase();
for (int idx = 0; idx < 4; ++idx)
logo->_objects[idx].update();
+ events.delay(10);
+ events.setButtonState();
+ ++logo->_frameCounter;
+
interrupted = vm->shouldQuit() || events.kbHit() || events._pressed;
if (interrupted) {
// Keyboard or mouse button pressed, so break out of logo display
@@ -412,8 +419,21 @@ Logo::Logo(ScalpelEngine *vm) : _vm(vm), _lib("sf3.rlb") {
Object::_vm = vm;
Visage::_tLib = &_lib;
+ _finished = false;
+
// Initialize counter
_counter = 0;
+
+ // Initialize wait frame counters
+ _waitFrames = 0;
+ _waitStartFrame = 0;
+
+ // Initialize animation counters
+ _animateObject = 0;
+ _animateStartFrame = 0;
+ _animateFrameDelay = 0;
+ _animateFrames = NULL;
+ _animateFrame = 0;
// Save a copy of the original palette
_vm->_screen->getPalette(_originalPalette);
@@ -437,12 +457,55 @@ Logo::~Logo() {
}
bool Logo::finished() const {
- return _counter >= 442;
+ return _finished;
}
+const AnimationFrame handFrames[] = {
+ { 1, 33, 91 }, { 2, 44, 124 }, { 3, 64, 153 }, { 4, 87, 174 },
+ { 5, 114, 191 }, { 6, 125, 184 }, { 7, 154, 187 }, { 8, 181, 182 },
+ { 9, 191, 167 }, { 10, 190, 150 }, { 11, 182, 139 }, { 11, 170, 130 },
+ { 11, 158, 121 }, { 0, 0, 0 }
+};
+
+const AnimationFrame companyFrames[] = {
+ { 1, 155, 94 }, { 2, 155, 94 }, { 3, 155, 94 }, { 4, 155, 94 },
+ { 5, 155, 94 }, { 6, 155, 94 }, { 7, 155, 94 }, { 8, 155, 94 },
+ { 0, 0, 0 }
+};
+
void Logo::nextFrame() {
Screen &screen = *_vm->_screen;
+ if (_waitFrames) {
+ uint32 currFrame = _frameCounter;
+ if (currFrame - _waitStartFrame < _waitFrames) {
+ return;
+ }
+ _waitStartFrame = 0;
+ _waitFrames = 0;
+ }
+
+ if (_animateFrames) {
+ uint32 currFrame = _frameCounter;
+ if (currFrame > _animateStartFrame + _animateFrameDelay) {
+ AnimationFrame animationFrame = _animateFrames[_animateFrame];
+ if (animationFrame.frame) {
+ _objects[_animateObject]._frame = animationFrame.frame;
+ _objects[_animateObject]._position = Common::Point(animationFrame.x, animationFrame.y);
+ _animateStartFrame += _animateFrameDelay;
+ _animateFrame++;
+ } else {
+ _animateObject = 0;
+ _animateFrameDelay = 0;
+ _animateFrames = NULL;
+ _animateStartFrame = 0;
+ _animateFrame = 0;
+ }
+ }
+ if (_animateFrames)
+ return;
+ }
+
switch (_counter++) {
case 0:
// Load the background and fade it in
@@ -480,160 +543,87 @@ void Logo::nextFrame() {
// Fade out the background but keep the shapes visible
fade(_palette2);
screen._backBuffer1.clear();
- screen.clear();
}
+ waitFrames(10);
break;
- case 13: {
+ case 4:
// Load the new palette
byte palette[PALETTE_SIZE];
Common::copy(&_palette2[0], &_palette2[PALETTE_SIZE], &palette[0]);
_lib.getPalette(palette, 12);
+ screen.clear();
screen.setPalette(palette);
- break;
- }
- case 14:
+ // Morph into the EA logo
_objects[0].setVisage(12, 1);
_objects[0]._frame = 1;
_objects[0]._numFrames = 7;
+ _objects[0].setAnimMode(true);
_objects[0]._position = Common::Point(170, 142);
_objects[0].setDestination(Common::Point(158, 71));
break;
- case 15:
+ case 5:
// Wait until the logo has expanded upwards to form EA logo
if (_objects[0].isMoving())
--_counter;
break;
- case 16:
+ case 6:
fade(_palette3, 40);
break;
- case 20:
+ case 7:
// Show the 'Electronic Arts' company name
_objects[1].setVisage(14, 1);
_objects[1]._frame = 1;
_objects[1]._position = Common::Point(152, 98);
+ waitFrames(120);
break;
- case 140:
+ case 8:
// Start sequence of positioning and size hand cursor in an arc
_objects[2].setVisage(18, 1);
- _objects[2]._frame = 1;
- _objects[2]._position = Common::Point(33, 91);
- break;
-
- case 145:
- _objects[2]._frame = 2;
- _objects[2]._position = Common::Point(44, 124);
- break;
-
- case 150:
- _objects[2]._frame = 3;
- _objects[2]._position = Common::Point(64, 153);
- break;
-
- case 155:
- _objects[2]._frame = 4;
- _objects[2]._position = Common::Point(87, 174);
- break;
-
- case 160:
- _objects[2]._frame = 5;
- _objects[2]._position = Common::Point(114, 191);
- break;
-
- case 165:
- _objects[2]._frame = 6;
- _objects[2]._position = Common::Point(125, 184);
- break;
-
- case 170:
- _objects[2]._frame = 7;
- _objects[2]._position = Common::Point(154, 187);
- break;
-
- case 175:
- _objects[2]._frame = 8;
- _objects[2]._position = Common::Point(181, 182);
- break;
-
- case 180:
- _objects[2]._frame = 9;
- _objects[2]._position = Common::Point(191, 167);
- break;
-
- case 185:
- _objects[2]._frame = 10;
- _objects[2]._position = Common::Point(190, 150);
- break;
-
- case 190:
- _objects[2]._frame = 11;
- _objects[2]._position = Common::Point(182, 139);
- break;
-
- case 195:
- _objects[2]._frame = 11;
- _objects[2]._position = Common::Point(170, 130);
- break;
-
- case 200:
- _objects[2]._frame = 11;
- _objects[2]._position = Common::Point(158, 121);
+ startAnimation(2, 5, &handFrames[0]);
break;
- case 205:
+ case 9:
// Show a highlighting of the company name
+ _objects[1].remove();
+ _objects[2].erase();
_objects[2].remove();
_objects[3].setVisage(19, 1);
- _objects[3]._position = Common::Point(155, 94);
+ startAnimation(3, 8, &companyFrames[0]);
break;
- case 213:
- _objects[3]._frame = 2;
- _objects[3]._position = Common::Point(155, 94);
+ case 10:
+ waitFrames(180);
break;
- case 221:
- _objects[1].remove();
+ case 11:
+ _finished = true;
break;
- case 222:
- _objects[3]._frame = 3;
- _objects[3]._position = Common::Point(155, 94);
- break;
-
- case 230:
- _objects[3]._frame = 4;
- _objects[3]._position = Common::Point(155, 94);
- break;
-
- case 238:
- _objects[3]._frame = 5;
- _objects[3]._position = Common::Point(155, 94);
- break;
-
- case 246:
- _objects[3]._frame = 6;
- _objects[3]._position = Common::Point(155, 94);
+ default:
break;
+ }
+}
- case 254:
- _objects[3]._frame = 7;
- _objects[3]._position = Common::Point(155, 94);
- break;
+void Logo::waitFrames(uint frames) {
+ _waitFrames = frames;
+ _waitStartFrame = _frameCounter;
+}
- case 262:
- _objects[3]._frame = 8;
- _objects[3]._position = Common::Point(155, 94);
- break;
+void Logo::startAnimation(uint object, uint frameDelay, const AnimationFrame *frames) {
+ _animateObject = object;
+ _animateFrameDelay = frameDelay;
+ _animateFrames = frames;
+ _animateStartFrame = _frameCounter;
+ _animateFrame = 1;
- default:
- break;
- }
+ _objects[object]._frame = frames[0].frame;
+ _objects[object]._position = Common::Point(frames[0].x, frames[0].y);
}
void Logo::loadBackground() {
diff --git a/engines/sherlock/scalpel/tsage/logo.h b/engines/sherlock/scalpel/tsage/logo.h
index 68b7353a15..8e47ea42a1 100644
--- a/engines/sherlock/scalpel/tsage/logo.h
+++ b/engines/sherlock/scalpel/tsage/logo.h
@@ -185,16 +185,30 @@ public:
void remove() { _visage.clear(); }
};
+struct AnimationFrame {
+ int frame;
+ int x;
+ int y;
+};
+
class Logo {
private:
ScalpelEngine *_vm;
TLib _lib;
- int _counter;
+ int _counter, _frameCounter;
+ bool _finished;
byte _originalPalette[PALETTE_SIZE];
byte _palette1[PALETTE_SIZE];
byte _palette2[PALETTE_SIZE];
byte _palette3[PALETTE_SIZE];
Object _objects[4];
+ uint _waitFrames;
+ uint32 _waitStartFrame;
+ int _animateObject;
+ uint32 _animateStartFrame;
+ uint _animateFrameDelay;
+ const AnimationFrame *_animateFrames;
+ uint _animateFrame;
Logo(ScalpelEngine *vm);
~Logo();
@@ -204,6 +218,19 @@ private:
bool finished() const;
/**
+ * Wait for a number of frames. Note that the frame count in _events is
+ * not the same as the number of calls to nextFrame().
+ */
+ void waitFrames(uint frames);
+
+ /**
+ * Start an animation sequence. Used for sequences that are described
+ * one frame at a time because they do unusual things, or run at
+ * unusual rates.
+ */
+ void startAnimation(uint object, uint frameDelay, const AnimationFrame *frames);
+
+ /**
* Load the background for the scene
*/
void loadBackground();
diff --git a/engines/sherlock/scene.cpp b/engines/sherlock/scene.cpp
index 76fb7ae3a7..4e40032df9 100644
--- a/engines/sherlock/scene.cpp
+++ b/engines/sherlock/scene.cpp
@@ -22,21 +22,16 @@
#include "sherlock/scene.h"
#include "sherlock/sherlock.h"
+#include "sherlock/screen.h"
#include "sherlock/scalpel/scalpel.h"
+#include "sherlock/scalpel/scalpel_people.h"
#include "sherlock/scalpel/scalpel_scene.h"
-#include "sherlock/screen.h"
#include "sherlock/tattoo/tattoo.h"
#include "sherlock/tattoo/tattoo_scene.h"
+#include "sherlock/tattoo/tattoo_user_interface.h"
namespace Sherlock {
-static const int FS_TRANS[8] = {
- STOP_UP, STOP_UPRIGHT, STOP_RIGHT, STOP_DOWNRIGHT, STOP_DOWN,
- STOP_DOWNLEFT, STOP_LEFT, STOP_UPLEFT
-};
-
-/*----------------------------------------------------------------*/
-
BgFileHeader::BgFileHeader() {
_numStructs = -1;
_numImages = -1;
@@ -82,6 +77,16 @@ void BgFileHeaderInfo::load(Common::SeekableReadStream &s) {
_filename = Common::String(buffer);
}
+void BgFileHeaderInfo::load3DO(Common::SeekableReadStream &s) {
+ _filesize = s.readUint32BE();
+ _maxFrames = s.readByte();
+
+ char buffer[9];
+ s.read(buffer, 9);
+ _filename = Common::String(buffer);
+ s.skip(2); // only on 3DO!
+}
+
/*----------------------------------------------------------------*/
void Exit::load(Common::SeekableReadStream &s, bool isRoseTattoo) {
@@ -102,14 +107,31 @@ void Exit::load(Common::SeekableReadStream &s, bool isRoseTattoo) {
if (!isRoseTattoo)
_allow = s.readSint16LE();
- _people.x = s.readSint16LE();
- _people.y = s.readSint16LE();
- _peopleDir = s.readUint16LE();
+ _newPosition.x = s.readSint16LE();
+ _newPosition.y = s.readSint16LE();
+ _newPosition._facing = s.readUint16LE();
if (isRoseTattoo)
_allow = s.readSint16LE();
}
+void Exit::load3DO(Common::SeekableReadStream &s) {
+ left = s.readSint16BE();
+ top = s.readSint16BE();
+ setWidth(s.readUint16BE());
+ setHeight(s.readUint16BE());
+
+ _image = 0;
+ _scene = s.readSint16BE();
+
+ _allow = s.readSint16BE();
+
+ _newPosition.x = s.readSint16BE();
+ _newPosition.y = s.readSint16BE();
+ _newPosition._facing = s.readUint16BE();
+ s.skip(2); // Filler
+}
+
/*----------------------------------------------------------------*/
void SceneEntry::load(Common::SeekableReadStream &s) {
@@ -119,6 +141,13 @@ void SceneEntry::load(Common::SeekableReadStream &s) {
_allow = s.readByte();
}
+void SceneEntry::load3DO(Common::SeekableReadStream &s) {
+ _startPosition.x = s.readSint16BE();
+ _startPosition.y = s.readSint16BE();
+ _startDir = s.readByte();
+ _allow = s.readByte();
+}
+
void SceneSound::load(Common::SeekableReadStream &s) {
char buffer[9];
s.read(buffer, 8);
@@ -128,6 +157,10 @@ void SceneSound::load(Common::SeekableReadStream &s) {
_priority = s.readByte();
}
+void SceneSound::load3DO(Common::SeekableReadStream &s) {
+ load(s);
+}
+
/*----------------------------------------------------------------*/
int ObjectArray::indexOf(const Object &obj) const {
@@ -153,6 +186,18 @@ void ScaleZone::load(Common::SeekableReadStream &s) {
/*----------------------------------------------------------------*/
+void WalkArray::load(Common::SeekableReadStream &s, bool isRoseTattoo) {
+ _pointsCount = (int8)s.readByte();
+
+ for (int idx = 0; idx < _pointsCount; ++idx) {
+ int x = s.readSint16LE();
+ int y = isRoseTattoo ? s.readSint16LE() : s.readByte();
+ push_back(Common::Point(x, y));
+ }
+}
+
+/*----------------------------------------------------------------*/
+
Scene *Scene::init(SherlockEngine *vm) {
if (vm->getGameID() == GType_SerratedScalpel)
return new Scalpel::ScalpelScene(vm);
@@ -161,25 +206,32 @@ Scene *Scene::init(SherlockEngine *vm) {
}
Scene::Scene(SherlockEngine *vm): _vm(vm) {
- for (int idx = 0; idx < SCENES_COUNT; ++idx)
- Common::fill(&_sceneStats[idx][0], &_sceneStats[idx][65], false);
+ _sceneStats = new bool *[SCENES_COUNT];
+ _sceneStats[0] = new bool[SCENES_COUNT * (MAX_BGSHAPES + 1)];
+ Common::fill(&_sceneStats[0][0], &_sceneStats[0][SCENES_COUNT * (MAX_BGSHAPES + 1)], false);
+ for (int idx = 1; idx < SCENES_COUNT; ++idx) {
+ _sceneStats[idx] = _sceneStats[idx - 1] + (MAX_BGSHAPES + 1);
+ }
+
_currentScene = -1;
_goToScene = -1;
_loadingSavedGame = false;
_walkedInScene = false;
_version = 0;
- _lzwMode = false;
+ _compressed = false;
_invGraphicItems = 0;
_cAnimFramePause = 0;
_restoreFlag = false;
_animating = 0;
_doBgAnimDone = true;
_tempFadeStyle = 0;
- _exitZone = -1;
+ _doBgAnimDone = false;
}
Scene::~Scene() {
freeScene();
+ delete[] _sceneStats[0];
+ delete[] _sceneStats;
}
void Scene::selectScene() {
@@ -193,12 +245,10 @@ void Scene::selectScene() {
ui._windowOpen = ui._infoFlag = false;
ui._menuMode = STD_MODE;
- // Free any previous scene
- freeScene();
-
// Load the scene
Common::String sceneFile = Common::String::format("res%02d", _goToScene);
- _rrmName = Common::String::format("res%02d.rrm", _goToScene);
+ // _rrmName gets set during loadScene()
+ // _rrmName is for ScalpelScene::startCAnim
_currentScene = _goToScene;
_goToScene = -1;
@@ -210,8 +260,8 @@ void Scene::selectScene() {
_tempFadeStyle = 0;
}
- people._walkDest = Common::Point(people[AL]._position.x / FIXED_INT_MULTIPLIER,
- people[AL]._position.y / FIXED_INT_MULTIPLIER);
+ people[HOLMES]._walkDest = Common::Point(people[HOLMES]._position.x / FIXED_INT_MULTIPLIER,
+ people[HOLMES]._position.y / FIXED_INT_MULTIPLIER);
_restoreFlag = true;
events.clearEvents();
@@ -226,7 +276,9 @@ void Scene::freeScene() {
if (_currentScene == -1)
return;
+ _vm->_ui->clearWindow();
_vm->_talk->freeTalkVars();
+ _vm->_talk->clearSequences();
_vm->_inventory->freeInv();
_vm->_music->freeSong();
_vm->_sound->freeLoadedSounds();
@@ -238,7 +290,7 @@ void Scene::freeScene() {
_sequenceBuffer.clear();
_descText.clear();
- _walkData.clear();
+ _walkPoints.clear();
_cAnim.clear();
_bgShapes.clear();
_zones.clear();
@@ -253,14 +305,11 @@ void Scene::freeScene() {
bool Scene::loadScene(const Common::String &filename) {
Events &events = *_vm->_events;
- Map &map = *_vm->_map;
Music &music = *_vm->_music;
People &people = *_vm->_people;
Resources &res = *_vm->_res;
SaveManager &saves = *_vm->_saves;
Screen &screen = *_vm->_screen;
- Sound &sound = *_vm->_sound;
- Talk &talk = *_vm->_talk;
UserInterface &ui = *_vm->_ui;
bool flag;
@@ -276,175 +325,492 @@ bool Scene::loadScene(const Common::String &filename) {
_cAnim.clear();
_sequenceBuffer.clear();
- // Check if it's a scene we need to keep trakc track of how many times we've visited
- for (int idx = (int)_sceneTripCounters.size() - 1; idx >= 0; --idx) {
- if (_sceneTripCounters[idx]._sceneNumber == _currentScene) {
- if (--_sceneTripCounters[idx]._numTimes == 0) {
- _vm->setFlags(_sceneTripCounters[idx]._flag);
- _sceneTripCounters.remove_at(idx);
+ //
+ // Load the room resource file for the scene
+ //
+
+ if (!IS_3DO) {
+ // PC version
+ Common::String roomFilename = filename + ".rrm";
+ _roomFilename = roomFilename;
+
+ flag = _vm->_res->exists(roomFilename);
+ if (flag) {
+ Common::SeekableReadStream *rrmStream = _vm->_res->load(roomFilename);
+
+ rrmStream->seek(39);
+ if (IS_SERRATED_SCALPEL) {
+ _version = rrmStream->readByte();
+ _compressed = _version == 10;
+ } else {
+ _compressed = rrmStream->readByte() > 0;
}
- }
- }
- if (IS_ROSE_TATTOO) {
- // Set the NPC paths for the scene
- setNPCPath(0);
-
- // Handle loading music for the scene
- if (sound._midiDrvLoaded) {
- if (talk._scriptMoreFlag != 1 && talk._scriptMoreFlag != 3)
- sound._nextSongName = Common::String::format("res%02d", _currentScene);
-
- // If it's a new song, then start it up
- if (sound._currentSongName.compareToIgnoreCase(sound._nextSongName)) {
- if (music.loadSong(sound._nextSongName)) {
- sound.setMIDIVolume(sound._musicVolume);
- if (music._musicOn)
- music.startSong();
+ // Go to header and read it in
+ rrmStream->seek(rrmStream->readUint32LE());
+
+ BgFileHeader bgHeader;
+ bgHeader.load(*rrmStream, IS_ROSE_TATTOO);
+ _invGraphicItems = bgHeader._numImages + 1;
+
+ if (IS_ROSE_TATTOO) {
+ // Resize the screen if necessary
+ int fullWidth = SHERLOCK_SCREEN_WIDTH + bgHeader._scrollSize;
+ if (screen._backBuffer1.w() != fullWidth) {
+ screen._backBuffer1.create(fullWidth, SHERLOCK_SCREEN_HEIGHT);
+ screen._backBuffer2.create(fullWidth, SHERLOCK_SCREEN_HEIGHT);
}
- }
- }
- }
- //
- // Load the room resource file for the scene
- //
+ // Handle initializing the palette
+ screen.initPaletteFade(bgHeader._bytesWritten);
+ rrmStream->read(screen._cMap, PALETTE_SIZE);
+ paletteLoaded();
+ screen.translatePalette(screen._cMap);
- Common::String rrmFile = filename + ".rrm";
- flag = _vm->_res->exists(rrmFile);
- if (flag) {
- Common::SeekableReadStream *rrmStream = _vm->_res->load(rrmFile);
+ // Read in background
+ if (_compressed) {
+ res.decompress(*rrmStream, (byte *)screen._backBuffer1.getPixels(), fullWidth * SHERLOCK_SCREEN_HEIGHT);
+ } else {
+ rrmStream->read(screen._backBuffer1.getPixels(), fullWidth * SHERLOCK_SCREEN_HEIGHT);
+ }
+ }
- rrmStream->seek(39);
- if (IS_SERRATED_SCALPEL) {
- _version = rrmStream->readByte();
- _lzwMode = _version == 10;
- } else {
- _lzwMode = rrmStream->readByte() > 0;
- }
+ // Read in the shapes header info
+ Common::Array<BgFileHeaderInfo> bgInfo;
+ bgInfo.resize(bgHeader._numStructs);
- // Go to header and read it in
- rrmStream->seek(rrmStream->readUint32LE());
+ for (uint idx = 0; idx < bgInfo.size(); ++idx)
+ bgInfo[idx].load(*rrmStream);
- BgFileHeader bgHeader;
- bgHeader.load(*rrmStream, IS_ROSE_TATTOO);
- _invGraphicItems = bgHeader._numImages + 1;
+ // Read information
+ if (IS_ROSE_TATTOO) {
+ // Load shapes
+ Common::SeekableReadStream *infoStream = !_compressed ? rrmStream : res.decompress(*rrmStream, bgHeader._numStructs * 625);
- if (IS_ROSE_TATTOO) {
- screen.initPaletteFade(bgHeader._bytesWritten);
- rrmStream->read(screen._cMap, PALETTE_SIZE);
- screen.translatePalette(screen._cMap);
- screen.setupBGArea(screen._cMap);
+ _bgShapes.resize(bgHeader._numStructs);
+ for (int idx = 0; idx < bgHeader._numStructs; ++idx)
+ _bgShapes[idx].load(*infoStream, true);
- screen.initScrollVars();
+ if (_compressed)
+ delete infoStream;
- // Read in background
- if (_lzwMode) {
- res.decompress(*rrmStream, (byte *)screen._backBuffer1.getPixels(), SHERLOCK_SCREEN_WIDTH * SHERLOCK_SCREEN_HEIGHT);
+ // Load description text
+ _descText.resize(bgHeader._descSize);
+ if (_compressed)
+ res.decompress(*rrmStream, (byte *)&_descText[0], bgHeader._descSize);
+ else
+ rrmStream->read(&_descText[0], bgHeader._descSize);
+
+ // Load sequences
+ _sequenceBuffer.resize(bgHeader._seqSize);
+ if (_compressed)
+ res.decompress(*rrmStream, &_sequenceBuffer[0], bgHeader._seqSize);
+ else
+ rrmStream->read(&_sequenceBuffer[0], bgHeader._seqSize);
+ } else if (!_compressed) {
+ // Serrated Scalpel uncompressed info
+ _bgShapes.resize(bgHeader._numStructs);
+ for (int idx = 0; idx < bgHeader._numStructs; ++idx)
+ _bgShapes[idx].load(*rrmStream, false);
+
+ if (bgHeader._descSize) {
+ _descText.resize(bgHeader._descSize);
+ rrmStream->read(&_descText[0], bgHeader._descSize);
+ }
+
+ if (bgHeader._seqSize) {
+ _sequenceBuffer.resize(bgHeader._seqSize);
+ rrmStream->read(&_sequenceBuffer[0], bgHeader._seqSize);
+ }
} else {
- rrmStream->read(screen._backBuffer1.getPixels(), SHERLOCK_SCREEN_WIDTH * SHERLOCK_SCREEN_HEIGHT);
+ // Serrated Scalpel compressed info
+ Common::SeekableReadStream *infoStream;
+
+ // Read shapes
+ infoStream = Resources::decompressLZ(*rrmStream, bgHeader._numStructs * 569);
+
+ _bgShapes.resize(bgHeader._numStructs);
+ for (int idx = 0; idx < bgHeader._numStructs; ++idx)
+ _bgShapes[idx].load(*infoStream, false);
+
+ delete infoStream;
+
+ // Read description texts
+ if (bgHeader._descSize) {
+ infoStream = Resources::decompressLZ(*rrmStream, bgHeader._descSize);
+
+ _descText.resize(bgHeader._descSize);
+ infoStream->read(&_descText[0], bgHeader._descSize);
+
+ delete infoStream;
+ }
+
+ // Read sequences
+ if (bgHeader._seqSize) {
+ infoStream = Resources::decompressLZ(*rrmStream, bgHeader._seqSize);
+
+ _sequenceBuffer.resize(bgHeader._seqSize);
+ infoStream->read(&_sequenceBuffer[0], bgHeader._seqSize);
+
+ delete infoStream;
+ }
}
- }
- // Read in the shapes header info
- Common::Array<BgFileHeaderInfo> bgInfo;
- bgInfo.resize(bgHeader._numStructs);
+ // Set up the list of images used by the scene
+ _images.resize(bgHeader._numImages + 1);
+ for (int idx = 0; idx < bgHeader._numImages; ++idx) {
+ _images[idx + 1]._filesize = bgInfo[idx]._filesize;
+ _images[idx + 1]._maxFrames = bgInfo[idx]._maxFrames;
- for (uint idx = 0; idx < bgInfo.size(); ++idx)
- bgInfo[idx].load(*rrmStream);
+ // Read in the image data
+ Common::SeekableReadStream *imageStream = _compressed ?
+ res.decompress(*rrmStream, bgInfo[idx]._filesize) :
+ rrmStream->readStream(bgInfo[idx]._filesize);
+
+ _images[idx + 1]._images = new ImageFile(*imageStream);
- // Read information
- if (IS_ROSE_TATTOO) {
- // Load shapes
- Common::SeekableReadStream *infoStream = !_lzwMode ? rrmStream : res.decompress(*rrmStream, bgHeader._numStructs * 625);
+ delete imageStream;
+ }
- _bgShapes.resize(bgHeader._numStructs);
- for (int idx = 0; idx < bgHeader._numStructs; ++idx)
- _bgShapes[idx].load(*infoStream, _vm->getGameID() == GType_RoseTattoo);
+ // Set up the bgShapes
+ for (int idx = 0; idx < bgHeader._numStructs; ++idx) {
+ _bgShapes[idx]._images = _images[_bgShapes[idx]._misc]._images;
+ _bgShapes[idx]._imageFrame = !_bgShapes[idx]._images ? (ImageFrame *)nullptr :
+ &(*_bgShapes[idx]._images)[0];
+
+ _bgShapes[idx]._examine = Common::String(&_descText[_bgShapes[idx]._descOffset]);
+ _bgShapes[idx]._sequences = &_sequenceBuffer[_bgShapes[idx]._sequenceOffset];
+ _bgShapes[idx]._misc = 0;
+ _bgShapes[idx]._seqCounter = 0;
+ _bgShapes[idx]._seqCounter2 = 0;
+ _bgShapes[idx]._seqStack = 0;
+ _bgShapes[idx]._frameNumber = -1;
+ _bgShapes[idx]._oldPosition = Common::Point(0, 0);
+ _bgShapes[idx]._oldSize = Common::Point(1, 1);
+ }
- if (_lzwMode)
- delete infoStream;
+ // Load in cAnim list
+ _cAnim.clear();
+ if (bgHeader._numcAnimations) {
+ int animSize = IS_SERRATED_SCALPEL ? 65 : 47;
+ Common::SeekableReadStream *cAnimStream = _compressed ?
+ res.decompress(*rrmStream, animSize * bgHeader._numcAnimations) :
+ rrmStream->readStream(animSize * bgHeader._numcAnimations);
+
+ // Load cAnim offset table as well
+ uint32 *cAnimOffsetTablePtr = new uint32[bgHeader._numcAnimations];
+ uint32 *cAnimOffsetPtr = cAnimOffsetTablePtr;
+ memset(cAnimOffsetTablePtr, 0, bgHeader._numcAnimations * sizeof(uint32));
+ if (IS_SERRATED_SCALPEL) {
+ // Save current stream offset
+ int32 curOffset = rrmStream->pos();
+ rrmStream->seek(44); // Seek to cAnim-Offset-Table
+ for (uint16 curCAnim = 0; curCAnim < bgHeader._numcAnimations; curCAnim++) {
+ *cAnimOffsetPtr = rrmStream->readUint32LE();
+ cAnimOffsetPtr++;
+ }
+ // Seek back to original stream offset
+ rrmStream->seek(curOffset);
+ }
+ // TODO: load offset table for Rose Tattoo as well
- // Load description text
- _descText.resize(bgHeader._descSize);
- if (_lzwMode)
- res.decompress(*rrmStream, (byte *)&_descText[0], bgHeader._descSize);
- else
- rrmStream->read(&_descText[0], bgHeader._descSize);
-
- // Load sequences
- _sequenceBuffer.resize(bgHeader._seqSize);
- if (_lzwMode)
- res.decompress(*rrmStream, &_sequenceBuffer[0], bgHeader._seqSize);
- else
- rrmStream->read(&_sequenceBuffer[0], bgHeader._seqSize);
- } else if (!_lzwMode) {
- // Serrated Scalpel uncompressed info
- _bgShapes.resize(bgHeader._numStructs);
- for (int idx = 0; idx < bgHeader._numStructs; ++idx)
- _bgShapes[idx].load(*rrmStream, false);
-
- if (bgHeader._descSize) {
- _descText.resize(bgHeader._descSize);
- rrmStream->read(&_descText[0], bgHeader._descSize);
+ // Go to the start of the cAnimOffsetTable
+ cAnimOffsetPtr = cAnimOffsetTablePtr;
+
+ _cAnim.resize(bgHeader._numcAnimations);
+ for (uint idx = 0; idx < _cAnim.size(); ++idx) {
+ _cAnim[idx].load(*cAnimStream, IS_ROSE_TATTOO, *cAnimOffsetPtr);
+ cAnimOffsetPtr++;
+ }
+
+ delete cAnimStream;
+ delete[] cAnimOffsetTablePtr;
}
- if (bgHeader._seqSize) {
- _sequenceBuffer.resize(bgHeader._seqSize);
- rrmStream->read(&_sequenceBuffer[0], bgHeader._seqSize);
+
+
+ // Read in the room bounding areas
+ int size = rrmStream->readUint16LE();
+ Common::SeekableReadStream *boundsStream = !_compressed ? rrmStream :
+ res.decompress(*rrmStream, size);
+
+ _zones.resize(size / 10);
+ for (uint idx = 0; idx < _zones.size(); ++idx) {
+ _zones[idx].left = boundsStream->readSint16LE();
+ _zones[idx].top = boundsStream->readSint16LE();
+ _zones[idx].setWidth(boundsStream->readSint16LE() + 1);
+ _zones[idx].setHeight(boundsStream->readSint16LE() + 1);
+ boundsStream->skip(2); // Skip unused scene number field
}
- } else {
- // Serrated Scalpel compressed info
- Common::SeekableReadStream *infoStream;
- // Read shapes
- infoStream = Resources::decompressLZ(*rrmStream, bgHeader._numStructs * 569);
+ if (_compressed)
+ delete boundsStream;
- _bgShapes.resize(bgHeader._numStructs);
- for (int idx = 0; idx < bgHeader._numStructs; ++idx)
- _bgShapes[idx].load(*infoStream, false);
+ // Ensure we've reached the path version byte
+ if (rrmStream->readByte() != (IS_SERRATED_SCALPEL ? 254 : 251))
+ error("Invalid scene path data");
- delete infoStream;
+ // Load the walk directory and walk data
+ assert(_zones.size() < MAX_ZONES);
- // Read description texts
- if (bgHeader._descSize) {
- infoStream = Resources::decompressLZ(*rrmStream, bgHeader._descSize);
- _descText.resize(bgHeader._descSize);
- infoStream->read(&_descText[0], bgHeader._descSize);
+ for (uint idx1 = 0; idx1 < _zones.size(); ++idx1) {
+ Common::fill(&_walkDirectory[idx1][0], &_walkDirectory[idx1][MAX_ZONES], 0);
+ for (uint idx2 = 0; idx2 < _zones.size(); ++idx2)
+ _walkDirectory[idx1][idx2] = rrmStream->readSint16LE();
+ }
- delete infoStream;
+ // Read in the walk data
+ size = rrmStream->readUint16LE();
+ Common::SeekableReadStream *walkStream = !_compressed ? rrmStream :
+ 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);
}
- // Read sequences
- if (bgHeader._seqSize) {
- infoStream = Resources::decompressLZ(*rrmStream, bgHeader._seqSize);
+ 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)
+ continue;
+
+ uint dataIndex = 0;
+ while (dataIndex < _walkPoints.size() && _walkPoints[dataIndex]._fileOffset != fileOffset)
+ ++dataIndex;
+ assert(dataIndex < _walkPoints.size());
+ _walkDirectory[idx1][idx2] = dataIndex;
+ }
+ }
- _sequenceBuffer.resize(bgHeader._seqSize);
- infoStream->read(&_sequenceBuffer[0], bgHeader._seqSize);
+ if (IS_ROSE_TATTOO) {
+ // Read in the entrance
+ _entrance.load(*rrmStream);
- delete infoStream;
+ // Load scale zones
+ _scaleZones.resize(rrmStream->readByte());
+ for (uint idx = 0; idx < _scaleZones.size(); ++idx)
+ _scaleZones[idx].load(*rrmStream);
+ }
+
+ // Read in the exits
+ int numExits = rrmStream->readByte();
+ _exits.resize(numExits);
+
+ for (int idx = 0; idx < numExits; ++idx)
+ _exits[idx].load(*rrmStream, IS_ROSE_TATTOO);
+
+ if (IS_SERRATED_SCALPEL)
+ // Read in the entrance
+ _entrance.load(*rrmStream);
+
+ // Initialize sound list
+ int numSounds = rrmStream->readByte();
+ _sounds.resize(numSounds);
+
+ for (int idx = 0; idx < numSounds; ++idx)
+ _sounds[idx].load(*rrmStream);
+
+ loadSceneSounds();
+
+ if (IS_ROSE_TATTOO) {
+ // Load the object sound list
+ char buffer[27];
+
+ _objSoundList.resize(rrmStream->readUint16LE());
+ for (uint idx = 0; idx < _objSoundList.size(); ++idx) {
+ rrmStream->read(buffer, 27);
+ _objSoundList[idx] = Common::String(buffer);
+ }
+ } else {
+ // Read in palette
+ rrmStream->read(screen._cMap, PALETTE_SIZE);
+ screen.translatePalette(screen._cMap);
+ Common::copy(screen._cMap, screen._cMap + PALETTE_SIZE, screen._sMap);
+
+ // Read in the background
+ Common::SeekableReadStream *bgStream = !_compressed ? rrmStream :
+ res.decompress(*rrmStream, SHERLOCK_SCREEN_WIDTH * SHERLOCK_SCENE_HEIGHT);
+
+ bgStream->read(screen._backBuffer1.getPixels(), SHERLOCK_SCREEN_WIDTH * SHERLOCK_SCENE_HEIGHT);
+
+ if (_compressed)
+ delete bgStream;
}
+
+ // Backup the image and set the palette
+ screen._backBuffer2.blitFrom(screen._backBuffer1);
+ screen.setPalette(screen._cMap);
+
+ delete rrmStream;
}
- // Set up the list of images used by the scene
- _images.resize(bgHeader._numImages + 1);
- for (int idx = 0; idx < bgHeader._numImages; ++idx) {
+ } else {
+ // === 3DO version ===
+ _roomFilename = "rooms/" + filename + ".rrm";
+ flag = _vm->_res->exists(_roomFilename);
+ if (!flag)
+ error("loadScene: 3DO room data file not found");
+
+ Common::SeekableReadStream *roomStream = _vm->_res->load(_roomFilename);
+ uint32 roomStreamSize = roomStream->size();
+
+ // there should be at least all bytes of the header data
+ if (roomStreamSize < 128)
+ error("loadScene: 3DO room data file is too small");
+
+ // Read 3DO header
+ roomStream->skip(4); // UINT32: offset graphic data?
+ uint16 header3DO_numStructs = roomStream->readUint16BE();
+ uint16 header3DO_numImages = roomStream->readUint16BE();
+ uint16 header3DO_numAnimations = roomStream->readUint16BE();
+ roomStream->skip(6);
+
+ uint32 header3DO_bgInfo_offset = roomStream->readUint32BE() + 0x80;
+ uint32 header3DO_bgInfo_size = roomStream->readUint32BE();
+ uint32 header3DO_bgShapes_offset = roomStream->readUint32BE() + 0x80;
+ uint32 header3DO_bgShapes_size = roomStream->readUint32BE();
+ uint32 header3DO_descriptions_offset = roomStream->readUint32BE() + 0x80;
+ uint32 header3DO_descriptions_size = roomStream->readUint32BE();
+ uint32 header3DO_sequence_offset = roomStream->readUint32BE() + 0x80;
+ uint32 header3DO_sequence_size = roomStream->readUint32BE();
+ uint32 header3DO_cAnim_offset = roomStream->readUint32BE() + 0x80;
+ uint32 header3DO_cAnim_size = roomStream->readUint32BE();
+ uint32 header3DO_roomBounding_offset = roomStream->readUint32BE() + 0x80;
+ uint32 header3DO_roomBounding_size = roomStream->readUint32BE();
+ uint32 header3DO_walkDirectory_offset = roomStream->readUint32BE() + 0x80;
+ uint32 header3DO_walkDirectory_size = roomStream->readUint32BE();
+ uint32 header3DO_walkData_offset = roomStream->readUint32BE() + 0x80;
+ uint32 header3DO_walkData_size = roomStream->readUint32BE();
+ uint32 header3DO_exits_offset = roomStream->readUint32BE() + 0x80;
+ uint32 header3DO_exits_size = roomStream->readUint32BE();
+ uint32 header3DO_entranceData_offset = roomStream->readUint32BE() + 0x80;
+ uint32 header3DO_entranceData_size = roomStream->readUint32BE();
+ uint32 header3DO_soundList_offset = roomStream->readUint32BE() + 0x80;
+ uint32 header3DO_soundList_size = roomStream->readUint32BE();
+ //uint32 header3DO_unknown_offset = roomStream->readUint32BE() + 0x80;
+ //uint32 header3DO_unknown_size = roomStream->readUint32BE();
+ roomStream->skip(8); // Skip over unknown offset+size
+ uint32 header3DO_bgGraphicData_offset = roomStream->readUint32BE() + 0x80;
+ uint32 header3DO_bgGraphicData_size = roomStream->readUint32BE();
+
+ // Calculate amount of entries
+ int32 header3DO_soundList_count = header3DO_soundList_size / 9;
+
+ _invGraphicItems = header3DO_numImages + 1;
+
+ // Verify all offsets
+ if (header3DO_bgInfo_offset >= roomStreamSize)
+ error("loadScene: 3DO bgInfo offset points outside of room file");
+ if (header3DO_bgInfo_size > (roomStreamSize - header3DO_bgInfo_offset))
+ error("loadScene: 3DO bgInfo size goes beyond room file");
+ if (header3DO_bgShapes_offset >= roomStreamSize)
+ error("loadScene: 3DO bgShapes offset points outside of room file");
+ if (header3DO_bgShapes_size > (roomStreamSize - header3DO_bgShapes_offset))
+ error("loadScene: 3DO bgShapes size goes beyond room file");
+ if (header3DO_descriptions_offset >= roomStreamSize)
+ error("loadScene: 3DO descriptions offset points outside of room file");
+ if (header3DO_descriptions_size > (roomStreamSize - header3DO_descriptions_offset))
+ error("loadScene: 3DO descriptions size goes beyond room file");
+ if (header3DO_sequence_offset >= roomStreamSize)
+ error("loadScene: 3DO sequence offset points outside of room file");
+ if (header3DO_sequence_size > (roomStreamSize - header3DO_sequence_offset))
+ error("loadScene: 3DO sequence size goes beyond room file");
+ if (header3DO_cAnim_offset >= roomStreamSize)
+ error("loadScene: 3DO cAnim offset points outside of room file");
+ if (header3DO_cAnim_size > (roomStreamSize - header3DO_cAnim_offset))
+ error("loadScene: 3DO cAnim size goes beyond room file");
+ if (header3DO_roomBounding_offset >= roomStreamSize)
+ error("loadScene: 3DO roomBounding offset points outside of room file");
+ if (header3DO_roomBounding_size > (roomStreamSize - header3DO_roomBounding_offset))
+ error("loadScene: 3DO roomBounding size goes beyond room file");
+ if (header3DO_walkDirectory_offset >= roomStreamSize)
+ error("loadScene: 3DO walkDirectory offset points outside of room file");
+ if (header3DO_walkDirectory_size > (roomStreamSize - header3DO_walkDirectory_offset))
+ error("loadScene: 3DO walkDirectory size goes beyond room file");
+ if (header3DO_walkData_offset >= roomStreamSize)
+ error("loadScene: 3DO walkData offset points outside of room file");
+ if (header3DO_walkData_size > (roomStreamSize - header3DO_walkData_offset))
+ error("loadScene: 3DO walkData size goes beyond room file");
+ if (header3DO_exits_offset >= roomStreamSize)
+ error("loadScene: 3DO exits offset points outside of room file");
+ if (header3DO_exits_size > (roomStreamSize - header3DO_exits_offset))
+ error("loadScene: 3DO exits size goes beyond room file");
+ if (header3DO_entranceData_offset >= roomStreamSize)
+ error("loadScene: 3DO entranceData offset points outside of room file");
+ if (header3DO_entranceData_size > (roomStreamSize - header3DO_entranceData_offset))
+ error("loadScene: 3DO entranceData size goes beyond room file");
+ if (header3DO_soundList_offset >= roomStreamSize)
+ error("loadScene: 3DO soundList offset points outside of room file");
+ if (header3DO_soundList_size > (roomStreamSize - header3DO_soundList_offset))
+ error("loadScene: 3DO soundList size goes beyond room file");
+ if (header3DO_bgGraphicData_offset >= roomStreamSize)
+ error("loadScene: 3DO bgGraphicData offset points outside of room file");
+ if (header3DO_bgGraphicData_size > (roomStreamSize - header3DO_bgGraphicData_offset))
+ error("loadScene: 3DO bgGraphicData size goes beyond room file");
+
+ // === BGINFO === read in the shapes header info
+ Common::Array<BgFileHeaderInfo> bgInfo;
+
+ uint32 expected3DO_bgInfo_size = header3DO_numStructs * 16;
+ if (expected3DO_bgInfo_size != header3DO_bgInfo_size) // Security check
+ error("loadScene: 3DO bgInfo size mismatch");
+
+ roomStream->seek(header3DO_bgInfo_offset);
+ bgInfo.resize(header3DO_numStructs);
+ for (uint idx = 0; idx < bgInfo.size(); ++idx)
+ bgInfo[idx].load3DO(*roomStream);
+
+ // === BGSHAPES === read in the shapes info
+ uint32 expected3DO_bgShapes_size = header3DO_numStructs * 588;
+ if (expected3DO_bgShapes_size != header3DO_bgShapes_size) // Security check
+ error("loadScene: 3DO bgShapes size mismatch");
+
+ roomStream->seek(header3DO_bgShapes_offset);
+ _bgShapes.resize(header3DO_numStructs);
+ for (int idx = 0; idx < header3DO_numStructs; ++idx)
+ _bgShapes[idx].load3DO(*roomStream);
+
+ // === DESCRIPTION === read description text
+ if (header3DO_descriptions_size) {
+ roomStream->seek(header3DO_descriptions_offset);
+ _descText.resize(header3DO_descriptions_size);
+ roomStream->read(&_descText[0], header3DO_descriptions_size);
+ }
+
+ // === SEQUENCE === read sequence buffer
+ if (header3DO_sequence_size) {
+ roomStream->seek(header3DO_sequence_offset);
+ _sequenceBuffer.resize(header3DO_sequence_size);
+ roomStream->read(&_sequenceBuffer[0], header3DO_sequence_size);
+ }
+
+ // === IMAGES === set up the list of images used by the scene
+ roomStream->seek(header3DO_bgGraphicData_offset);
+ _images.resize(header3DO_numImages + 1);
+ for (int idx = 0; idx < header3DO_numImages; ++idx) {
_images[idx + 1]._filesize = bgInfo[idx]._filesize;
_images[idx + 1]._maxFrames = bgInfo[idx]._maxFrames;
- // Read in the image data
- Common::SeekableReadStream *imageStream = _lzwMode ?
- res.decompress(*rrmStream, bgInfo[idx]._filesize) :
- rrmStream->readStream(bgInfo[idx]._filesize);
+ // Read image data into memory
+ Common::SeekableReadStream *imageStream = roomStream->readStream(bgInfo[idx]._filesize);
- _images[idx + 1]._images = new ImageFile(*imageStream);
+ // Load image data into an ImageFile array as room file data
+ // which is basically a fixed header, followed by a raw cel header, followed by regular cel data
+ _images[idx + 1]._images = new ImageFile3DO(*imageStream, true);
delete imageStream;
}
- // Set up the bgShapes
- for (int idx = 0; idx < bgHeader._numStructs; ++idx) {
+ // === BGSHAPES === Set up the bgShapes
+ for (int idx = 0; idx < header3DO_numStructs; ++idx) {
_bgShapes[idx]._images = _images[_bgShapes[idx]._misc]._images;
_bgShapes[idx]._imageFrame = !_bgShapes[idx]._images ? (ImageFrame *)nullptr :
&(*_bgShapes[idx]._images)[0];
@@ -460,121 +826,169 @@ bool Scene::loadScene(const Common::String &filename) {
_bgShapes[idx]._oldSize = Common::Point(1, 1);
}
- // Load in cAnim list
+ // === CANIM === read cAnim list
_cAnim.clear();
- if (bgHeader._numcAnimations) {
- int animSize = IS_SERRATED_SCALPEL ? 65 : 47;
- Common::SeekableReadStream *canimStream = _lzwMode ?
- res.decompress(*rrmStream, animSize * bgHeader._numcAnimations) :
- rrmStream->readStream(animSize * bgHeader._numcAnimations);
+ if (header3DO_numAnimations) {
+ roomStream->seek(header3DO_cAnim_offset);
+ Common::SeekableReadStream *cAnimStream = roomStream->readStream(header3DO_cAnim_size);
+
+ uint32 *cAnimOffsetTablePtr = new uint32[header3DO_numAnimations];
+ uint32 *cAnimOffsetPtr = cAnimOffsetTablePtr;
+ uint32 cAnimOffset = 0;
+ memset(cAnimOffsetTablePtr, 0, header3DO_numAnimations * sizeof(uint32));
+
+ // Seek to end of graphics data and load cAnim offset table from there
+ roomStream->seek(header3DO_bgGraphicData_offset + header3DO_bgGraphicData_size);
+ for (uint16 curCAnim = 0; curCAnim < header3DO_numAnimations; curCAnim++) {
+ cAnimOffset = roomStream->readUint32BE();
+ if (cAnimOffset >= roomStreamSize)
+ error("loadScene: 3DO cAnim entry offset points outside of room file");
+
+ *cAnimOffsetPtr = cAnimOffset;
+ cAnimOffsetPtr++;
+ }
- _cAnim.resize(bgHeader._numcAnimations);
- for (uint idx = 0; idx < _cAnim.size(); ++idx)
- _cAnim[idx].load(*canimStream, IS_ROSE_TATTOO);
+ // Go to the start of the cAnimOffsetTable
+ cAnimOffsetPtr = cAnimOffsetTablePtr;
- delete canimStream;
+ _cAnim.resize(header3DO_numAnimations);
+ for (uint idx = 0; idx < _cAnim.size(); ++idx) {
+ _cAnim[idx].load3DO(*cAnimStream, *cAnimOffsetPtr);
+ cAnimOffsetPtr++;
+ }
+
+ delete cAnimStream;
+ delete[] cAnimOffsetTablePtr;
}
- // Read in the room bounding areas
- int size = rrmStream->readUint16LE();
- Common::SeekableReadStream *boundsStream = !_lzwMode ? rrmStream :
- res.decompress(*rrmStream, size);
+ // === BOUNDING AREAS === Read in the room bounding areas
+ int roomBoundingCount = header3DO_roomBounding_size / 12;
+ uint32 expected3DO_roomBounding_size = roomBoundingCount * 12;
+ if (expected3DO_roomBounding_size != header3DO_roomBounding_size)
+ error("loadScene: 3DO roomBounding size mismatch");
- _zones.resize(size / 10);
+ roomStream->seek(header3DO_roomBounding_offset);
+ _zones.resize(roomBoundingCount);
for (uint idx = 0; idx < _zones.size(); ++idx) {
- _zones[idx].left = boundsStream->readSint16LE();
- _zones[idx].top = boundsStream->readSint16LE();
- _zones[idx].setWidth(boundsStream->readSint16LE() + 1);
- _zones[idx].setHeight(boundsStream->readSint16LE() + 1);
- boundsStream->skip(2); // Skip unused scene number field
+ _zones[idx].left = roomStream->readSint16BE();
+ _zones[idx].top = roomStream->readSint16BE();
+ _zones[idx].setWidth(roomStream->readSint16BE() + 1);
+ _zones[idx].setHeight(roomStream->readSint16BE() + 1);
+ roomStream->skip(4); // skip UINT32
}
- if (_lzwMode)
- delete boundsStream;
-
- // Ensure we've reached the path version byte
- if (rrmStream->readByte() != (IS_SERRATED_SCALPEL ? 254 : 251))
- error("Invalid scene path data");
+ // === WALK DIRECTORY === Load the walk directory
+ uint32 expected3DO_walkDirectory_size = _zones.size() * _zones.size() * 2;
+ if (expected3DO_walkDirectory_size != header3DO_walkDirectory_size)
+ error("loadScene: 3DO walkDirectory size mismatch");
- // Load the walk directory
+ roomStream->seek(header3DO_walkDirectory_offset);
assert(_zones.size() < MAX_ZONES);
for (uint idx1 = 0; idx1 < _zones.size(); ++idx1) {
for (uint idx2 = 0; idx2 < _zones.size(); ++idx2)
- _walkDirectory[idx1][idx2] = rrmStream->readSint16LE();
+ _walkDirectory[idx1][idx2] = roomStream->readSint16BE();
}
- // Read in the walk data
- size = rrmStream->readUint16LE();
- Common::SeekableReadStream *walkStream = !_lzwMode ? rrmStream :
- res.decompress(*rrmStream, size);
-
- _walkData.resize(size);
- walkStream->read(&_walkData[0], size);
-
- if (_lzwMode)
- delete walkStream;
+ // === WALK DATA === Read in the walk data
+ roomStream->seek(header3DO_walkData_offset);
- if (IS_ROSE_TATTOO) {
- // Read in the entrance
- _entrance.load(*rrmStream);
-
- // Load scale zones
- _scaleZones.resize(rrmStream->readByte());
- for (uint idx = 0; idx < _scaleZones.size(); ++idx)
- _scaleZones[idx].load(*rrmStream);
+ 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 exits
- _exitZone = -1;
- int numExits = rrmStream->readByte();
- _exits.resize(numExits);
-
- for (int idx = 0; idx < numExits; ++idx)
- _exits[idx].load(*rrmStream, IS_ROSE_TATTOO);
-
- if (IS_SERRATED_SCALPEL)
- // Read in the entrance
- _entrance.load(*rrmStream);
-
- // Initialize sound list
- int numSounds = rrmStream->readByte();
- _sounds.resize(numSounds);
-
- for (int idx = 0; idx < numSounds; ++idx)
- _sounds[idx].load(*rrmStream);
-
- loadSceneSounds();
-
- if (IS_ROSE_TATTOO) {
- // Load the object sound list
- char buffer[27];
-
- _objSoundList.resize(rrmStream->readUint16LE());
- for (uint idx = 0; idx < _objSoundList.size(); ++idx) {
- rrmStream->read(buffer, 27);
- _objSoundList[idx] = Common::String(buffer);
+ // 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)
+ continue;
+
+ uint dataIndex = 0;
+ while (dataIndex < _walkPoints.size() && _walkPoints[dataIndex]._fileOffset != fileOffset)
+ ++dataIndex;
+ assert(dataIndex < _walkPoints.size());
+ _walkDirectory[idx1][idx2] = dataIndex;
}
- } else {
- // Read in palette
- rrmStream->read(screen._cMap, PALETTE_SIZE);
- screen.translatePalette(screen._cMap);
- Common::copy(screen._cMap, screen._cMap + PALETTE_SIZE, screen._sMap);
+ }
- // Read in the background
- Common::SeekableReadStream *bgStream = !_lzwMode ? rrmStream :
- res.decompress(*rrmStream, SHERLOCK_SCREEN_WIDTH * SHERLOCK_SCENE_HEIGHT);
+ // === EXITS === Read in the exits
+ roomStream->seek(header3DO_exits_offset);
+
+ int exitsCount = header3DO_exits_size / 20;
+
+ _exits.resize(exitsCount);
+ for (int idx = 0; idx < exitsCount; ++idx)
+ _exits[idx].load3DO(*roomStream);
+
+ // === ENTRANCE === Read in the entrance
+ if (header3DO_entranceData_size != 8)
+ error("loadScene: 3DO entranceData size mismatch");
+
+ roomStream->seek(header3DO_entranceData_offset);
+ _entrance.load3DO(*roomStream);
+
+ // === SOUND LIST === Initialize sound list
+ roomStream->seek(header3DO_soundList_offset);
+ _sounds.resize(header3DO_soundList_count);
+ for (int idx = 0; idx < header3DO_soundList_count; ++idx)
+ _sounds[idx].load3DO(*roomStream);
+
+ delete roomStream;
+
+ // === BACKGROUND PICTURE ===
+ // load from file rooms\[filename].bg
+ // it's uncompressed 15-bit RGB555 data
+
+ Common::String roomBackgroundFilename = "rooms/" + filename + ".bg";
+ flag = _vm->_res->exists(roomBackgroundFilename);
+ if (!flag)
+ error("loadScene: 3DO room background file not found (%s)", roomBackgroundFilename.c_str());
+
+ Common::File roomBackgroundStream;
+ if (!roomBackgroundStream.open(roomBackgroundFilename))
+ error("Could not open file - %s", roomBackgroundFilename.c_str());
+
+ int totalPixelCount = SHERLOCK_SCREEN_WIDTH * SHERLOCK_SCENE_HEIGHT;
+ uint16 *roomBackgroundDataPtr = NULL;
+ uint16 *pixelSourcePtr = NULL;
+ uint16 *pixelDestPtr = (uint16 *)screen._backBuffer1.getPixels();
+ uint16 curPixel = 0;
+ uint32 roomBackgroundStreamSize = roomBackgroundStream.size();
+ uint32 expectedBackgroundSize = totalPixelCount * 2;
+
+ // Verify file size of background file
+ if (expectedBackgroundSize != roomBackgroundStreamSize)
+ error("loadScene: 3DO room background file not expected size");
+
+ roomBackgroundDataPtr = new uint16[totalPixelCount];
+ roomBackgroundStream.read(roomBackgroundDataPtr, roomBackgroundStreamSize);
+ roomBackgroundStream.close();
+
+ // Convert data from RGB555 to RGB565
+ pixelSourcePtr = roomBackgroundDataPtr;
+ for (int pixels = 0; pixels < totalPixelCount; pixels++) {
+ curPixel = READ_BE_UINT16(pixelSourcePtr++);
+
+ byte curPixelRed = (curPixel >> 10) & 0x1F;
+ byte curPixelGreen = (curPixel >> 5) & 0x1F;
+ byte curPixelBlue = curPixel & 0x1F;
+ *pixelDestPtr = ((curPixelRed << 11) | (curPixelGreen << 6) | (curPixelBlue));
+ pixelDestPtr++;
+ }
- bgStream->read(screen._backBuffer1.getPixels(), SHERLOCK_SCREEN_WIDTH * SHERLOCK_SCENE_HEIGHT);
+ delete[] roomBackgroundDataPtr;
- if (_lzwMode)
- delete bgStream;
- }
+#if 0
+ // code to show the background
+ screen.blitFrom(screen._backBuffer1);
+ _vm->_events->wait(10000);
+#endif
- // Backup the image and set the palette
+ // Backup the image
screen._backBuffer2.blitFrom(screen._backBuffer1);
- screen.setPalette(screen._cMap);
-
- delete rrmStream;
}
// Handle drawing any on-screen interface
@@ -622,17 +1036,6 @@ bool Scene::loadScene(const Common::String &filename) {
_walkedInScene = false;
saves._justLoaded = false;
- if (!_vm->isDemo()) {
- // Reset the previous map location and position on overhead map
- map._oldCharPoint = _currentScene;
-
- if (IS_SERRATED_SCALPEL) {
- map._overPos.x = (map[_currentScene].x - 6) * FIXED_INT_MULTIPLIER;
- map._overPos.y = (map[_currentScene].y + 9) * FIXED_INT_MULTIPLIER;
-
- }
- }
-
events.clearEvents();
return flag;
}
@@ -645,11 +1048,11 @@ void Scene::loadSceneSounds() {
}
void Scene::checkSceneStatus() {
- if (_sceneStats[_currentScene][64]) {
- for (uint idx = 0; idx < 64; ++idx) {
+ if (_sceneStats[_currentScene][MAX_BGSHAPES]) {
+ for (int idx = 0; idx < MAX_BGSHAPES; ++idx) {
bool flag = _sceneStats[_currentScene][idx];
- if (idx < _bgShapes.size()) {
+ if (idx < (int)_bgShapes.size()) {
Object &obj = _bgShapes[idx];
if (flag) {
@@ -671,7 +1074,7 @@ void Scene::checkSceneStatus() {
void Scene::saveSceneStatus() {
// Flag any objects for the scene that have been altered
- int count = MIN((int)_bgShapes.size(), 64);
+ int count = MIN((int)_bgShapes.size(), MAX_BGSHAPES);
for (int idx = 0; idx < count; ++idx) {
Object &obj = _bgShapes[idx];
_sceneStats[_currentScene][idx] = obj._type == HIDDEN || obj._type == REMOVE
@@ -679,7 +1082,7 @@ void Scene::saveSceneStatus() {
}
// Flag scene as having been visited
- _sceneStats[_currentScene][64] = true;
+ _sceneStats[_currentScene][MAX_BGSHAPES] = true;
}
void Scene::checkSceneFlags(bool flag) {
@@ -687,9 +1090,15 @@ void Scene::checkSceneFlags(bool flag) {
for (uint idx = 0; idx < _bgShapes.size(); ++idx) {
Object &o = _bgShapes[idx];
+ bool objectFlag = true;
- if (o._requiredFlag) {
- if (!_vm->readFlags(_bgShapes[idx]._requiredFlag)) {
+ if (o._requiredFlag[0] || o._requiredFlag[1]) {
+ if (o._requiredFlag[0] != 0)
+ objectFlag = _vm->readFlags(o._requiredFlag[0]);
+ if (o._requiredFlag[1] != 0)
+ objectFlag &= _vm->readFlags(o._requiredFlag[1]);
+
+ if (!objectFlag) {
// Kill object
if (o._type != HIDDEN && o._type != INVALID) {
if (o._images == nullptr || o._images->size() == 0)
@@ -699,7 +1108,7 @@ void Scene::checkSceneFlags(bool flag) {
// Flag it as needing to be hidden after first erasing it
o._type = mode;
}
- } else if (_bgShapes[idx]._requiredFlag > 0) {
+ } else if (IS_ROSE_TATTOO || o._requiredFlag[0] > 0) {
// Restore object
if (o._images == nullptr || o._images->size() == 0)
o._type = NO_SHAPE;
@@ -750,18 +1159,29 @@ void Scene::transitionToScene() {
SaveManager &saves = *_vm->_saves;
Screen &screen = *_vm->_screen;
Talk &talk = *_vm->_talk;
- Common::Point &hSavedPos = people._hSavedPos;
- int &hSavedFacing = people._hSavedFacing;
+ Point32 &hSavedPos = people._savedPos;
+ int &hSavedFacing = people._savedPos._facing;
if (hSavedPos.x < 1) {
// No exit information from last scene-check entrance info
if (_entrance._startPosition.x < 1) {
// No entrance info either, so use defaults
- hSavedPos = Common::Point(16000, 10000);
- hSavedFacing = 4;
+ if (IS_SERRATED_SCALPEL) {
+ hSavedPos = Point32(160 * FIXED_INT_MULTIPLIER, 100 * FIXED_INT_MULTIPLIER);
+ hSavedFacing = 4;
+ } else {
+ hSavedPos = people[HOLMES]._position;
+ hSavedFacing = people[HOLMES]._sequenceNumber;
+ }
} else {
// setup entrance info
- hSavedPos = _entrance._startPosition;
+ hSavedPos.x = _entrance._startPosition.x * FIXED_INT_MULTIPLIER;
+ hSavedPos.y = _entrance._startPosition.y * FIXED_INT_MULTIPLIER;
+ if (IS_SERRATED_SCALPEL) {
+ hSavedPos.x /= 100;
+ hSavedPos.y /= 100;
+ }
+
hSavedFacing = _entrance._startDir;
}
} else {
@@ -769,7 +1189,11 @@ void Scene::transitionToScene() {
// Note: If a savegame was just loaded, then the data is already correct.
// Otherwise, this is a linked scene or entrance info, and must be translated
if (hSavedFacing < 8 && !saves._justLoaded) {
- hSavedFacing = FS_TRANS[hSavedFacing];
+ if (IS_ROSE_TATTOO)
+ hSavedFacing = Tattoo::FS_TRANS[hSavedFacing];
+ else
+ hSavedFacing = Scalpel::FS_TRANS[hSavedFacing];
+
hSavedPos.x *= FIXED_INT_MULTIPLIER;
hSavedPos.y *= FIXED_INT_MULTIPLIER;
}
@@ -777,13 +1201,15 @@ void Scene::transitionToScene() {
int cAnimNum = -1;
- if (hSavedFacing < 101) {
- // Standard info, so set it
- people[PLAYER]._position = hSavedPos;
- people[PLAYER]._sequenceNumber = hSavedFacing;
- } else {
- // It's canimation information
- cAnimNum = hSavedFacing - 101;
+ if (!saves._justLoaded) {
+ if (hSavedFacing < 101) {
+ // Standard info, so set it
+ people[HOLMES]._position = hSavedPos;
+ people[HOLMES]._sequenceNumber = hSavedFacing;
+ } else {
+ // It's canimation information
+ cAnimNum = hSavedFacing - 101;
+ }
}
// Reset positioning for next load
@@ -792,9 +1218,14 @@ void Scene::transitionToScene() {
if (cAnimNum != -1) {
// Prevent Holmes from being drawn
- people[PLAYER]._position = Common::Point(0, 0);
+ people[HOLMES]._position = Common::Point(0, 0);
}
+ // 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)
+ people[people._walkControl].centerScreenOnPerson();
+
for (uint objIdx = 0; objIdx < _bgShapes.size(); ++objIdx) {
Object &obj = _bgShapes[objIdx];
@@ -811,8 +1242,8 @@ void Scene::transitionToScene() {
}
if (Common::Rect(topLeft.x, topLeft.y, bottomRight.x, bottomRight.y).contains(
- Common::Point(people[PLAYER]._position.x / FIXED_INT_MULTIPLIER,
- people[PLAYER]._position.y / FIXED_INT_MULTIPLIER))) {
+ Common::Point(people[HOLMES]._position.x / FIXED_INT_MULTIPLIER,
+ people[HOLMES]._position.y / FIXED_INT_MULTIPLIER))) {
// Current point is already inside box - impact occurred on
// a previous call. So simply do nothing except talk until the
// player is clear of the box
@@ -844,22 +1275,30 @@ void Scene::transitionToScene() {
updateBackground();
// Actually do the transition
- if (screen._fadeStyle)
- screen.randomTransition();
- else
- screen.blitFrom(screen._backBuffer1);
+ if (screen._fadeStyle) {
+ if (!IS_3DO) {
+ // do pixel-transition for PC
+ screen.randomTransition();
+ } else {
+ // fade in for 3DO
+ screen.clear();
+ screen.fadeIntoScreen3DO(3);
+ }
+ } else {
+ screen.slamArea(screen._currentScroll.x, screen._currentScroll.y, SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT);
+ }
screen.update();
// Start any initial animation for the scene
if (cAnimNum != -1) {
CAnim &c = _cAnim[cAnimNum];
- Common::Point pt = c._goto;
+ PositionFacing pt = c._goto[0];
- c._goto = Common::Point(-1, -1);
- people[AL]._position = Common::Point(0, 0);
+ c._goto[0].x = c._goto[0].y = -1;
+ people[HOLMES]._position = Common::Point(0, 0);
startCAnim(cAnimNum, 1);
- c._goto = pt;
+ c._goto[0] = pt;
}
}
@@ -892,92 +1331,6 @@ void Scene::updateBackground() {
drawAllShapes();
}
-void Scene::drawAllShapes() {
- People &people = *_vm->_people;
- Screen &screen = *_vm->_screen;
-
- // Restrict drawing window
- screen.setDisplayBounds(Common::Rect(0, 0, SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCENE_HEIGHT));
-
- // 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);
- }
-
- // 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);
- }
-
- // 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);
- }
-
- // 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);
- }
-
- // Draw any active characters
- for (int idx = 0; idx < MAX_CHARACTERS; ++idx) {
- Person &p = people[idx];
- if (p._type == CHARACTER && p._walkLoaded) {
- bool flipped = IS_SERRATED_SCALPEL && (
- p._sequenceNumber == WALK_LEFT || p._sequenceNumber == STOP_LEFT ||
- 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,
- p._position.y / FIXED_INT_MULTIPLIER - p.frameHeight()), flipped);
- }
- }
-
- // Draw all static and active shapes that are NORMAL and are in front of the player
- 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,
- _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);
- }
-
- // Draw all static and active shapes that are FORWARD
- for (uint idx = 0; idx < _bgShapes.size(); ++idx) {
- _bgShapes[idx]._oldPosition = _bgShapes[idx]._position;
- _bgShapes[idx]._oldSize = Common::Point(_bgShapes[idx].frameWidth(),
- _bgShapes[idx].frameHeight());
-
- 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,
- _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);
- }
-
- screen.resetDisplayBounds();
-}
-
Exit *Scene::checkForExit(const Common::Rect &r) {
for (uint idx = 0; idx < _exits.size(); ++idx) {
if (_exits[idx].intersects(r))
@@ -987,238 +1340,6 @@ Exit *Scene::checkForExit(const Common::Rect &r) {
return nullptr;
}
-int Scene::startCAnim(int cAnimNum, int playRate) {
- Events &events = *_vm->_events;
- Map &map = *_vm->_map;
- People &people = *_vm->_people;
- Resources &res = *_vm->_res;
- Talk &talk = *_vm->_talk;
- UserInterface &ui = *_vm->_ui;
- Common::Point tpPos, walkPos;
- int tpDir, walkDir;
- int tFrames = 0;
- int gotoCode = -1;
-
- // Validation
- if (cAnimNum >= (int)_cAnim.size())
- // number out of bounds
- return -1;
- if (_canimShapes.size() >= 3 || playRate == 0)
- // Too many active animations, or invalid play rate
- return 0;
-
- CAnim &cAnim = _cAnim[cAnimNum];
- if (playRate < 0) {
- // Reverse direction
- walkPos = cAnim._teleportPos;
- walkDir = cAnim._teleportDir;
- tpPos = cAnim._goto;
- tpDir = cAnim._gotoDir;
- } else {
- // Forward direction
- walkPos = cAnim._goto;
- walkDir = cAnim._gotoDir;
- tpPos = cAnim._teleportPos;
- tpDir = cAnim._teleportDir;
- }
-
- CursorId oldCursor = events.getCursor();
- events.setCursor(WAIT);
-
- if (walkPos.x != -1) {
- // Holmes must walk to the walk point before the cAnimation is started
- if (people[AL]._position != walkPos)
- people.walkToCoords(walkPos, walkDir);
- }
-
- if (talk._talkToAbort)
- return 1;
-
- // Add new anim shape entry for displaying the animation
- _canimShapes.push_back(Object());
- Object &cObj = _canimShapes[_canimShapes.size() - 1];
-
- // 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
-
- // 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;
-
- if (cAnim._name.size() > 0 && cAnim._type != NO_SHAPE) {
- if (tpPos.x != -1)
- people[AL]._type = REMOVE;
-
- Common::String fname = cAnim._name + ".vgs";
- if (!res.isInCache(fname)) {
- // Set up RRM scene data
- Common::SeekableReadStream *rrmStream = res.load(_rrmName);
- rrmStream->seek(44 + cAnimNum * 4);
- rrmStream->seek(rrmStream->readUint32LE());
-
- // Load the canimation into the cache
- Common::SeekableReadStream *imgStream = !_lzwMode ? rrmStream->readStream(cAnim._size) :
- Resources::decompressLZ(*rrmStream, cAnim._size);
- res.addToCache(fname, *imgStream);
-
- delete imgStream;
- delete rrmStream;
- }
-
- // Now load the resource as an image
- cObj._images = new ImageFile(fname);
- cObj._imageFrame = &(*cObj._images)[0];
- cObj._maxFrames = cObj._images->size();
-
- int frames = 0;
- if (playRate < 0) {
- // Reverse direction
- // Count number of frames
- while (cObj._sequences[frames] && frames < MAX_FRAME)
- ++frames;
- } else {
- // Forward direction
- Object::_countCAnimFrames = true;
-
- while (cObj._type == ACTIVE_BG_SHAPE) {
- cObj.checkObject();
- ++frames;
-
- if (frames >= 1000)
- error("CAnim has infinite loop sequence");
- }
-
- if (frames > 1)
- --frames;
-
- Object::_countCAnimFrames = false;
-
- 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
- if (frames == 0)
- return -2;
-
- ++frames;
- int repeat = ABS(playRate);
- int dir;
-
- if (playRate < 0) {
- // Play in reverse
- dir = -2;
- cObj._frameNumber = frames - 3;
- } else {
- dir = 0;
- }
-
- tFrames = frames - 1;
- int pauseFrame = (_cAnimFramePause) ? frames - _cAnimFramePause : -1;
-
- while (--frames) {
- if (frames == pauseFrame)
- ui.printObjectDesc();
-
- doBgAnim();
-
- // Repeat same frame
- int temp = repeat;
- while (--temp > 0) {
- cObj._frameNumber--;
- doBgAnim();
-
- if (_vm->shouldQuit())
- return 0;
- }
-
- cObj._frameNumber += dir;
- }
-
- people[AL]._type = CHARACTER;
- }
-
- // Teleport to ending coordinates if necessary
- if (tpPos.x != -1) {
- people[AL]._position = tpPos; // Place the player
- people[AL]._sequenceNumber = tpDir;
- people.gotoStand(people[AL]);
- }
-
- if (playRate < 0)
- // Reverse direction - set to end sequence
- cObj._frameNumber = tFrames - 1;
-
- 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();
-
- if (gotoCode > 0 && !talk._talkToAbort) {
- _goToScene = gotoCode;
-
- if (_goToScene < 97 && map[_goToScene].x) {
- map._overPos = map[_goToScene];
- }
- }
-
- people.loadWalk();
-
- if (tpPos.x != -1 && !talk._talkToAbort) {
- // Teleport to ending coordinates
- people[AL]._position = tpPos;
- people[AL]._sequenceNumber = tpDir;
-
- people.gotoStand(people[AL]);
- }
-
- events.setCursor(oldCursor);
-
- return 1;
-}
-
-int Scene::findBgShape(const Common::Rect &r) {
- if (!_doBgAnimDone)
- // New frame hasn't been drawn yet
- return -1;
-
- for (int idx = (int)_bgShapes.size() - 1; idx >= 0; --idx) {
- Object &o = _bgShapes[idx];
- if (o._type != INVALID && o._type != NO_SHAPE && o._type != HIDDEN
- && o._aType <= PERSON) {
- if (r.intersects(o.getNewBounds()))
- return idx;
- } else if (o._type == NO_SHAPE) {
- if (r.intersects(o.getNoShapeBounds()))
- return idx;
- }
- }
-
- return -1;
-}
-
int Scene::checkForZones(const Common::Point &pt, int zoneType) {
int matches = 0;
@@ -1247,26 +1368,7 @@ int Scene::whichZone(const Common::Point &pt) {
return -1;
}
-int Scene::closestZone(const Common::Point &pt) {
- int dist = 1000;
- int zone = -1;
-
- for (uint idx = 0; idx < _zones.size(); ++idx) {
- Common::Point zc((_zones[idx].left + _zones[idx].right) / 2,
- (_zones[idx].top + _zones[idx].bottom) / 2);
- int d = ABS(zc.x - pt.x) + ABS(zc.y - pt.y);
-
- if (d < dist) {
- // Found a closer zone
- dist = d;
- zone = idx;
- }
- }
-
- return zone;
-}
-
-void Scene::synchronize(Common::Serializer &s) {
+void Scene::synchronize(Serializer &s) {
if (s.isSaving())
saveSceneStatus();
@@ -1277,37 +1379,16 @@ void Scene::synchronize(Common::Serializer &s) {
_loadingSavedGame = true;
}
- for (int sceneNum = 0; sceneNum < SCENES_COUNT; ++sceneNum) {
- for (int flag = 0; flag < 65; ++flag) {
+ for (int sceneNum = 1; sceneNum < SCENES_COUNT; ++sceneNum) {
+ for (int flag = 0; flag <= MAX_BGSHAPES; ++flag) {
s.syncAsByte(_sceneStats[sceneNum][flag]);
}
}
}
-void Scene::setNPCPath(int npc) {
- People &people = *_vm->_people;
- Talk &talk = *_vm->_talk;
-
- people[npc].clearNPC();
- people[npc]._name = Common::String::format("WATS%.2dA", _currentScene);
-
- // If we're in the middle of a script that will continue once the scene is loaded,
- // return without calling the path script
- if (talk._scriptMoreFlag == 1 || talk._scriptMoreFlag == 3)
- return;
-
- // Turn off all the NPCs, since the talk script will turn them back on as needed
- for (uint idx = 0; idx < MAX_NPC; ++idx)
- people[idx + 1]._type = INVALID;
-
- // Call the path script for the scene
- Common::String pathFile = Common::String::format("PATH%.2dA", _currentScene);
- talk.talkTo(pathFile);
-}
-
void Scene::checkBgShapes() {
People &people = *_vm->_people;
- Person &holmes = people._player;
+ Person &holmes = people[HOLMES];
Common::Point pt(holmes._position.x / FIXED_INT_MULTIPLIER, holmes._position.y / FIXED_INT_MULTIPLIER);
// Iterate through the shapes
diff --git a/engines/sherlock/scene.h b/engines/sherlock/scene.h
index 37a1b32740..f75dfb40cd 100644
--- a/engines/sherlock/scene.h
+++ b/engines/sherlock/scene.h
@@ -33,7 +33,6 @@
namespace Sherlock {
-#define SCENES_COUNT 63
#define MAX_ZONES 40
#define INFO_LINE 140
@@ -73,14 +72,14 @@ struct BgFileHeaderInfo {
* Load the data for the object
*/
void load(Common::SeekableReadStream &s);
+ void load3DO(Common::SeekableReadStream &s);
};
class Exit: public Common::Rect {
public:
int _scene;
int _allow;
- Common::Point _people;
- int _peopleDir;
+ PositionFacing _newPosition;
Common::String _dest;
int _image; // Arrow image to use
@@ -89,6 +88,7 @@ public:
* Load the data for the object
*/
void load(Common::SeekableReadStream &s, bool isRoseTattoo);
+ void load3DO(Common::SeekableReadStream &s);
};
struct SceneEntry {
@@ -100,6 +100,7 @@ struct SceneEntry {
* Load the data for the object
*/
void load(Common::SeekableReadStream &s);
+ void load3DO(Common::SeekableReadStream &s);
};
struct SceneSound {
@@ -110,6 +111,7 @@ struct SceneSound {
* Load the data for the object
*/
void load(Common::SeekableReadStream &s);
+ void load3DO(Common::SeekableReadStream &s);
};
class ObjectArray : public Common::Array<Object> {
@@ -128,33 +130,24 @@ public:
void load(Common::SeekableReadStream &s);
};
-struct SceneTripEntry {
- bool _flag;
- int _sceneNumber;
- int _numTimes;
+class WalkArray : public Common::Array < Common::Point > {
+public:
+ int _pointsCount;
+ int _fileOffset;
+
+ WalkArray() : _pointsCount(0), _fileOffset(-1) {}
- SceneTripEntry() : _flag(false), _sceneNumber(0), _numTimes(0) {}
- SceneTripEntry(bool flag, int sceneNumber, int numTimes) : _flag(flag),
- _sceneNumber(sceneNumber), _numTimes(numTimes) {}
+ /**
+ * Load data for the walk array entry
+ */
+ void load(Common::SeekableReadStream &s, bool isRoseTattoo);
};
class Scene {
private:
- Common::String _rrmName;
bool _loadingSavedGame;
/**
- * Loads the data associated for a given scene. The .BGD file's format is:
- * BGHEADER: Holds an index for the rest of the file
- * STRUCTS: The objects for the scene
- * IMAGES: The graphic information for the structures
- *
- * The _misc field of the structures contains the number of the graphic image
- * that it should point to after loading; _misc is then set to 0.
- */
- bool loadScene(const Common::String &filename);
-
- /**
* Loads sounds for the scene
*/
void loadSceneSounds();
@@ -185,6 +178,18 @@ private:
void saveSceneStatus();
protected:
SherlockEngine *_vm;
+ Common::String _roomFilename;
+
+ /**
+ * Loads the data associated for a given scene. The room resource file's format is:
+ * BGHEADER: Holds an index for the rest of the file
+ * STRUCTS: The objects for the scene
+ * IMAGES: The graphic information for the structures
+ *
+ * The _misc field of the structures contains the number of the graphic image
+ * that it should point to after loading; _misc is then set to 0.
+ */
+ virtual bool loadScene(const Common::String &filename);
/**
* Checks all the background shapes. If a background shape is animating,
@@ -196,29 +201,32 @@ protected:
/**
* Draw all the shapes, people and NPCs in the correct order
*/
- void drawAllShapes();
+ virtual void drawAllShapes() = 0;
+
+ /**
+ * Called by loadScene when the palette is loaded for Rose Tattoo
+ */
+ virtual void paletteLoaded() {}
Scene(SherlockEngine *vm);
public:
int _currentScene;
int _goToScene;
- bool _sceneStats[SCENES_COUNT][65];
- bool _savedStats[SCENES_COUNT][9];
+ bool **_sceneStats;
bool _walkedInScene;
int _version;
- bool _lzwMode;
+ bool _compressed;
int _invGraphicItems;
Common::String _comments;
Common::Array<char> _descText;
Common::Array<Common::Rect> _zones;
- Common::Array<Object> _bgShapes;
+ ObjectArray _bgShapes;
Common::Array<CAnim> _cAnim;
Common::Array<byte> _sequenceBuffer;
Common::Array<SceneImage> _images;
int _walkDirectory[MAX_ZONES][MAX_ZONES];
- Common::Array<byte> _walkData;
+ Common::Array<WalkArray> _walkPoints;
Common::Array<Exit> _exits;
- int _exitZone;
SceneEntry _entrance;
Common::Array<SceneSound> _sounds;
ObjectArray _canimShapes;
@@ -229,7 +237,6 @@ public:
bool _doBgAnimDone;
int _tempFadeStyle;
int _cAnimFramePause;
- Common::Array<SceneTripEntry> _sceneTripCounters;
public:
static Scene *init(SherlockEngine *vm);
virtual ~Scene();
@@ -240,11 +247,6 @@ public:
void selectScene();
/**
- * Fres all the graphics and other dynamically allocated data for the scene
- */
- void freeScene();
-
- /**
* Check the scene's objects against the game flags. If false is passed,
* it means the scene has just been loaded. A value of true means that the scene
* is in use (ie. not just loaded)
@@ -257,28 +259,12 @@ public:
Exit *checkForExit(const Common::Rect &r);
/**
- * Attempt to start a canimation sequence. It will load the requisite graphics, and
- * then copy the canim object into the _canimShapes array to start the animation.
- *
- * @param cAnimNum The canim object within the current scene
- * @param playRate Play rate. 0 is invalid; 1=normal speed, 2=1/2 speed, etc.
- * A negative playRate can also be specified to play the animation in reverse
- */
- int startCAnim(int cAnimNum, int playRate);
-
- /**
* Scans through the object list to find one with a matching name, and will
* call toggleHidden with all matches found. Returns the numer of matches found
*/
int toggleObject(const Common::String &name);
/**
- * Attempts to find a background shape within the passed bounds. If found,
- * it will return the shape number, or -1 on failure.
- */
- int findBgShape(const Common::Rect &r);
-
- /**
* Checks to see if the given position in the scene belongs to a given zone type.
* If it is, the zone is activated and used just like a TAKL zone or aFLAG_SET zone.
*/
@@ -290,21 +276,25 @@ public:
int whichZone(const Common::Point &pt);
/**
+ * Fres all the graphics and other dynamically allocated data for the scene
+ */
+ virtual void freeScene();
+
+ /**
* Returns the index of the closest zone to a given point.
*/
- int closestZone(const Common::Point &pt);
+ virtual int closestZone(const Common::Point &pt) = 0;
/**
- * Synchronize the data for a savegame
+ * Attempts to find a background shape within the passed bounds. If found,
+ * it will return the shape number, or -1 on failure.
*/
- void synchronize(Common::Serializer &s);
+ virtual int findBgShape(const Common::Point &pt) = 0;
/**
- * Resets the NPC path information when entering a new scene.
- * @remarks The default talk file for the given NPC is set to WATS##A, where ## is
- * the scene number being entered
+ * Synchronize the data for a savegame
*/
- void setNPCPath(int npc);
+ virtual void synchronize(Serializer &s);
public:
/**
* Draw all objects and characters.
@@ -316,6 +306,16 @@ public:
* to be drawn
*/
virtual void updateBackground();
+
+ /**
+ * Attempt to start a canimation sequence. It will load the requisite graphics, and
+ * then copy the canim object into the _canimShapes array to start the animation.
+ *
+ * @param cAnimNum The canim object within the current scene
+ * @param playRate Play rate. 0 is invalid; 1=normal speed, 2=1/2 speed, etc.
+ * A negative playRate can also be specified to play the animation in reverse
+ */
+ virtual int startCAnim(int cAnimNum, int playRate = 1) = 0;
};
} // End of namespace Sherlock
diff --git a/engines/sherlock/screen.cpp b/engines/sherlock/screen.cpp
index a3af5559c7..4233bca0cb 100644
--- a/engines/sherlock/screen.cpp
+++ b/engines/sherlock/screen.cpp
@@ -22,55 +22,41 @@
#include "sherlock/screen.h"
#include "sherlock/sherlock.h"
+#include "sherlock/scalpel/scalpel_screen.h"
#include "common/system.h"
#include "common/util.h"
#include "graphics/palette.h"
namespace Sherlock {
+Screen *Screen::init(SherlockEngine *vm) {
+ if (vm->getGameID() == GType_SerratedScalpel)
+ return new Scalpel::ScalpelScreen(vm);
+ else
+ return new Screen(vm);
+}
+
Screen::Screen(SherlockEngine *vm) : Surface(g_system->getWidth(), g_system->getHeight()), _vm(vm),
_backBuffer1(g_system->getWidth(), g_system->getHeight()),
_backBuffer2(g_system->getWidth(), g_system->getHeight()),
_backBuffer(&_backBuffer1) {
_transitionSeed = 1;
_fadeStyle = false;
- _font = nullptr;
- _fontHeight = 0;
Common::fill(&_cMap[0], &_cMap[PALETTE_SIZE], 0);
Common::fill(&_sMap[0], &_sMap[PALETTE_SIZE], 0);
Common::fill(&_tMap[0], &_tMap[PALETTE_SIZE], 0);
+
+ // Set up the initial font
setFont(IS_SERRATED_SCALPEL ? 1 : 4);
// Rose Tattoo specific fields
_fadeBytesRead = _fadeBytesToRead = 0;
_oldFadePercent = 0;
- _scrollSize = 0;
- _scrollSpeed = 0;
- _currentScroll = 0;
- _targetScroll = 0;
_flushScreen = false;
}
Screen::~Screen() {
- delete _font;
-}
-
-void Screen::setFont(int fontNumb) {
- // Interactive demo doesn't use fonts
- if (!_vm->_interactiveFl)
- return;
-
- _fontNumber = fontNumb;
- Common::String fname = Common::String::format("FONT%d.VGS", fontNumb + 1);
-
- // Discard any previous font and read in new one
- delete _font;
- _font = new ImageFile(fname);
-
- // Iterate through the frames to find the tallest font character
- _fontHeight = 0;
- for (uint idx = 0; idx < _font->size(); ++idx)
- _fontHeight = MAX((uint16)_fontHeight, (*_font)[idx]._frame.h);
+ Fonts::free();
}
void Screen::update() {
@@ -91,6 +77,10 @@ void Screen::update() {
_dirtyRects.clear();
}
+void Screen::makeAllDirty() {
+ addDirtyRect(Common::Rect(0, 0, this->w(), this->h()));
+}
+
void Screen::getPalette(byte palette[PALETTE_SIZE]) {
g_system->getPaletteManager()->grabPalette(palette, 0, PALETTE_COUNT);
}
@@ -229,14 +219,133 @@ void Screen::verticalTransition() {
}
}
-void Screen::restoreBackground(const Common::Rect &r) {
- if (r.width() > 0 && r.height() > 0) {
- Common::Rect tempRect = r;
- tempRect.clip(Common::Rect(0, 0, this->w(), SHERLOCK_SCENE_HEIGHT));
+void Screen::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 = this->w();
+ uint16 screenHeight = this->h();
+ uint16 screenX = 0;
+ uint16 screenY = 0;
+ uint16 pixelsChanged = 0;
+
+ _dirtyRects.clear();
+
+ 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;
+ }
+ }
+ *currentScreenPtr = currentScreenPixelRed | currentScreenPixelGreen | currentScreenPixelBlue;
+ pixelsChanged++;
+ }
+
+ currentScreenPtr++;
+ targetScreenPtr++;
+ }
+ }
+
+ // Too much considered dirty at the moment
+ addDirtyRect(Common::Rect(0, 0, screenWidth, screenHeight));
- if (tempRect.isValidRect())
- _backBuffer1.blitFrom(_backBuffer2, Common::Point(tempRect.left, tempRect.top), tempRect);
+ events.pollEvents();
+ events.delay(10 * speed);
+ } while ((pixelsChanged) && (!_vm->shouldQuit()));
+}
+
+void Screen::blitFrom3DOcolorLimit(uint16 limitColor) {
+ uint16 *currentScreenPtr = (uint16 *)getPixels();
+ uint16 *targetScreenPtr = (uint16 *)_backBuffer->getPixels();
+ uint16 currentScreenPixel = 0;
+
+ uint16 screenWidth = this->w();
+ uint16 screenHeight = this->h();
+ 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;
+
+ *currentScreenPtr = currentScreenPixelRed | currentScreenPixelGreen | currentScreenPixelBlue;
+ currentScreenPtr++;
+ targetScreenPtr++;
+ }
}
+
+ // Too much considered dirty at the moment
+ addDirtyRect(Common::Rect(0, 0, screenWidth, screenHeight));
+}
+
+void Screen::restoreBackground(const Common::Rect &r) {
+ if (r.width() > 0 && r.height() > 0)
+ _backBuffer1.blitFrom(_backBuffer2, Common::Point(r.left, r.top), r);
}
void Screen::slamArea(int16 xp, int16 yp, int16 width, int16 height) {
@@ -245,14 +354,33 @@ void Screen::slamArea(int16 xp, int16 yp, int16 width, int16 height) {
void Screen::slamRect(const Common::Rect &r) {
if (r.width() && r.height() > 0) {
- Common::Rect tempRect = r;
- tempRect.clip(Common::Rect(0, 0, this->w(), this->h()));
+ Common::Rect srcRect = r, destRect = r;
+
+ destRect.translate(-_currentScroll.x, -_currentScroll.y);
+
+ if (destRect.left < 0) {
+ srcRect.left += -destRect.left;
+ destRect.left = 0;
+ }
+ if (destRect.top < 0) {
+ srcRect.top += -destRect.top;
+ destRect.top = 0;
+ }
+ if (destRect.right > SHERLOCK_SCREEN_WIDTH) {
+ srcRect.right -= (destRect.left - SHERLOCK_SCREEN_WIDTH);
+ destRect.right = SHERLOCK_SCREEN_WIDTH;
+ }
+ if (destRect.bottom > SHERLOCK_SCREEN_HEIGHT) {
+ srcRect.bottom -= (destRect.bottom - SHERLOCK_SCREEN_HEIGHT);
+ destRect.bottom = SHERLOCK_SCREEN_HEIGHT;
+ }
- if (tempRect.isValidRect())
- blitFrom(*_backBuffer, Common::Point(tempRect.left, tempRect.top), tempRect);
+ if (srcRect.isValidRect())
+ blitFrom(*_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;
@@ -283,7 +411,7 @@ void Screen::flushImage(ImageFrame *frame, const Common::Point &pt, int16 *xp, i
void Screen::flushScaleImage(ImageFrame *frame, const Common::Point &pt, int16 *xp, int16 *yp,
int16 *width, int16 *height, int scaleVal) {
- Common::Point imgPos = pt + frame->_offset;
+ Common::Point imgPos(pt.x + frame->sDrawXOffset(scaleVal), pt.y + frame->sDrawYOffset(scaleVal));
Common::Rect newBounds(imgPos.x, imgPos.y, imgPos.x + frame->sDrawXSize(scaleVal),
imgPos.y + frame->sDrawYSize(scaleVal));
Common::Rect oldBounds(*xp, *yp, *xp + *width, *yp + *height);
@@ -310,6 +438,28 @@ void Screen::flushScaleImage(ImageFrame *frame, const Common::Point &pt, int16 *
*height = newBounds.height();
}
+void Screen::flushImage(ImageFrame *frame, const Common::Point &pt, Common::Rect &newBounds, int scaleVal) {
+ Common::Point newPos(newBounds.left, newBounds.top);
+ Common::Point newSize(newBounds.width(), newBounds.height());
+
+ if (scaleVal == SCALE_THRESHOLD)
+ flushImage(frame, pt, &newPos.x, &newPos.y, &newSize.x, &newSize.y);
+ else
+ flushScaleImage(frame, pt, &newPos.x, &newPos.y, &newSize.x, &newSize.y, scaleVal);
+
+ // Transfer the pos and size amounts into a single bounds rect
+ newBounds = Common::Rect(newPos.x, newPos.y, newPos.x + newSize.x, newPos.y + newSize.y);
+}
+
+void Screen::blockMove(const Common::Rect &r) {
+ Common::Rect bounds = r;
+ slamRect(bounds);
+}
+
+void Screen::blockMove() {
+ blockMove(Common::Rect(0, 0, w(), h()));
+}
+
void Screen::print(const Common::Point &pt, byte color, const char *formatStr, ...) {
// Create the string to display
va_list args;
@@ -349,37 +499,8 @@ void Screen::gPrint(const Common::Point &pt, byte color, const char *formatStr,
writeString(str, pt, color);
}
-int Screen::stringWidth(const Common::String &str) {
- int width = 0;
-
- for (const char *c = str.c_str(); *c; ++c)
- width += charWidth(*c);
-
- return width;
-}
-
-int Screen::charWidth(char c) {
- if (c == ' ')
- return 5;
- else if (Common::isPrint(c))
- return (*_font)[c - 33]._frame.w + 1;
- else
- return 0;
-}
-
-void Screen::writeString(const Common::String &str, const Common::Point &pt, byte color) {
- Common::Point charPos = pt;
-
- for (const char *c = str.c_str(); *c; ++c) {
- if (*c == ' ')
- charPos.x += 5;
- else {
- assert(Common::isPrint(*c));
- ImageFrame &frame = (*_font)[*c - 33];
- _backBuffer->transBlitFrom(frame, charPos, false, color);
- charPos.x += frame._frame.w + 1;
- }
- }
+void Screen::writeString(const Common::String &str, const Common::Point &pt, byte overrideColor) {
+ Fonts::writeString(_backBuffer, str, pt, overrideColor);
}
void Screen::vgaBar(const Common::Rect &r, int color) {
@@ -387,67 +508,8 @@ void Screen::vgaBar(const Common::Rect &r, int color) {
slamRect(r);
}
-void Screen::makeButton(const Common::Rect &bounds, int textX,
- const Common::String &str) {
-
- 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);
-}
-
-void Screen::buttonPrint(const Common::Point &pt, byte color, bool slamIt,
- const Common::String &str) {
- int xStart = pt.x - stringWidth(str) / 2;
-
- 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());
- } else {
- gPrint(Common::Point(xStart, pt.y), color, "%s", str.c_str());
- }
-}
-
-void Screen::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 Screen::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 Screen::setDisplayBounds(const Common::Rect &r) {
- assert(r.left == 0 && r.top == 0);
- _sceneSurface.setPixels(_backBuffer1.getPixels(), r.width(), r.height());
+ _sceneSurface.setPixels(_backBuffer1.getBasePtr(r.left, r.top), r.width(), r.height(), _backBuffer1.getPixelFormat());
_backBuffer = &_sceneSurface;
}
@@ -461,7 +523,7 @@ Common::Rect Screen::getDisplayBounds() {
Common::Rect(0, 0, this->w(), this->h());
}
-void Screen::synchronize(Common::Serializer &s) {
+void Screen::synchronize(Serializer &s) {
int fontNumb = _fontNumber;
s.syncAsByte(fontNumb);
if (s.isLoading())
@@ -484,22 +546,6 @@ int Screen::fadeRead(Common::SeekableReadStream &stream, byte *buf, int totalSiz
return totalSize;
}
-/**
- * Creates a grey-scale version of the passed palette
- */
-void Screen::setupBGArea(const byte cMap[PALETTE_SIZE]) {
- warning("TODO");
-}
-
-/**
- * Initializes scroll variables
- */
-void Screen::initScrollVars() {
- _scrollSize = 0;
- _currentScroll = 0;
- _targetScroll = 0;
-}
-
void Screen::translatePalette(byte palette[PALETTE_SIZE]) {
for (int idx = 0; idx < PALETTE_SIZE; ++idx)
palette[idx] = VGA_COLOR_TRANS(palette[idx]);
diff --git a/engines/sherlock/screen.h b/engines/sherlock/screen.h
index 8fda9cbb9c..2e0cef72ca 100644
--- a/engines/sherlock/screen.h
+++ b/engines/sherlock/screen.h
@@ -25,33 +25,25 @@
#include "common/list.h"
#include "common/rect.h"
-#include "common/serializer.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
enum {
+ BLACK = 0,
INFO_BLACK = 1,
- INFO_FOREGROUND = 11,
- INFO_BACKGROUND = 1,
BORDER_COLOR = 237,
- INV_FOREGROUND = 14,
- INV_BACKGROUND = 1,
- COMMAND_HIGHLIGHTED = 10,
- COMMAND_FOREGROUND = 15,
COMMAND_BACKGROUND = 4,
- COMMAND_NULL = 248,
- BUTTON_TOP = 233,
- BUTTON_MIDDLE = 244,
- BUTTON_BOTTOM = 248,
+ BUTTON_BACKGROUND = 235,
TALK_FOREGROUND = 12,
- TALK_NULL = 16,
- PEN_COLOR = 250
+ TALK_NULL = 16
};
class SherlockEngine;
@@ -59,18 +51,13 @@ class SherlockEngine;
class Screen : public Surface {
private:
SherlockEngine *_vm;
- int _fontNumber;
Common::List<Common::Rect> _dirtyRects;
uint32 _transitionSeed;
- ImageFile *_font;
- int _fontHeight;
Surface _sceneSurface;
// Rose Tattoo fields
int _fadeBytesRead, _fadeBytesToRead;
int _oldFadePercent;
- byte _lookupTable[PALETTE_COUNT];
- byte _lookupTable1[PALETTE_COUNT];
private:
/**
* Merges together overlapping dirty areas of the screen
@@ -81,11 +68,6 @@ private:
* Returns the union of two dirty area rectangles
*/
bool unionRectangle(Common::Rect &destRect, const Common::Rect &src1, const Common::Rect &src2);
-
- /**
- * Draws the given string into the back buffer using the images stored in _font
- */
- void writeString(const Common::String &str, const Common::Point &pt, byte color);
protected:
/**
* Adds a rectangle to the list of modified areas of the screen during the
@@ -99,22 +81,22 @@ public:
byte _cMap[PALETTE_SIZE];
byte _sMap[PALETTE_SIZE];
byte _tMap[PALETTE_SIZE];
- int _currentScroll, _targetScroll;
- int _scrollSize, _scrollSpeed;
bool _flushScreen;
+ Common::Point _currentScroll;
public:
+ static Screen *init(SherlockEngine *vm);
Screen(SherlockEngine *vm);
virtual ~Screen();
/**
- * Set the font to use for writing text on the screen
+ * Handles updating any dirty areas of the screen Surface object to the physical screen
*/
- void setFont(int fontNumber);
+ void update();
/**
- * Handles updating any dirty areas of the screen Surface object to the physical screen
+ * Makes the whole screen dirty, Hack for 3DO movie playing
*/
- void update();
+ void makeAllDirty();
/**
* Return the currently active palette
@@ -152,6 +134,13 @@ public:
void verticalTransition();
/**
+ * Fade backbuffer 1 into screen (3DO RGB!)
+ */
+ void fadeIntoScreen3DO(int speed);
+
+ void blitFrom3DOcolorLimit(uint16 color);
+
+ /**
* Prints the text passed onto the back buffer at the given position and color.
* The string is then blitted to the screen
*/
@@ -192,41 +181,24 @@ public:
int16 *width, int16 *height, int scaleVal);
/**
- * Returns the width of a string in pixels
- */
- int stringWidth(const Common::String &str);
-
- /**
- * Returns the width of a character in pixels
+ * Variation of flushImage/flushScaleImage that takes in and updates a rect
*/
- int charWidth(char c);
+ void flushImage(ImageFrame *frame, const Common::Point &pt, Common::Rect &newBounds, int scaleVal);
/**
- * Fills an area on the back buffer, and then copies it to the screen
+ * Copies data from the back buffer to the screen
*/
- void vgaBar(const Common::Rect &r, int color);
+ void blockMove(const Common::Rect &r);
/**
- * Draws a button for use in the inventory, talk, and examine dialogs.
+ * Copies the entire screen from the back buffer
*/
- void makeButton(const Common::Rect &bounds, int textX, const Common::String &str);
+ void blockMove();
/**
- * Prints an interface command with the first letter highlighted to indicate
- * what keyboard shortcut is associated with it
- */
- void buttonPrint(const Common::Point &pt, byte color, bool slamIt, const Common::String &str);
-
- /**
- * Draw a panel in the back buffer with a raised area effect around the edges
- */
- void makePanel(const Common::Rect &r);
-
- /**
- * Draw a field in the back buffer with a raised area effect around the edges,
- * suitable for text input.
+ * Fills an area on the back buffer, and then copies it to the screen
*/
- void makeField(const Common::Rect &r);
+ void vgaBar(const Common::Rect &r, int color);
/**
* Sets the active back buffer pointer to a restricted sub-area of the first back buffer
@@ -243,22 +215,22 @@ public:
*/
Common::Rect getDisplayBounds();
- int fontNumber() const { return _fontNumber; }
-
/**
* Synchronize the data for a savegame
*/
- void synchronize(Common::Serializer &s);
+ void synchronize(Serializer &s);
+
+ /**
+ * Draws the given string into the back buffer using the images stored in _font
+ */
+ virtual void writeString(const Common::String &str, const Common::Point &pt, byte overrideColor);
+
// Rose Tattoo specific methods
void initPaletteFade(int bytesToRead);
int fadeRead(Common::SeekableReadStream &stream, byte *buf, int totalSize);
- void setupBGArea(const byte cMap[PALETTE_SIZE]);
-
- void initScrollVars();
-
/**
* Translate a palette from 6-bit RGB values to full 8-bit values suitable for passing
* to the underlying palette manager
diff --git a/engines/sherlock/sherlock.cpp b/engines/sherlock/sherlock.cpp
index d3a409a67b..ae77c91009 100644
--- a/engines/sherlock/sherlock.cpp
+++ b/engines/sherlock/sherlock.cpp
@@ -33,6 +33,7 @@ SherlockEngine::SherlockEngine(OSystem *syst, const SherlockGameDescription *gam
_animation = nullptr;
_debugger = nullptr;
_events = nullptr;
+ _fixedText = nullptr;
_inventory = nullptr;
_journal = nullptr;
_map = nullptr;
@@ -56,13 +57,14 @@ SherlockEngine::~SherlockEngine() {
delete _animation;
delete _debugger;
delete _events;
+ delete _fixedText;
delete _journal;
delete _map;
- delete _music;
delete _people;
delete _saves;
delete _scene;
delete _screen;
+ delete _music;
delete _sound;
delete _talk;
delete _ui;
@@ -71,11 +73,15 @@ SherlockEngine::~SherlockEngine() {
}
void SherlockEngine::initialize() {
- DebugMan.addDebugChannel(kDebugScript, "scripts", "Script debug level");
+ DebugMan.addDebugChannel(kDebugLevelScript, "scripts", "Script debug level");
+ DebugMan.addDebugChannel(kDebugLevelAdLibDriver, "AdLib", "AdLib driver debugging");
+ DebugMan.addDebugChannel(kDebugLevelMT32Driver, "MT32", "MT32 driver debugging");
+ DebugMan.addDebugChannel(kDebugLevelMusic, "Music", "Music debugging");
+ Fonts::setVm(this);
ImageFile::setVm(this);
- Object::setVm(this);
- Sprite::setVm(this);
+ ImageFile3DO::setVm(this);
+ BaseObject::setVm(this);
if (isDemo()) {
Common::File f;
@@ -87,22 +93,29 @@ void SherlockEngine::initialize() {
_res = new Resources(this);
_animation = new Animation(this);
- _debugger = new Debugger(this);
+ _debugger = Debugger::init(this);
_events = new Events(this);
- _inventory = new Inventory(this);
- _map = new Map(this);
+ _fixedText = FixedText::init(this);
+ _inventory = Inventory::init(this);
+ _map = Map::init(this);
_music = new Music(this, _mixer);
- _journal = new Journal(this);
- _people = new People(this);
- _saves = new SaveManager(this, _targetName);
+ _journal = Journal::init(this);
+ _people = People::init(this);
+ _saves = SaveManager::init(this, _targetName);
_scene = Scene::init(this);
- _screen = new Screen(this);
+ _screen = Screen::init(this);
_sound = new Sound(this, _mixer);
_talk = Talk::init(this);
_ui = UserInterface::init(this);
// Load game settings
loadConfig();
+
+ if (getPlatform() == Common::kPlatform3DO) {
+ // Disable portraits on 3DO
+ // 3DO does not include portrait data
+ _people->_portraitsOn = false;
+ }
}
Common::Error SherlockEngine::run() {
@@ -115,7 +128,7 @@ Common::Error SherlockEngine::run() {
// If requested, load a savegame instead of showing the intro
if (ConfMan.hasKey("save_slot")) {
int saveSlot = ConfMan.getInt("save_slot");
- if (saveSlot >= 1 && saveSlot <= MAX_SAVEGAME_SLOTS)
+ if (saveSlot >= 0 && saveSlot <= MAX_SAVEGAME_SLOTS)
_loadGameSlot = saveSlot;
}
@@ -166,7 +179,7 @@ void SherlockEngine::sceneLoop() {
// Handle any input from the keyboard or mouse
handleInput();
- if (_people->_hSavedPos.x == -1) {
+ if (_people->_savedPos.x == -1) {
_canLoadSave = true;
_scene->doBgAnim();
_canLoadSave = false;
@@ -175,11 +188,10 @@ void SherlockEngine::sceneLoop() {
_scene->freeScene();
_people->freeWalk();
-
}
void SherlockEngine::handleInput() {
- _canLoadSave = true;
+ _canLoadSave = _ui->_menuMode == STD_MODE || _ui->_menuMode == LAB_MODE;
_events->pollEventsAndWait();
_canLoadSave = false;
@@ -203,11 +215,15 @@ void SherlockEngine::setFlags(int flagNum) {
_scene->checkSceneFlags(true);
}
+void SherlockEngine::setFlagsDirect(int flagNum) {
+ _flags[ABS(flagNum)] = flagNum >= 0;
+}
+
void SherlockEngine::loadConfig() {
// Load sound settings
syncSoundSettings();
- ConfMan.registerDefault("font", 1);
+ ConfMan.registerDefault("font", getGameID() == GType_SerratedScalpel ? 1 : 4);
_screen->setFont(ConfMan.getInt("font"));
if (getGameID() == GType_SerratedScalpel)
@@ -240,7 +256,7 @@ void SherlockEngine::syncSoundSettings() {
_music->syncMusicSettings();
}
-void SherlockEngine::synchronize(Common::Serializer &s) {
+void SherlockEngine::synchronize(Serializer &s) {
for (uint idx = 0; idx < _flags.size(); ++idx)
s.syncAsByte(_flags[idx]);
}
@@ -263,4 +279,4 @@ Common::Error SherlockEngine::saveGameState(int slot, const Common::String &desc
return Common::kNoError;
}
-} // End of namespace Comet
+} // End of namespace Sherlock
diff --git a/engines/sherlock/sherlock.h b/engines/sherlock/sherlock.h
index e71c729893..c05680eb08 100644
--- a/engines/sherlock/sherlock.h
+++ b/engines/sherlock/sherlock.h
@@ -35,6 +35,7 @@
#include "sherlock/animation.h"
#include "sherlock/debugger.h"
#include "sherlock/events.h"
+#include "sherlock/fixed_text.h"
#include "sherlock/inventory.h"
#include "sherlock/journal.h"
#include "sherlock/map.h"
@@ -51,7 +52,10 @@
namespace Sherlock {
enum {
- kDebugScript = 1 << 0
+ kDebugLevelScript = 1 << 0,
+ kDebugLevelAdLibDriver = 2 << 0,
+ kDebugLevelMT32Driver = 3 << 0,
+ kDebugLevelMusic = 4 << 0
};
enum GameType {
@@ -61,7 +65,14 @@ enum GameType {
#define SHERLOCK_SCREEN_WIDTH _vm->_screen->w()
#define SHERLOCK_SCREEN_HEIGHT _vm->_screen->h()
+#define SHERLOCK_SCENE_WIDTH _vm->_screen->_backBuffer1.w()
#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)
+
+#define COL_INFO_FOREGROUND (IS_SERRATED_SCALPEL ? (byte)Scalpel::INFO_FOREGROUND : (byte)Tattoo::INFO_FOREGROUND)
+#define COL_PEN_COLOR (IS_SERRATED_SCALPEL ? (byte)Scalpel::PEN_COLOR : (byte)Tattoo::PEN_COLOR)
+#define COL_PEN_HIGHLIGHT (IS_SERRATED_SCALPEL ? 15 : 129)
struct SherlockGameDescription;
@@ -78,11 +89,6 @@ private:
* Handle all player input
*/
void handleInput();
-
- /**
- * Load game configuration esttings
- */
- void loadConfig();
protected:
/**
* Does basic initialization of the game engine
@@ -97,11 +103,17 @@ protected:
* Returns a list of features the game itself supports
*/
virtual bool hasFeature(EngineFeature f) const;
+
+ /**
+ * Load game configuration esttings
+ */
+ virtual void loadConfig();
public:
const SherlockGameDescription *_gameDescription;
Animation *_animation;
Debugger *_debugger;
Events *_events;
+ FixedText *_fixedText;
Inventory *_inventory;
Journal *_journal;
Map *_map;
@@ -156,6 +168,11 @@ public:
virtual void syncSoundSettings();
/**
+ * Saves game configuration information
+ */
+ virtual void saveConfig();
+
+ /**
* Returns whether the version is a demo
*/
virtual bool isDemo() const;
@@ -171,6 +188,11 @@ public:
Common::Platform getPlatform() const;
/**
+ * Return the game's language
+ */
+ Common::Language getLanguage() const;
+
+ /**
* Return a random number
*/
int getRandomNumber(int limit) { return _randomSource.getRandomNumber(limit - 1); }
@@ -189,18 +211,20 @@ public:
void setFlags(int flagNum);
/**
- * Saves game configuration information
+ * Set a global flag to 0 or 1 depending on whether the passed flag is negative or positive.
+ * @remarks We don't use the global setFlags method because we don't want to check scene flags
*/
- void saveConfig();
+ void setFlagsDirect(int flagNum);
/**
* Synchronize the data for a savegame
*/
- void synchronize(Common::Serializer &s);
+ void synchronize(Serializer &s);
};
#define IS_ROSE_TATTOO (_vm->getGameID() == GType_RoseTattoo)
#define IS_SERRATED_SCALPEL (_vm->getGameID() == GType_SerratedScalpel)
+#define IS_3DO (_vm->getPlatform() == Common::kPlatform3DO)
} // End of namespace Sherlock
diff --git a/engines/sherlock/sound.cpp b/engines/sherlock/sound.cpp
index 390576e98e..fd51462bc0 100644
--- a/engines/sherlock/sound.cpp
+++ b/engines/sherlock/sound.cpp
@@ -27,6 +27,8 @@
#include "common/algorithm.h"
#include "audio/mixer.h"
#include "audio/decoders/raw.h"
+#include "audio/decoders/aiff.h"
+#include "audio/decoders/wave.h"
namespace Sherlock {
@@ -53,17 +55,19 @@ static const uint8 creativeADPCM_AdjustMap[64] = {
Sound::Sound(SherlockEngine *vm, Audio::Mixer *mixer) : _vm(vm), _mixer(mixer) {
_digitized = false;
_voices = 0;
- _diskSoundPlaying = false;
_soundPlaying = false;
- _soundIsOn = &_soundPlaying;
+ _speechPlaying = false;
_curPriority = 0;
- _digiBuf = nullptr;
- _midiDrvLoaded = false;
- _musicVolume = 0;
+ _soundVolume = 255;
_soundOn = true;
_speechOn = true;
+ if (IS_3DO) {
+ // 3DO: we don't need to prepare anything for sound
+ return;
+ }
+
_vm->_res->addToCache("MUSIC.LIB");
if (!_vm->_interactiveFl)
_vm->_res->addToCache("TITLE.SND");
@@ -85,12 +89,13 @@ Sound::Sound(SherlockEngine *vm, Audio::Mixer *mixer) : _vm(vm), _mixer(mixer) {
void Sound::syncSoundSettings() {
_digitized = !ConfMan.getBool("mute");
- _voices = !ConfMan.getBool("mute") && !ConfMan.getBool("speech_mute") ? 1 : 0;
+ _speechOn = !ConfMan.getBool("mute") && !ConfMan.getBool("speech_mute");
+ _voices = _speechOn ? 1 : 0;
}
void Sound::loadSound(const Common::String &name, int priority) {
// No implementation required in ScummVM
- warning("loadSound");
+ //warning("loadSound");
}
byte Sound::decodeSample(byte sample, byte &reference, int16 &scale) {
@@ -116,59 +121,34 @@ byte Sound::decodeSample(byte sample, byte &reference, int16 &scale) {
}
bool Sound::playSound(const Common::String &name, WaitType waitType, int priority, const char *libraryFilename) {
- Resources &res = *_vm->_res;
stopSound();
Common::String filename = name;
- if (!filename.contains('.'))
- filename += ".SND";
-
- Common::String libFilename(libraryFilename);
- Common::SeekableReadStream *stream = libFilename.empty() ? res.load(filename) : res.load(filename, libFilename);
-
- if (!stream)
- error("Unable to find sound file '%s'", filename.c_str());
-
- stream->skip(2);
- int size = stream->readUint32BE();
- int rate = stream->readUint16BE();
- byte *data = (byte *)malloc(size);
- byte *ptr = data;
- stream->read(ptr, size);
- delete stream;
-
- assert(size > 2);
-
- byte *decoded = (byte *)malloc((size - 1) * 2);
-
- // Holmes uses Creative ADPCM 4-bit data
- int counter = 0;
- byte reference = ptr[0];
- int16 scale = 0;
-
- for(int i = 1; i < size; i++) {
- decoded[counter++] = decodeSample((ptr[i]>>4)&0x0f, reference, scale);
- decoded[counter++] = decodeSample((ptr[i]>>0)&0x0f, reference, scale);
+ 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;
+ }
+ }
}
- free(data);
-
-#if 0
- // Debug : used to dump files
- Common::DumpFile outFile;
- outFile.open(filename);
- outFile.write(decoded, (size - 2) * 2);
- outFile.flush();
- outFile.close();
-#endif
+ 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());
- Audio::AudioStream *audioStream = Audio::makeRawStream(decoded, (size - 2) * 2, rate, Audio::FLAG_UNSIGNED, DisposeAfterUse::YES);
- _mixer->playStream(Audio::Mixer::kPlainSoundType, &_effectsHandle, audioStream, -1, Audio::Mixer::kMaxChannelVolume);
_soundPlaying = true;
_curPriority = priority;
if (waitType == WAIT_RETURN_IMMEDIATELY) {
- _diskSoundPlaying = true;
return true;
}
@@ -180,22 +160,23 @@ bool Sound::playSound(const Common::String &name, WaitType waitType, int priorit
retval = false;
break;
}
- } while (!_vm->shouldQuit() && _mixer->isSoundHandleActive(_effectsHandle));
+ } while (!_vm->shouldQuit() && _mixer->isSoundHandleActive(soundHandle));
_soundPlaying = false;
- _mixer->stopHandle(_effectsHandle);
+ _mixer->stopHandle(soundHandle);
return retval;
}
void Sound::playLoadedSound(int bufNum, WaitType waitType) {
- if (_mixer->isSoundHandleActive(_effectsHandle) && (_curPriority > _vm->_scene->_sounds[bufNum]._priority))
- return;
+ if (IS_SERRATED_SCALPEL) {
+ if (_mixer->isSoundHandleActive(_scalpelEffectsHandle) && (_curPriority > _vm->_scene->_sounds[bufNum]._priority))
+ return;
- stopSound();
- playSound(_vm->_scene->_sounds[bufNum]._name, waitType, _vm->_scene->_sounds[bufNum]._priority);
+ stopSound();
+ }
- return;
+ playSound(_vm->_scene->_sounds[bufNum]._name, waitType, _vm->_scene->_sounds[bufNum]._priority);
}
void Sound::freeLoadedSounds() {
@@ -205,23 +186,117 @@ void Sound::freeLoadedSounds() {
}
void Sound::stopSound() {
- _mixer->stopHandle(_effectsHandle);
-}
-
-void Sound::stopSndFuncPtr(int v1, int v2) {
- // TODO
- warning("TODO: Sound::stopSndFuncPtr");
+ if (IS_SERRATED_SCALPEL) {
+ _mixer->stopHandle(_scalpelEffectsHandle);
+ } else {
+ for (int i = 0; i < MAX_MIXER_CHANNELS; i++)
+ _mixer->stopHandle(_tattooEffectsHandle[i]);
+ }
}
void Sound::freeDigiSound() {
- delete[] _digiBuf;
- _digiBuf = nullptr;
- _diskSoundPlaying = false;
_soundPlaying = false;
}
-void Sound::setMIDIVolume(int volume) {
- // TODO
+Audio::SoundHandle Sound::getFreeSoundHandle() {
+ for (int i = 0; i < MAX_MIXER_CHANNELS; i++) {
+ if (!_mixer->isSoundHandleActive(_tattooEffectsHandle[i]))
+ return _tattooEffectsHandle[i];
+ }
+
+ error("getFreeSoundHandle: No sound handle found");
+}
+
+void Sound::setVolume(int volume) {
+ warning("TODO: setVolume - %d", 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";
+
+ // 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);
+
+ if (playSoundResource(name, libraryName, Audio::Mixer::kSpeechSoundType, _speechHandle))
+ _speechPlaying = true;
+}
+
+void Sound::stopSpeech() {
+ _mixer->stopHandle(_speechHandle);
+ _speechPlaying = false;
+}
+
+bool Sound::isSpeechPlaying() {
+ _speechPlaying = _mixer->isSoundHandleActive(_speechHandle);
+ return _speechPlaying;
+}
+
+bool Sound::playSoundResource(const Common::String &name, const Common::String &libFilename,
+ Audio::Mixer::SoundType soundType, Audio::SoundHandle &handle) {
+ Resources &res = *_vm->_res;
+ Common::SeekableReadStream *stream = libFilename.empty() ? res.load(name) : res.load(name, libFilename, true);
+ if (!stream)
+ return false;
+
+ Audio::AudioStream *audioStream;
+ if (IS_ROSE_TATTOO && soundType == Audio::Mixer::kSpeechSoundType) {
+ audioStream = Audio::makeRawStream(stream, 11025, Audio::FLAG_UNSIGNED);
+ } else if (IS_3DO) {
+ // 3DO: AIFF file
+ audioStream = Audio::makeAIFFStream(stream, DisposeAfterUse::YES);
+ } else if (IS_SERRATED_SCALPEL) {
+ stream->skip(2);
+ int size = stream->readUint32BE();
+ int rate = stream->readUint16BE();
+ byte *data = (byte *)malloc(size);
+ byte *ptr = data;
+ stream->read(ptr, size);
+ delete stream;
+
+ assert(size > 2);
+
+ byte *decoded = (byte *)malloc((size - 1) * 2);
+
+ // Holmes uses Creative ADPCM 4-bit data
+ int counter = 0;
+ byte reference = ptr[0];
+ int16 scale = 0;
+
+ for (int i = 1; i < size; i++) {
+ decoded[counter++] = decodeSample((ptr[i] >> 4) & 0x0f, reference, scale);
+ decoded[counter++] = decodeSample((ptr[i] >> 0) & 0x0f, reference, scale);
+ }
+
+ free(data);
+
+ audioStream = Audio::makeRawStream(decoded, (size - 2) * 2, rate, Audio::FLAG_UNSIGNED, DisposeAfterUse::YES);
+ } else {
+ audioStream = Audio::makeWAVStream(stream, DisposeAfterUse::YES);
+ }
+
+ if (!audioStream)
+ return false;
+
+ _mixer->playStream(soundType, &handle, audioStream, -1, Audio::Mixer::kMaxChannelVolume);
+ return true;
}
} // End of namespace Sherlock
diff --git a/engines/sherlock/sound.h b/engines/sherlock/sound.h
index e1c0777763..b2d1584e85 100644
--- a/engines/sherlock/sound.h
+++ b/engines/sherlock/sound.h
@@ -39,26 +39,37 @@ enum WaitType {
WAIT_RETURN_IMMEDIATELY = 0, WAIT_FINISH = 1, WAIT_KBD_OR_FINISH = 2
};
+#define MAX_MIXER_CHANNELS 10
+
class Sound {
private:
SherlockEngine *_vm;
Audio::Mixer *_mixer;
- Audio::SoundHandle _effectsHandle;
+ Audio::SoundHandle _scalpelEffectsHandle;
+ Audio::SoundHandle _tattooEffectsHandle[MAX_MIXER_CHANNELS];
+ Audio::SoundHandle _speechHandle;
int _curPriority;
+ /**
+ * Decode a sound sample
+ */
byte decodeSample(byte sample, byte& reference, int16& scale);
+
+ /**
+ * Handle playing a sound or speech
+ */
+ bool playSoundResource(const Common::String &name, const Common::String &libFilename,
+ Audio::Mixer::SoundType soundType, Audio::SoundHandle &handle);
public:
bool _digitized;
int _voices;
bool _soundOn;
bool _speechOn;
- bool _diskSoundPlaying;
bool _soundPlaying;
- bool *_soundIsOn;
- byte *_digiBuf;
- bool _midiDrvLoaded;
- Common::String _currentSongName, _nextSongName;
- int _musicVolume;
+ bool _speechPlaying;
+ int _soundVolume;
+
+ Common::String _talkSoundFile;
public:
Sound(SherlockEngine *vm, Audio::Mixer *mixer);
@@ -92,9 +103,26 @@ public:
*/
void stopSound();
- void stopSndFuncPtr(int v1, int v2);
void freeDigiSound();
- void setMIDIVolume(int volume);
+
+ Audio::SoundHandle getFreeSoundHandle();
+
+ void setVolume(int volume);
+
+ /**
+ * Play a specified voice resource
+ */
+ void playSpeech(const Common::String &name);
+
+ /**
+ * Stop any currently playing speech
+ */
+ void stopSpeech();
+
+ /**
+ * Returns true if speech is currently playing
+ */
+ bool isSpeechPlaying();
};
} // End of namespace Sherlock
diff --git a/engines/sherlock/surface.cpp b/engines/sherlock/surface.cpp
index 5a9e59e01b..b56692c704 100644
--- a/engines/sherlock/surface.cpp
+++ b/engines/sherlock/surface.cpp
@@ -28,11 +28,11 @@
namespace Sherlock {
-Surface::Surface(uint16 width, uint16 height) : _freePixels(true) {
+Surface::Surface(uint16 width, uint16 height) : Fonts(), _freePixels(true) {
create(width, height);
}
-Surface::Surface() : _freePixels(false) {
+Surface::Surface() : Fonts(), _freePixels(false) {
}
Surface::~Surface() {
@@ -44,10 +44,18 @@ void Surface::create(uint16 width, uint16 height) {
if (_freePixels)
_surface.free();
- _surface.create(width, height, Graphics::PixelFormat::createFormatCLUT8());
+ 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));
}
@@ -92,17 +100,51 @@ void Surface::blitFrom(const Surface &src, const Common::Point &pt, const Common
}
void Surface::transBlitFrom(const ImageFrame &src, const Common::Point &pt,
- bool flipped, int overrideColor) {
- transBlitFrom(src._frame, pt + src._offset, flipped, overrideColor);
+ 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) {
+ bool flipped, int overrideColor, int scaleVal) {
const Graphics::Surface &s = src._surface;
- transBlitFrom(s, pt, flipped, overrideColor);
+ 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);
@@ -120,19 +162,42 @@ void Surface::transBlitFrom(const Graphics::Surface &src, const Common::Point &p
addDirtyRect(Common::Rect(destPt.x, destPt.y, destPt.x + drawRect.width(),
destPt.y + drawRect.height()));
- // Draw loop
- const int TRANSPARENCY = 0xFF;
- 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;
+ 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;
}
}
@@ -145,6 +210,10 @@ void Surface::fillRect(const Common::Rect &r, byte color) {
addDirtyRect(r);
}
+void Surface::fill(uint16 color) {
+ _surface.fillRect(Common::Rect(_surface.w, _surface.h), color);
+}
+
bool Surface::clip(Common::Rect &srcBounds, Common::Rect &destBounds) {
if (destBounds.left >= _surface.w || destBounds.top >= _surface.h ||
destBounds.right <= 0 || destBounds.bottom <= 0)
@@ -185,17 +254,28 @@ void Surface::free() {
}
}
-void Surface::setPixels(byte *pixels, int width, int height) {
- _surface.format = Graphics::PixelFormat::createFormatCLUT8();
- _surface.w = _surface.pitch = width;
+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);
}
-void Surface::maskArea(const ImageFrame &src, const Common::Point &pt, int scrollX) {
- // TODO
- error("TODO: maskArea");
+void Surface::writeString(const Common::String &str, const Common::Point &pt, byte overrideColor) {
+ Fonts::writeString(this, str, pt, overrideColor);
}
+void Surface::writeFancyString(const Common::String &str, const Common::Point &pt, byte overrideColor1, byte 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);
+ writeString(str, Common::Point(pt.x, pt.y + 1), overrideColor1);
+ writeString(str, Common::Point(pt.x + 2, pt.y + 1), overrideColor1);
+ writeString(str, Common::Point(pt.x, pt.y + 2), overrideColor1);
+ writeString(str, Common::Point(pt.x + 1, pt.y + 2), overrideColor1);
+ writeString(str, Common::Point(pt.x + 2, pt.y + 2), overrideColor1);
+ writeString(str, Common::Point(pt.x + 1, pt.y + 1), overrideColor2);
+}
} // End of namespace Sherlock
diff --git a/engines/sherlock/surface.h b/engines/sherlock/surface.h
index 663f87f37f..385fb1793e 100644
--- a/engines/sherlock/surface.h
+++ b/engines/sherlock/surface.h
@@ -24,13 +24,18 @@
#define SHERLOCK_GRAPHICS_H
#include "common/rect.h"
+#include "common/platform.h"
#include "graphics/surface.h"
+#include "sherlock/fonts.h"
namespace Sherlock {
+#define SCALE_THRESHOLD 0x100
+#define TRANSPARENCY 255
+
struct ImageFrame;
-class Surface {
+class Surface: public Fonts {
private:
bool _freePixels;
@@ -45,14 +50,16 @@ private:
void blitFrom(const Graphics::Surface &src);
/**
- * Draws a surface at a given position within this surface
+ * Draws a sub-section of a surface at a given position within this surface
*/
- void blitFrom(const Graphics::Surface &src, const Common::Point &pt);
+ void blitFrom(const Graphics::Surface &src, const Common::Point &pt, const Common::Rect &srcBounds);
/**
- * Draws a sub-section of a surface at a given position within this surface
+ * Draws a surface at a given position within this surface with transparency
*/
- void blitFrom(const Graphics::Surface &src, const Common::Point &pt, const Common::Rect &srcBounds);
+ void transBlitFromUnscaled(const Graphics::Surface &src, const Common::Point &pt, bool flipped,
+ int overrideColor);
+
protected:
Graphics::Surface _surface;
@@ -68,6 +75,8 @@ public:
*/
void create(uint16 width, uint16 height);
+ Graphics::PixelFormat getPixelFormat();
+
/**
* Copy a surface into this one
*/
@@ -99,22 +108,27 @@ public:
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);
+
+ /**
* 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);
+ 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);
+ bool flipped = false, int overrideColor = 0, int scaleVal = 256);
/**
* Draws a surface 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);
+ bool flipped = false, int overrideColor = 0, int scaleVal = 256);
/**
* Fill a given area of the surface with a given color
@@ -126,10 +140,10 @@ public:
*/
void fillRect(const Common::Rect &r, byte color);
- void maskArea(const ImageFrame &src, const Common::Point &pt, int scrollX);
+ void fill(uint16 color);
/**
- * Clear the screen
+ * Clear the surface
*/
void clear();
@@ -139,9 +153,20 @@ public:
void free();
/**
+ * Returns true if the surface is empty
+ */
+ bool empty() const { return _surface.getPixels() == nullptr; }
+
+ /**
* Set the pixels for the surface to an existing data block
*/
- void setPixels(byte *pixels, int width, int height);
+ void setPixels(byte *pixels, int width, int height, Graphics::PixelFormat format);
+
+ /**
+ * Draws the given string into the back buffer using the images stored in _font
+ */
+ virtual void writeString(const Common::String &str, const Common::Point &pt, byte overrideColor);
+ void writeFancyString(const Common::String &str, const Common::Point &pt, byte overrideColor1, byte overrideColor2);
inline uint16 w() const { return _surface.w; }
inline uint16 h() const { return _surface.h; }
@@ -149,6 +174,7 @@ public:
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, uint32 color) { _surface.hLine(x, y, x2, color); }
inline void vLine(int x, int y, int y2, uint32 color) { _surface.vLine(x, y, y2, color); }
};
diff --git a/engines/sherlock/talk.cpp b/engines/sherlock/talk.cpp
index 59897e2c2a..fa00b9d715 100644
--- a/engines/sherlock/talk.cpp
+++ b/engines/sherlock/talk.cpp
@@ -23,162 +23,29 @@
#include "sherlock/talk.h"
#include "sherlock/sherlock.h"
#include "sherlock/screen.h"
+#include "sherlock/scalpel/scalpel.h"
+#include "sherlock/scalpel/scalpel_people.h"
+#include "sherlock/scalpel/scalpel_talk.h"
#include "sherlock/scalpel/scalpel_user_interface.h"
+#include "sherlock/tattoo/tattoo.h"
+#include "sherlock/tattoo/tattoo_people.h"
+#include "sherlock/tattoo/tattoo_scene.h"
+#include "sherlock/tattoo/tattoo_talk.h"
namespace Sherlock {
-#define SPEAKER_REMOVE 0x80
-
-const byte SCALPEL_OPCODES[] = {
- 128, // OP_SWITCH_SPEAKER
- 129, // OP_RUN_CANIMATION
- 130, // OP_ASSIGN_PORTRAIT_LOCATION
- 131, // OP_PAUSE
- 132, // OP_REMOVE_PORTRAIT
- 133, // OP_CLEAR_WINDOW
- 134, // OP_ADJUST_OBJ_SEQUENCE
- 135, // OP_WALK_TO_COORDS
- 136, // OP_PAUSE_WITHOUT_CONTROL
- 137, // OP_BANISH_WINDOW
- 138, // OP_SUMMON_WINDOW
- 139, // OP_SET_FLAG
- 140, // OP_SFX_COMMAND
- 141, // OP_TOGGLE_OBJECT
- 142, // OP_STEALTH_MODE_ACTIVE
- 143, // OP_IF_STATEMENT
- 144, // OP_ELSE_STATEMENT
- 145, // OP_END_IF_STATEMENT
- 146, // OP_STEALTH_MODE_DEACTIVATE
- 147, // OP_TURN_HOLMES_OFF
- 148, // OP_TURN_HOLMES_ON
- 149, // OP_GOTO_SCENE
- 150, // OP_PLAY_PROLOGUE
- 151, // OP_ADD_ITEM_TO_INVENTORY
- 152, // OP_SET_OBJECT
- 153, // OP_CALL_TALK_FILE
- 143, // OP_MOVE_MOUSE
- 155, // OP_DISPLAY_INFO_LINE
- 156, // OP_CLEAR_INFO_LINE
- 157, // OP_WALK_TO_CANIMATION
- 158, // OP_REMOVE_ITEM_FROM_INVENTORY
- 159, // OP_ENABLE_END_KEY
- 160, // OP_DISABLE_END_KEY
- 161, // OP_CARRIAGE_RETURN
- 0, // OP_MOUSE_ON_OFF
- 0, // OP_SET_WALK_CONTROL
- 0, // OP_SET_TALK_SEQUENCE
- 0, // OP_PLAY_SONG
- 0, // OP_WALK_HOLMES_AND_NPC_TO_CANIM
- 0, // OP_SET_NPC_PATH_DEST
- 0, // OP_NEXT_SONG
- 0, // OP_SET_NPC_PATH_PAUSE
- 0, // OP_PASSWORD
- 0, // OP_SET_SCENE_ENTRY_FLAG
- 0, // OP_WALK_NPC_TO_CANIM
- 0, // OP_WALK_HOLMES_AND_NPC_TO_COORDS
- 0, // OP_WALK_HOLMES_AND_NPC_TO_COORDS
- 0, // OP_SET_NPC_TALK_FILE
- 0, // OP_TURN_NPC_OFF
- 0, // OP_TURN_NPC_ON
- 0, // OP_NPC_DESC_ON_OFF
- 0, // OP_NPC_PATH_PAUSE_TAKING_NOTES
- 0, // OP_NPC_PATH_PAUSE_LOOKING_HOLMES
- 0, // OP_ENABLE_TALK_INTERRUPTS
- 0, // OP_DISABLE_TALK_INTERRUPTS
- 0, // OP_SET_NPC_INFO_LINE
- 0, // OP_SET_NPC_POSITION
- 0, // OP_NPC_PATH_LABEL
- 0, // OP_PATH_GOTO_LABEL
- 0, // OP_PATH_IF_FLAG_GOTO_LABEL
- 0, // OP_NPC_WALK_GRAPHICS
- 0, // OP_NPC_VERB
- 0, // OP_NPC_VERB_CANIM
- 0, // OP_NPC_VERB_SCRIPT
- 0, // OP_RESTORE_PEOPLE_SEQUENCE
- 0, // OP_NPC_VERB_TARGET
- 0 // OP_TURN_SOUNDS_OFF
-};
-
-const byte TATTOO_OPCODES[] = {
- 170, // OP_SWITCH_SPEAKER
- 171, // OP_RUN_CANIMATION
- 0, // OP_ASSIGN_PORTRAIT_LOCATION
- 173, // OP_PAUSE
- 0, // OP_REMOVE_PORTRAIT
- 0, // OP_CLEAR_WINDOW
- 176, // OP_ADJUST_OBJ_SEQUENCE
- 177, // OP_WALK_TO_COORDS
- 178, // OP_PAUSE_WITHOUT_CONTROL
- 179, // OP_BANISH_WINDOW
- 0, // OP_SUMMON_WINDOW
- 181, // OP_SET_FLAG
- 0, // OP_SFX_COMMAND
- 183, // OP_TOGGLE_OBJECT
- 184, // OP_STEALTH_MODE_ACTIVE
- 0, // OP_IF_STATEMENT
- 0, // OP_ELSE_STATEMENT
- 0, // OP_END_IF_STATEMENT
- 188, // OP_STEALTH_MODE_DEACTIVATE
- 189, // OP_TURN_HOLMES_OFF
- 190, // OP_TURN_HOLMES_ON
- 191, // OP_GOTO_SCENE
- 0, // OP_PLAY_PROLOGUE
- 193, // OP_ADD_ITEM_TO_INVENTORY
- 194, // OP_SET_OBJECT
- 172, // OP_CALL_TALK_FILE
- 0, // OP_MOVE_MOUSE
- 0, // OP_DISPLAY_INFO_LINE
- 0, // OP_CLEAR_INFO_LINE
- 199, // OP_WALK_TO_CANIMATION
- 200, // OP_REMOVE_ITEM_FROM_INVENTORY
- 201, // OP_ENABLE_END_KEY
- 202, // OP_DISABLE_END_KEY
- 0, // OP_CARRIAGE_RETURN
- 174, // OP_MOUSE_ON_OFF
- 175, // OP_SET_WALK_CONTROL
- 180, // OP_SET_TALK_SEQUENCE
- 182, // OP_PLAY_SONG
- 187, // OP_WALK_HOLMES_AND_NPC_TO_CANIM
- 192, // OP_SET_NPC_PATH_DEST
- 195, // OP_NEXT_SONG
- 196, // OP_SET_NPC_PATH_PAUSE
- 197, // OP_PASSWORD
- 198, // OP_SET_SCENE_ENTRY_FLAG
- 185, // OP_WALK_NPC_TO_CANIM
- 204, // OP_WALK_HOLMES_AND_NPC_TO_COORDS
- 205, // OP_SET_NPC_TALK_FILE
- 206, // OP_TURN_NPC_OFF
- 207, // OP_TURN_NPC_ON
- 208, // OP_NPC_DESC_ON_OFF
- 209, // OP_NPC_PATH_PAUSE_TAKING_NOTES
- 210, // OP_NPC_PATH_PAUSE_LOOKING_HOLMES
- 211, // OP_ENABLE_TALK_INTERRUPTS
- 212, // OP_DISABLE_TALK_INTERRUPTS
- 213, // OP_SET_NPC_INFO_LINE
- 214, // OP_SET_NPC_POSITION
- 215, // OP_NPC_PATH_LABEL
- 216, // OP_PATH_GOTO_LABEL
- 217, // OP_PATH_IF_FLAG_GOTO_LABEL
- 218, // OP_NPC_WALK_GRAPHICS
- 220, // OP_NPC_VERB
- 221, // OP_NPC_VERB_CANIM
- 222, // OP_NPC_VERB_SCRIPT
- 224, // OP_RESTORE_PEOPLE_SEQUENCE
- 226, // OP_NPC_VERB_TARGET
- 227 // OP_TURN_SOUNDS_OFF
-};
-
-/*----------------------------------------------------------------*/
-
SequenceEntry::SequenceEntry() {
_objNum = 0;
- _frameNumber = 0;
+ _obj = nullptr;
+ _seqStack = 0;
_seqTo = 0;
+ _sequenceNumber = _frameNumber = 0;
+ _seqCounter = _seqCounter2 = 0;
}
/*----------------------------------------------------------------*/
-void Statement::synchronize(Common::SeekableReadStream &s) {
+void Statement::load(Common::SeekableReadStream &s, bool isRoseTattoo) {
int length;
length = s.readUint16LE();
@@ -212,6 +79,7 @@ void Statement::synchronize(Common::SeekableReadStream &s) {
_portraitSide = s.readByte();
_quotient = s.readUint16LE();
+ _journal = isRoseTattoo ? s.readByte() : 0;
}
/*----------------------------------------------------------------*/
@@ -222,26 +90,17 @@ TalkHistoryEntry::TalkHistoryEntry() {
/*----------------------------------------------------------------*/
-TalkSequences::TalkSequences(const byte *data) {
- Common::copy(data, data + MAX_TALK_SEQUENCES, _data);
-}
-
-void TalkSequences::clear() {
- Common::fill(&_data[0], &_data[MAX_TALK_SEQUENCES], 0);
-}
-
-/*----------------------------------------------------------------*/
-
Talk *Talk::init(SherlockEngine *vm) {
if (vm->getGameID() == GType_SerratedScalpel)
- return new ScalpelTalk(vm);
+ return new Scalpel::ScalpelTalk(vm);
else
- return new TattooTalk(vm);
+ return new Tattoo::TattooTalk(vm);
}
Talk::Talk(SherlockEngine *vm) : _vm(vm) {
_talkCounter = 0;
_talkToAbort = false;
+ _openTalkWindow = false;
_speaker = 0;
_talkIndex = 0;
_talkTo = 0;
@@ -252,7 +111,9 @@ Talk::Talk(SherlockEngine *vm) : _vm(vm) {
_moreTalkDown = _moreTalkUp = false;
_scriptMoreFlag = 0;
_scriptSaveIndex = -1;
- _opcodes = IS_SERRATED_SCALPEL ? SCALPEL_OPCODES : TATTOO_OPCODES;
+ _opcodes = nullptr;
+ _opcodeTable = nullptr;
+ _3doSpeechIndex = -1;
_charCount = 0;
_line = 0;
@@ -261,15 +122,19 @@ Talk::Talk(SherlockEngine *vm) : _vm(vm) {
_pauseFlag = false;
_seqCount = 0;
_scriptStart = _scriptEnd = nullptr;
+ _endStr = _noTextYet = false;
+
+ _talkHistory.resize(IS_ROSE_TATTOO ? 1500 : 500);
}
-void Talk::talkTo(const Common::String &filename) {
+void Talk::talkTo(const Common::String filename) {
Events &events = *_vm->_events;
Inventory &inv = *_vm->_inventory;
Journal &journal = *_vm->_journal;
People &people = *_vm->_people;
Scene &scene = *_vm->_scene;
Screen &screen = *_vm->_screen;
+ Sound &sound = *_vm->_sound;
UserInterface &ui = *_vm->_ui;
Common::Rect savedBounds = screen.getDisplayBounds();
bool abortFlag = false;
@@ -280,7 +145,11 @@ void Talk::talkTo(const Common::String &filename) {
// If there any canimations currently running, or a portrait is being cleared,
// save the filename for later executing when the canimation is done
- if (scene._canimShapes.size() > 0 || people._clearingThePortrait) {
+ bool ongoingAnim = scene._canimShapes.size() > 0;
+ if (IS_ROSE_TATTOO) {
+ ongoingAnim = static_cast<Tattoo::TattooScene *>(_vm->_scene)->_activeCAnim.active();
+ }
+ if (ongoingAnim || people._clearingThePortrait) {
// Make sure we're not in the middle of a script
if (!_scriptMoreFlag) {
_scriptName = filename;
@@ -301,13 +170,13 @@ void Talk::talkTo(const Common::String &filename) {
// Turn on the Exit option
ui._endKeyActive = true;
- if (people[AL]._walkCount || people._walkTo.size() > 0) {
- // Only interrupt if an action if trying to do an action, and not just
- // if the player is walking around the scene
+ if (people[HOLMES]._walkCount || (!people[HOLMES]._walkTo.empty() &&
+ (IS_SERRATED_SCALPEL || people._allowWalkAbort))) {
+ // Only interrupt if trying to do an action, and not just if player is walking around the scene
if (people._allowWalkAbort)
abortFlag = true;
- people.gotoStand(people._player);
+ people[HOLMES].gotoStand();
}
if (_talkToAbort)
@@ -327,13 +196,19 @@ void Talk::talkTo(const Common::String &filename) {
}
}
- while (!_sequenceStack.empty())
+ if (IS_ROSE_TATTOO) {
pullSequence();
+ } else {
+ while (!isSequencesEmpty())
+ pullSequence();
+ }
if (IS_SERRATED_SCALPEL) {
// Restore any pressed button
if (!ui._windowOpen && savedMode != STD_MODE)
- ((Scalpel::ScalpelUserInterface *)_vm->_ui)->restoreButton((int)(savedMode - 1));
+ static_cast<Scalpel::ScalpelUserInterface *>(_vm->_ui)->restoreButton((int)(savedMode - 1));
+ } else {
+ static_cast<Tattoo::TattooPeople *>(_vm->_people)->pullNPCPaths();
}
// Clear the ui counter so that anything displayed on the info line
@@ -462,9 +337,19 @@ void Talk::talkTo(const Common::String &filename) {
_scriptSelect = select;
_speaker = _talkTo;
- Statement &statement = _statements[select];
+ // Set up the talk file extension
+ if (IS_ROSE_TATTOO && sound._speechOn && _scriptMoreFlag != 1)
+ sound._talkSoundFile += Common::String::format("%02dB", select + 1);
+
+ // Make a copy of the statement (in case the script frees the statement list), and then execute it
+ Statement statement = _statements[select];
doScript(_statements[select]._reply);
+ if (IS_ROSE_TATTOO) {
+ for (int idx = 0; idx < MAX_CHARACTERS; ++idx)
+ people[idx]._misc = 0;
+ }
+
if (_talkToAbort)
return;
@@ -502,40 +387,9 @@ void Talk::talkTo(const Common::String &filename) {
// If the new conversion is a reply first, then we don't need
// to display any choices, since the reply needs to be shown
- if (!newStatement._statement.hasPrefix("*") &&
- !newStatement._statement.hasPrefix("^")) {
- clearSequences();
- pushSequence(_talkTo);
- setStillSeq(_talkTo);
+ if (!newStatement._statement.hasPrefix("*") && !newStatement._statement.hasPrefix("^")) {
_talkIndex = select;
- ui._selector = ui._oldSelector = -1;
-
- if (!ui._windowOpen) {
- // Draw the talk interface on the back buffer
- drawInterface();
- displayTalk(false);
- } else {
- displayTalk(true);
- }
-
- byte color = ui._endKeyActive ? COMMAND_FOREGROUND : COMMAND_NULL;
-
- // 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, "Exit");
- } else {
- screen.buttonPrint(Common::Point(119, CONTROLS_Y), color, false, "Exit");
-
- if (!ui._slideWindows) {
- screen.slamRect(Common::Rect(0, CONTROLS_Y,
- SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT));
- } else {
- ui.summonWindow();
- }
-
- ui._windowOpen = true;
- }
+ showTalk();
// Break out of loop now that we're waiting for player input
events.setCursor(ARROW);
@@ -545,7 +399,6 @@ void Talk::talkTo(const Common::String &filename) {
if (_talkTo != -1 && !_talkHistory[_converseNum][select])
journal.record(_converseNum, select, true);
_talkHistory[_converseNum][select] = true;
-
}
ui._key = ui._oldKey = Scalpel::COMMANDS[TALK_MODE - 1];
@@ -555,13 +408,17 @@ void Talk::talkTo(const Common::String &filename) {
} else {
freeTalkVars();
- if (!ui._lookScriptFlag) {
- ui.drawInterface(2);
- ui.banishWindow();
- ui._windowBounds.top = CONTROLS_Y1;
- ui._menuMode = STD_MODE;
+ if (IS_SERRATED_SCALPEL) {
+ if (!ui._lookScriptFlag) {
+ ui.drawInterface(2);
+ ui._menuMode = STD_MODE;
+ ui._windowBounds.top = CONTROLS_Y1;
+ }
+ } else {
+ ui._menuMode = static_cast<Tattoo::TattooScene *>(_vm->_scene)->_labTableScene ? LAB_MODE : STD_MODE;
}
+ ui.banishWindow();
break;
}
}
@@ -582,27 +439,21 @@ void Talk::talkTo(const Common::String &filename) {
// previous script can continue
popStack();
- if (_vm->getGameID() == GType_SerratedScalpel && filename == "Tube59c") {
- // WORKAROUND: Original game bug causes the results of testing the powdery substance
- // to disappear too quickly. Introduce a delay to allow it to be properly displayed
- ui._menuCounter = 30;
- }
-
events.setCursor(ARROW);
}
-void Talk::talk(int objNum) {
+void Talk::initTalk(int objNum) {
Events &events = *_vm->_events;
People &people = *_vm->_people;
Scene &scene = *_vm->_scene;
- Screen &screen = *_vm->_screen;
UserInterface &ui = *_vm->_ui;
- Object &obj = scene._bgShapes[objNum];
ui._windowBounds.top = CONTROLS_Y;
ui._infoFlag = true;
_speaker = SPEAKER_REMOVE;
- loadTalkFile(scene._bgShapes[objNum]._name);
+
+ Common::String talkFilename = (objNum >= 1000) ? people[objNum - 1000]._npcName : scene._bgShapes[objNum]._name;
+ loadTalkFile(talkFilename);
// Find the first statement with the correct flags
int select = -1;
@@ -612,8 +463,15 @@ void Talk::talk(int objNum) {
break;
}
}
- if (select == -1)
- error("No entry matched all required flags");
+
+ if (select == -1) {
+ freeTalkVars();
+ if (!scumm_strnicmp(talkFilename.c_str(), "PATH", 4))
+ error("No entries found to execute in path file");
+
+ nothingToSay();
+ return;
+ }
// See if the statement is a stealth mode reply
Statement &statement = _statements[select];
@@ -623,35 +481,44 @@ void Talk::talk(int objNum) {
// Start talk in stealth mode
_talkStealth = 2;
- talkTo(obj._name);
+ talkTo(talkFilename);
} else if (statement._statement.hasPrefix("*")) {
// Character being spoken to will speak first
- clearSequences();
- pushSequence(_talkTo);
- setStillSeq(_talkTo);
+ if (objNum > 1000) {
+ (*static_cast<Tattoo::TattooPeople *>(_vm->_people))[objNum - 1000].walkHolmesToNPC();
+ } else {
+ Object &obj = scene._bgShapes[objNum];
+ clearSequences();
+ pushSequence(_talkTo);
+ people.setListenSequence(_talkTo, 129);
- events.setCursor(WAIT);
- if (obj._lookPosition.y != 0)
- // Need to walk to character first
- people.walkToCoords(Common::Point(obj._lookPosition.x, obj._lookPosition.y * 100),
- obj._lookFacing);
- events.setCursor(ARROW);
+ events.setCursor(WAIT);
+ if (obj._lookPosition.y != 0)
+ // Need to walk to character first
+ people[HOLMES].walkToCoords(obj._lookPosition, obj._lookPosition._facing);
+ events.setCursor(ARROW);
+ }
if (!_talkToAbort)
- talkTo(obj._name);
+ talkTo(talkFilename);
} else {
// Holmes will be speaking first
- clearSequences();
- pushSequence(_talkTo);
- setStillSeq(_talkTo);
-
_talkToFlag = false;
- events.setCursor(WAIT);
- if (obj._lookPosition.y != 0)
- // Walk over to person to talk to
- people.walkToCoords(Common::Point(obj._lookPosition.x, obj._lookPosition.y * 100),
- obj._lookFacing);
- events.setCursor(ARROW);
+
+ if (objNum > 1000) {
+ (*static_cast<Tattoo::TattooPeople *>(_vm->_people))[objNum - 1000].walkHolmesToNPC();
+ } else {
+ Object &obj = scene._bgShapes[objNum];
+ clearSequences();
+ pushSequence(_talkTo);
+ people.setListenSequence(_talkTo, 129);
+
+ events.setCursor(WAIT);
+ if (obj._lookPosition.y != 0)
+ // Walk over to person to talk to
+ people[HOLMES].walkToCoords(obj._lookPosition, obj._lookPosition._facing);
+ events.setCursor(ARROW);
+ }
if (!_talkToAbort) {
// See if walking over triggered a conversation
@@ -662,21 +529,11 @@ void Talk::talk(int objNum) {
pullSequence();
}
} else {
- drawInterface();
-
- events._pressed = events._released = false;
_talkIndex = select;
- displayTalk(false);
- ui._selector = ui._oldSelector = -1;
+ showTalk();
- if (!ui._slideWindows) {
- screen.slamRect(Common::Rect(0, CONTROLS_Y, SHERLOCK_SCREEN_WIDTH,
- SHERLOCK_SCREEN_HEIGHT));
- } else {
- ui.summonWindow();
- }
-
- ui._windowOpen = true;
+ // Break out of loop now that we're waiting for player input
+ events.setCursor(ARROW);
}
_talkToFlag = -1;
@@ -709,6 +566,12 @@ void Talk::loadTalkFile(const Common::String &filename) {
Common::String talkFile = chP ? Common::String(filename.c_str(), chP) + ".tlk" :
Common::String(filename.c_str(), filename.c_str() + 7) + ".tlk";
+ // Create the base of the sound filename used for talking in Rose Tattoo
+ if (IS_ROSE_TATTOO && _scriptMoreFlag != 1)
+ sound._talkSoundFile = Common::String(filename.c_str(), filename.c_str() + 7) + ".";
+ else if (IS_3DO)
+ _3doSpeechIndex = 1;
+
// Open the talk file for reading
Common::SeekableReadStream *talkStream = res.load(talkFile);
_converseNum = res.resourceIndex();
@@ -716,7 +579,7 @@ void Talk::loadTalkFile(const Common::String &filename) {
_statements.resize(talkStream->readByte());
for (uint idx = 0; idx < _statements.size(); ++idx)
- _statements[idx].synchronize(*talkStream);
+ _statements[idx].load(*talkStream, IS_ROSE_TATTOO);
delete talkStream;
@@ -765,317 +628,15 @@ void Talk::setTalkMap() {
}
}
-void Talk::drawInterface() {
- Screen &screen = *_vm->_screen;
- Surface &bb = *screen._backBuffer;
-
- 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);
- bb.fillRect(Common::Rect(SHERLOCK_SCREEN_WIDTH - 2, CONTROLS_Y + 10,
- SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT), BORDER_COLOR);
- bb.fillRect(Common::Rect(0, SHERLOCK_SCREEN_HEIGHT - 1, SHERLOCK_SCREEN_WIDTH - 2,
- SHERLOCK_SCREEN_HEIGHT), BORDER_COLOR);
- bb.fillRect(Common::Rect(2, CONTROLS_Y + 10, SHERLOCK_SCREEN_WIDTH - 2,
- SHERLOCK_SCREEN_HEIGHT - 2), INV_BACKGROUND);
-
- if (_talkTo != -1) {
- screen.makeButton(Common::Rect(99, CONTROLS_Y, 139, CONTROLS_Y + 10),
- 119 - screen.stringWidth("Exit") / 2, "Exit");
- screen.makeButton(Common::Rect(140, CONTROLS_Y, 180, CONTROLS_Y + 10),
- 159 - screen.stringWidth("Up") / 2, "Up");
- screen.makeButton(Common::Rect(181, CONTROLS_Y, 221, CONTROLS_Y + 10),
- 200 - screen.stringWidth("Down") / 2, "Down");
- } else {
- int strWidth = screen.stringWidth(Scalpel::PRESS_KEY_TO_CONTINUE);
- 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");
- }
-}
-
-bool Talk::displayTalk(bool slamIt) {
- Screen &screen = *_vm->_screen;
- int yp = CONTROLS_Y + 14;
- int lineY = -1;
- _moreTalkDown = _moreTalkUp = false;
-
- for (uint idx = 0; idx < _statements.size(); ++idx) {
- _statements[idx]._talkPos.top = _statements[idx]._talkPos.bottom = -1;
- }
-
- if (_talkIndex) {
- for (int idx = 0; idx < _talkIndex && !_moreTalkUp; ++idx) {
- if (_statements[idx]._talkMap != -1)
- _moreTalkUp = true;
- }
- }
-
- // Display the up arrow and enable Up button if the first option is scrolled off-screen
- if (_moreTalkUp) {
- if (slamIt) {
- screen.print(Common::Point(5, CONTROLS_Y + 13), INV_FOREGROUND, "~");
- screen.buttonPrint(Common::Point(159, CONTROLS_Y), COMMAND_FOREGROUND, true, "Up");
- } else {
- screen.gPrint(Common::Point(5, CONTROLS_Y + 12), INV_FOREGROUND, "~");
- screen.buttonPrint(Common::Point(159, CONTROLS_Y), COMMAND_FOREGROUND, false, "Up");
- }
- } else {
- if (slamIt) {
- screen.buttonPrint(Common::Point(159, CONTROLS_Y), COMMAND_NULL, true, "Up");
- 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, "Up");
- screen._backBuffer1.fillRect(Common::Rect(5, CONTROLS_Y + 11,
- 15, CONTROLS_Y + 22), INV_BACKGROUND);
- }
- }
-
- // Loop through the statements
- bool done = false;
- for (uint idx = _talkIndex; idx < _statements.size() && !done; ++idx) {
- Statement &statement = _statements[idx];
-
- if (statement._talkMap != -1) {
- bool flag = _talkHistory[_converseNum][idx];
- lineY = talkLine(idx, statement._talkMap, flag ? TALK_NULL : INV_FOREGROUND,
- yp, slamIt);
-
- if (lineY != -1) {
- statement._talkPos.top = yp;
- yp = lineY;
- statement._talkPos.bottom = yp;
-
- if (yp == SHERLOCK_SCREEN_HEIGHT)
- done = true;
- } else {
- done = true;
- }
- }
- }
-
- // Display the down arrow and enable down button if there are more statements available down off-screen
- if (lineY == -1 || lineY == SHERLOCK_SCREEN_HEIGHT) {
- _moreTalkDown = true;
-
- if (slamIt) {
- screen.print(Common::Point(5, 190), INV_FOREGROUND, "|");
- screen.buttonPrint(Common::Point(200, CONTROLS_Y), COMMAND_FOREGROUND, true, "Down");
- } else {
- screen.gPrint(Common::Point(5, 189), INV_FOREGROUND, "|");
- screen.buttonPrint(Common::Point(200, CONTROLS_Y), COMMAND_FOREGROUND, false, "Down");
- }
- } else {
- if (slamIt) {
- screen.buttonPrint(Common::Point(200, CONTROLS_Y), COMMAND_NULL, true, "Down");
- screen.vgaBar(Common::Rect(5, 189, 16, 199), INV_BACKGROUND);
- } else {
- screen.buttonPrint(Common::Point(200, CONTROLS_Y), COMMAND_NULL, false, "Down");
- screen._backBuffer1.fillRect(Common::Rect(5, 189, 16, 199), INV_BACKGROUND);
- }
- }
-
- return done;
-}
-
-int Talk::talkLine(int lineNum, int stateNum, byte color, int lineY, bool slamIt) {
- Screen &screen = *_vm->_screen;
- int idx = lineNum;
- Common::String msg, number;
- bool numberFlag = false;
-
- // Get the statement to display as well as optional number prefix
- if (idx < SPEAKER_REMOVE) {
- number = Common::String::format("%d.", stateNum + 1);
- numberFlag = true;
- } else {
- idx -= SPEAKER_REMOVE;
- }
- msg = _statements[idx]._statement;
-
- // Handle potentially multiple lines needed to display entire statement
- const char *lineStartP = msg.c_str();
- int maxWidth = 298 - (numberFlag ? 18 : 0);
- for (;;) {
- // Get as much of the statement as possible will fit on the
- Common::String sLine;
- const char *lineEndP = lineStartP;
- int width = 0;
- do {
- width += screen.charWidth(*lineEndP);
- } while (*++lineEndP && width < maxWidth);
-
- // Check if we need to wrap the line
- if (width >= maxWidth) {
- // Work backwards to the prior word's end
- while (*--lineEndP != ' ')
- ;
-
- sLine = Common::String(lineStartP, lineEndP++);
- } else {
- // Can display remainder of the statement on the current line
- sLine = Common::String(lineStartP);
- }
-
-
- if (lineY <= (SHERLOCK_SCREEN_HEIGHT - 10)) {
- // Need to directly display on-screen?
- if (slamIt) {
- // See if a numer prefix is needed or not
- if (numberFlag) {
- // Are we drawing the first line?
- if (lineStartP == msg.c_str()) {
- // We are, so print the number and then the text
- screen.print(Common::Point(16, lineY), color, "%s", number.c_str());
- }
-
- // Draw the line with an indent
- screen.print(Common::Point(30, lineY), color, "%s", sLine.c_str());
- } else {
- screen.print(Common::Point(16, lineY), color, "%s", sLine.c_str());
- }
- } else {
- if (numberFlag) {
- if (lineStartP == msg.c_str()) {
- screen.gPrint(Common::Point(16, lineY - 1), color, "%s", number.c_str());
- }
-
- screen.gPrint(Common::Point(30, lineY - 1), color, "%s", sLine.c_str());
- } else {
- screen.gPrint(Common::Point(16, lineY - 1), color, "%s", sLine.c_str());
- }
- }
-
- // Move to next line, if any
- lineY += 9;
- lineStartP = lineEndP;
-
- if (!*lineEndP)
- break;
- } else {
- // We're close to the bottom of the screen, so stop display
- lineY = -1;
- break;
- }
- }
-
- if (lineY == -1 && lineStartP != msg.c_str())
- lineY = SHERLOCK_SCREEN_HEIGHT;
-
- // Return the Y position of the next line to follow this one
- return lineY;
-}
-
-void Talk::clearSequences() {
- _sequenceStack.clear();
-}
-
-void Talk::pullSequence() {
- Scene &scene = *_vm->_scene;
-
- if (_sequenceStack.empty())
- return;
-
- SequenceEntry seq = _sequenceStack.pop();
- if (seq._objNum != -1) {
- Object &obj = scene._bgShapes[seq._objNum];
-
- if (obj._seqSize < MAX_TALK_SEQUENCES) {
- warning("Tried to restore too few frames");
- } else {
- for (int idx = 0; idx < MAX_TALK_SEQUENCES; ++idx)
- obj._sequences[idx] = seq._sequences[idx];
-
- obj._frameNumber = seq._frameNumber;
- obj._seqTo = seq._seqTo;
- }
- }
-}
-
void Talk::pushSequence(int speaker) {
People &people = *_vm->_people;
Scene &scene = *_vm->_scene;
// Only proceed if a speaker is specified
- if (speaker == -1)
- return;
-
- SequenceEntry seqEntry;
- if (!speaker) {
- seqEntry._objNum = -1;
- } else {
- seqEntry._objNum = people.findSpeaker(speaker);
-
- if (seqEntry._objNum != -1) {
- Object &obj = scene._bgShapes[seqEntry._objNum];
- for (uint idx = 0; idx < MAX_TALK_SEQUENCES; ++idx)
- seqEntry._sequences.push_back(obj._sequences[idx]);
-
- seqEntry._frameNumber = obj._frameNumber;
- seqEntry._seqTo = obj._seqTo;
- }
- }
-
- _sequenceStack.push(seqEntry);
- if (_scriptStack.size() >= 5)
- error("script stack overflow");
-}
-
-void Talk::setSequence(int speaker) {
- People &people = *_vm->_people;
- Scene &scene = *_vm->_scene;
-
- // If no speaker is specified, then nothing needs to be done
- if (speaker == -1)
- return;
-
- if (speaker) {
+ if (speaker != -1) {
int objNum = people.findSpeaker(speaker);
- if (objNum != -1) {
- Object &obj = scene._bgShapes[objNum];
-
- if (obj._seqSize < MAX_TALK_SEQUENCES) {
- warning("Tried to copy too many talk frames");
- } else {
- for (int idx = 0; idx < MAX_TALK_SEQUENCES; ++idx) {
- obj._sequences[idx] = people._characters[speaker]._talkSequences[idx];
- if (idx > 0 && !obj._sequences[idx] && !obj._sequences[idx - 1])
- return;
-
- obj._frameNumber = 0;
- obj._sequenceNumber = 0;
- }
- }
- }
- }
-}
-
-void Talk::setStillSeq(int speaker) {
- People &people = *_vm->_people;
- Scene &scene = *_vm->_scene;
-
- // Don't bother doing anything if no specific speaker is specified
- if (speaker == -1)
- return;
-
- if (speaker) {
- int objNum = people.findSpeaker(speaker);
- if (objNum != -1) {
- Object &obj = scene._bgShapes[objNum];
-
- if (obj._seqSize < MAX_TALK_SEQUENCES) {
- warning("Tried to copy too few still frames");
- } else {
- for (uint idx = 0; idx < MAX_TALK_SEQUENCES; ++idx) {
- obj._sequences[idx] = people._characters[speaker]._stillSequences[idx];
- if (idx > 0 && !people._characters[speaker]._talkSequences[idx] &&
- !people._characters[speaker]._talkSequences[idx - 1])
- break;
- }
-
- obj._frameNumber = 0;
- obj._seqTo = 0;
- }
- }
+ if (objNum != -1)
+ pushSequenceEntry(&scene._bgShapes[objNum]);
}
}
@@ -1084,14 +645,12 @@ void Talk::doScript(const Common::String &script) {
Scene &scene = *_vm->_scene;
Screen &screen = *_vm->_screen;
UserInterface &ui = *_vm->_ui;
- bool openTalkWindow = false;
_savedSequences.clear();
_scriptStart = (const byte *)script.c_str();
_scriptEnd = _scriptStart + script.size();
const byte *str = _scriptStart;
- _yp = CONTROLS_Y + 12;
_charCount = 0;
_line = 0;
_wait = 0;
@@ -1099,6 +658,21 @@ void Talk::doScript(const Common::String &script) {
_seqCount = 0;
_noTextYet = true;
_endStr = false;
+ _openTalkWindow = false;
+
+ if (IS_SERRATED_SCALPEL)
+ _yp = CONTROLS_Y + 12;
+ else
+ _yp = (_talkTo == -1) ? 5 : screen.fontHeight() + 11;
+
+ if (IS_ROSE_TATTOO) {
+ for (int idx = 0; idx < MAX_CHARACTERS; ++idx) {
+ Tattoo::TattooPerson &p = (*(Tattoo::TattooPeople *)_vm->_people)[idx];
+ p._savedNpcSequence = p._sequenceNumber;
+ p._savedNpcFrame = p._frameNumber;
+ p._resetNPCPath = true;
+ }
+ }
if (_scriptMoreFlag) {
_scriptMoreFlag = 0;
@@ -1110,48 +684,60 @@ void Talk::doScript(const Common::String &script) {
_talkStealth = 2;
_speaker |= SPEAKER_REMOVE;
} else {
- pushSequence(_speaker);
- ui.clearWindow();
+ if (IS_SERRATED_SCALPEL)
+ pushSequence(_speaker);
+ if (IS_SERRATED_SCALPEL || ui._windowOpen)
+ ui.clearWindow();
// Need to switch speakers?
if (str[0] == _opcodes[OP_SWITCH_SPEAKER]) {
_speaker = str[1] - 1;
- str += 2;
- pullSequence();
- pushSequence(_speaker);
- setSequence(_speaker);
+
+ if (IS_SERRATED_SCALPEL) {
+ str += 2;
+ pullSequence();
+ pushSequence(_speaker);
+ } else {
+ str += 3;
+ }
+
+ people.setTalkSequence(_speaker);
} else {
- setSequence(_speaker);
+ people.setTalkSequence(_speaker);
}
- // Assign portrait location?
- if (str[0] == _opcodes[OP_ASSIGN_PORTRAIT_LOCATION]) {
- switch (str[1] & 15) {
- case 1:
- people._portraitSide = 20;
- break;
- case 2:
- people._portraitSide = 220;
- break;
- case 3:
- people._portraitSide = 120;
- break;
- default:
- break;
+ if (IS_SERRATED_SCALPEL) {
+ // Assign portrait location?
+ if (str[0] == _opcodes[OP_ASSIGN_PORTRAIT_LOCATION]) {
+ switch (str[1] & 15) {
+ case 1:
+ people._portraitSide = 20;
+ break;
+ case 2:
+ people._portraitSide = 220;
+ break;
+ case 3:
+ people._portraitSide = 120;
+ break;
+ default:
+ break;
- }
+ }
- if (str[1] > 15)
- people._speakerFlip = true;
- str += 2;
- }
+ if (str[1] > 15)
+ people._speakerFlip = true;
+ str += 2;
+ }
- // Remove portrait?
- if (str[0] == _opcodes[OP_REMOVE_PORTRAIT]) {
- _speaker = 255;
- } else {
- // Nope, so set the first speaker
- people.setTalking(_speaker);
+ if (IS_SERRATED_SCALPEL) {
+ // Remove portrait?
+ if ( str[0] == _opcodes[OP_REMOVE_PORTRAIT]) {
+ _speaker = -1;
+ } else {
+ // Nope, so set the first speaker
+ ((Scalpel::ScalpelPeople *)_vm->_people)->setTalking(_speaker);
+ }
+ }
}
}
@@ -1166,9 +752,9 @@ void Talk::doScript(const Common::String &script) {
// Start of comment, so skip over it
while (*str++ != '}')
;
- } else if (c >= 128 && c <= 227 && _opcodeTable[c - 128]) {
+ } else if (isOpcode(c)) {
// Handle control code
- switch ((this->*_opcodeTable[c - 128])(str)) {
+ switch ((this->*_opcodeTable[c - _opcodes[0]])(str)) {
case RET_EXIT:
return;
case RET_CONTINUE:
@@ -1179,107 +765,12 @@ void Talk::doScript(const Common::String &script) {
++str;
} else {
- // If the window isn't yet open, draw the window before printing starts
- if (!ui._windowOpen && _noTextYet) {
- _noTextYet = false;
- drawInterface();
-
- if (_talkTo != -1) {
- screen.buttonPrint(Common::Point(119, CONTROLS_Y), COMMAND_NULL, false, "Exit");
- screen.buttonPrint(Common::Point(159, CONTROLS_Y), COMMAND_NULL, false, "Up");
- screen.buttonPrint(Common::Point(200, CONTROLS_Y), COMMAND_NULL, false, "Down");
- }
- }
-
- // If it's the first line, display the speaker
- if (!_line && _speaker >= 0 && _speaker < (int)people._characters.size()) {
- // If the window is open, display the name directly on-screen.
- // Otherwise, simply draw it on the back buffer
- if (ui._windowOpen) {
- screen.print(Common::Point(16, _yp), TALK_FOREGROUND, "%s",
- people._characters[_speaker & 127]._name);
- } else {
- screen.gPrint(Common::Point(16, _yp - 1), TALK_FOREGROUND, "%s",
- people._characters[_speaker & 127]._name);
- openTalkWindow = true;
- }
-
- _yp += 9;
- }
-
- // Find amount of text that will fit on the line
- int width = 0, idx = 0;
- do {
- width += screen.charWidth(str[idx]);
- ++idx;
- ++_charCount;
- } while (width < 298 && str[idx] && str[idx] != '{' && str[idx] < _opcodes[0]);
-
- if (str[idx] || width >= 298) {
- if (str[idx] < _opcodes[0] && str[idx] != '{') {
- --idx;
- --_charCount;
- }
- } else {
- _endStr = true;
- }
-
- // If word wrap is needed, find the start of the current word
- if (width >= 298) {
- while (str[idx] != ' ') {
- --idx;
- --_charCount;
- }
- }
-
- // Print the line
- Common::String lineStr((const char *)str, (const char *)str + idx);
-
- // If the speaker indicates a description file, print it in yellow
- if (_speaker != -1) {
- if (ui._windowOpen) {
- screen.print(Common::Point(16, _yp), COMMAND_FOREGROUND, "%s", lineStr.c_str());
- } else {
- screen.gPrint(Common::Point(16, _yp - 1), COMMAND_FOREGROUND, "%s", lineStr.c_str());
- openTalkWindow = true;
- }
- } else {
- if (ui._windowOpen) {
- screen.print(Common::Point(16, _yp), COMMAND_FOREGROUND, "%s", lineStr.c_str());
- } else {
- screen.gPrint(Common::Point(16, _yp - 1), COMMAND_FOREGROUND, "%s", lineStr.c_str());
- openTalkWindow = true;
- }
- }
-
- // Move to end of displayed line
- str += idx;
-
- // If line wrap occurred, then move to after the separating space between the words
- if (str[0] < _opcodes[0] && str[0] != '{')
- ++str;
-
- _yp += 9;
- ++_line;
-
- // Certain different conditions require a wait
- if ((_line == 4 && str < _scriptEnd && str[0] != _opcodes[OP_SFX_COMMAND] && str[0] != _opcodes[OP_PAUSE] && _speaker != -1) ||
- (_line == 5 && str < _scriptEnd && str[0] != _opcodes[OP_PAUSE] && _speaker == -1) ||
- _endStr) {
- _wait = 1;
- }
-
- byte v = (str >= _scriptEnd ? 0 : str[0]);
- if (v == _opcodes[OP_SWITCH_SPEAKER] || v == _opcodes[OP_ASSIGN_PORTRAIT_LOCATION] ||
- v == _opcodes[OP_BANISH_WINDOW] || v == _opcodes[OP_IF_STATEMENT] ||
- v == _opcodes[OP_ELSE_STATEMENT] || v == _opcodes[OP_END_IF_STATEMENT] ||
- v == _opcodes[OP_GOTO_SCENE] || v == _opcodes[OP_CALL_TALK_FILE]) {
- _wait = 1;
- }
+ // Handle drawing the talk interface with the text
+ talkInterface(str);
}
// Open window if it wasn't already open, and text has already been printed
- if ((openTalkWindow && _wait) || (openTalkWindow && str[0] >= _opcodes[0] && str[0] != _opcodes[OP_CARRIAGE_RETURN])) {
+ if ((_openTalkWindow && _wait) || (_openTalkWindow && str[0] >= _opcodes[0] && str[0] != _opcodes[OP_END_TEXT_WINDOW])) {
if (!ui._slideWindows) {
screen.slamRect(Common::Rect(0, CONTROLS_Y, SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT));
} else {
@@ -1287,34 +778,12 @@ void Talk::doScript(const Common::String &script) {
}
ui._windowOpen = true;
- openTalkWindow = false;
+ _openTalkWindow = false;
}
- if (_wait) {
+ if (_wait)
// Handling pausing
- if (!_pauseFlag && _charCount < 160)
- _charCount = 160;
-
- _wait = waitForMore(_charCount);
- if (_wait == -1)
- _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 (str[0] == _opcodes[OP_SFX_COMMAND])
- str += 9;
- }
-
- // Clear the window unless the wait was due to a PAUSE command
- if (!_pauseFlag && _wait != -1 && str < _scriptEnd && str[0] != _opcodes[OP_SFX_COMMAND]) {
- if (!_talkStealth)
- ui.clearWindow();
- _yp = CONTROLS_Y + 12;
- _charCount = _line = 0;
- }
-
- _pauseFlag = false;
- }
+ talkWait(str);
} while (!_vm->shouldQuit() && !_endStr);
if (_wait != -1) {
@@ -1329,8 +798,13 @@ void Talk::doScript(const Common::String &script) {
}
pullSequence();
- if (_speaker >= 0 && _speaker < SPEAKER_REMOVE)
- people.clearTalking();
+
+ if (IS_SERRATED_SCALPEL) {
+ if (_speaker >= 0 && _speaker < SPEAKER_REMOVE)
+ people.clearTalking();
+ } else {
+ static_cast<Tattoo::TattooPeople *>(_vm->_people)->pullNPCPaths();
+ }
}
}
@@ -1342,14 +816,23 @@ int Talk::waitForMore(int delay) {
UserInterface &ui = *_vm->_ui;
CursorId oldCursor = events.getCursor();
int key2 = 254;
+ bool playingSpeech = false;
// Unless we're in stealth mode, show the appropriate cursor
if (!_talkStealth) {
events.setCursor(ui._lookScriptFlag ? MAGNIFY : ARROW);
}
+ // Handle playing any speech associated with the text being displayed
+ switchSpeaker();
+ if (sound._speechOn && IS_ROSE_TATTOO) {
+ sound.playSpeech(sound._talkSoundFile);
+ sound._talkSoundFile.setChar(sound._talkSoundFile.lastChar() + 1, sound._talkSoundFile.size() - 1);
+ }
+ playingSpeech = sound.isSpeechPlaying();
+
do {
- if (sound._speechOn && !*sound._soundIsOn)
+ if (IS_SERRATED_SCALPEL && sound._speechOn && !sound.isSpeechPlaying())
people._portrait._frameNumber = -1;
scene.doBgAnim();
@@ -1360,11 +843,21 @@ int Talk::waitForMore(int delay) {
events._released = true;
} else {
// See if there's been a button press
+ events.pollEventsAndWait();
events.setButtonState();
if (events.kbHit()) {
Common::KeyState keyState = events.getKey();
- if (Common::isPrint(keyState.ascii))
+ if (keyState.keycode == Common::KEYCODE_ESCAPE) {
+ if (IS_ROSE_TATTOO && static_cast<Tattoo::TattooEngine *>(_vm)->_runningProlog) {
+ // Skip out of the introduction
+ _vm->setFlags(-76);
+ _vm->setFlags(396);
+ scene._goToScene = 1;
+ }
+ break;
+
+ } else if (Common::isPrint(keyState.ascii))
key2 = keyState.keycode;
}
@@ -1378,18 +871,17 @@ int Talk::waitForMore(int delay) {
if ((delay > 0 && !ui._invLookFlag && !ui._lookScriptFlag) || _talkStealth)
--delay;
- // If there are voices playing, reset delay so that they keep playing
- if (sound._voices == 2 && *sound._soundIsOn)
+ if (playingSpeech && !sound.isSpeechPlaying())
delay = 0;
- } while (!_vm->shouldQuit() && key2 == 254 && (delay || (sound._voices == 2 && *sound._soundIsOn))
+ } 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 (sound._voices == 2)
sound._voices = 1;
- if (delay > 0 && sound._diskSoundPlaying)
- sound.stopSndFuncPtr(0, 0);
+ if (delay > 0 && sound.isSpeechPlaying())
+ sound.stopSpeech();
// Adjust _talkStealth mode:
// mode 1 - It was by a pause without stealth being on before the pause, so reset back to 0
@@ -1406,13 +898,22 @@ int Talk::waitForMore(int delay) {
break;
}
- sound._speechOn = false;
+
+ sound.stopSpeech();
events.setCursor(_talkToAbort ? ARROW : oldCursor);
events._pressed = events._released = false;
return key2;
}
+bool Talk::isOpcode(byte checkCharacter) {
+ if ((checkCharacter < _opcodes[0]) || (checkCharacter >= (_opcodes[0] + 99)))
+ return false; // outside of range
+ if (_opcodeTable[checkCharacter - _opcodes[0]])
+ return true;
+ return false;
+}
+
void Talk::popStack() {
if (!_scriptStack.empty()) {
ScriptStackEntry scriptEntry = _scriptStack.pop();
@@ -1423,8 +924,8 @@ void Talk::popStack() {
}
}
-void Talk::synchronize(Common::Serializer &s) {
- for (int idx = 0; idx < MAX_TALK_FILES; ++idx) {
+void Talk::synchronize(Serializer &s) {
+ for (uint idx = 0; idx < _talkHistory.size(); ++idx) {
TalkHistoryEntry &he = _talkHistory[idx];
for (int flag = 0; flag < 16; ++flag)
@@ -1507,42 +1008,6 @@ OpcodeReturn Talk::cmdBanishWindow(const byte *&str) {
return RET_SUCCESS;
}
-OpcodeReturn Talk::cmdCallTalkFile(const byte *&str) {
- Common::String tempString;
-
- ++str;
- for (int idx = 0; idx < 8 && str[idx] != '~'; ++idx)
- tempString += str[idx];
- str += 8;
-
- int scriptCurrentIndex = str - _scriptStart;
-
- // Save the current script position and new talk file
- if (_scriptStack.size() < 9) {
- ScriptStackEntry rec1;
- rec1._name = _scriptName;
- rec1._currentIndex = scriptCurrentIndex;
- rec1._select = _scriptSelect;
- _scriptStack.push(rec1);
-
- // Push the new talk file onto the stack
- ScriptStackEntry rec2;
- rec2._name = tempString;
- rec2._currentIndex = 0;
- rec2._select = 100;
- _scriptStack.push(rec2);
- }
- else {
- error("Script stack overflow");
- }
-
- _scriptMoreFlag = 1;
- _endStr = true;
- _wait = 0;
-
- return RET_SUCCESS;
-}
-
OpcodeReturn Talk::cmdDisableEndKey(const byte *&str) {
_vm->_ui->_endKeyActive = false;
return RET_SUCCESS;
@@ -1553,44 +1018,20 @@ OpcodeReturn Talk::cmdEnableEndKey(const byte *&str) {
return RET_SUCCESS;
}
-OpcodeReturn Talk::cmdGotoScene(const byte *&str) {
- Map &map = *_vm->_map;
- People &people = *_vm->_people;
- Scene &scene = *_vm->_scene;
- scene._goToScene = str[1] - 1;
-
- if (scene._goToScene != 100) {
- // Not going to the map overview
- map._oldCharPoint = scene._goToScene;
- map._overPos.x = map[scene._goToScene].x * 100 - 600;
- map._overPos.y = map[scene._goToScene].y * 100 + 900;
-
- // Run a canimation?
- if (str[2] > 100) {
- people._hSavedFacing = str[2];
- people._hSavedPos = Common::Point(160, 100);
- }
- }
- str += 6;
-
- _scriptMoreFlag = (scene._goToScene == 100) ? 2 : 1;
- _scriptSaveIndex = str - _scriptStart;
- _endStr = true;
- _wait = 0;
-
+OpcodeReturn Talk::cmdEndTextWindow(const byte *&str) {
return RET_SUCCESS;
}
OpcodeReturn Talk::cmdHolmesOff(const byte *&str) {
People &people = *_vm->_people;
- people[PLAYER]._type = REMOVE;
+ people[HOLMES]._type = REMOVE;
return RET_SUCCESS;
}
OpcodeReturn Talk::cmdHolmesOn(const byte *&str) {
People &people = *_vm->_people;
- people[PLAYER]._type = CHARACTER;
+ people[HOLMES]._type = CHARACTER;
return RET_SUCCESS;
}
@@ -1607,6 +1048,8 @@ OpcodeReturn Talk::cmdPauseWithoutControl(const byte *&str) {
Scene &scene = *_vm->_scene;
++str;
+ events.incWaitCounter();
+
for (int idx = 0; idx < (str[0] - 1); ++idx) {
scene.doBgAnim();
if (_talkToAbort)
@@ -1617,6 +1060,9 @@ OpcodeReturn Talk::cmdPauseWithoutControl(const byte *&str) {
events.setButtonState();
}
+ events.decWaitCounter();
+
+ _endStr = false;
return RET_SUCCESS;
}
@@ -1643,7 +1089,9 @@ OpcodeReturn Talk::cmdRunCAnimation(const byte *&str) {
return RET_EXIT;
// Check if next character is changing side or changing portrait
- if (_charCount && (str[1] == _opcodes[OP_SWITCH_SPEAKER] || str[1] == _opcodes[OP_ASSIGN_PORTRAIT_LOCATION]))
+ _wait = 0;
+ if (_charCount && (str[1] == _opcodes[OP_SWITCH_SPEAKER] ||
+ (IS_SERRATED_SCALPEL && str[1] == _opcodes[OP_ASSIGN_PORTRAIT_LOCATION])))
_wait = 1;
return RET_SUCCESS;
@@ -1697,28 +1145,6 @@ OpcodeReturn Talk::cmdStealthModeDeactivate(const byte *&str) {
return RET_SUCCESS;
}
-OpcodeReturn Talk::cmdSwitchSpeaker(const byte *&str) {
- People &people = *_vm->_people;
- UserInterface &ui = *_vm->_ui;
-
- if (!(_speaker & SPEAKER_REMOVE))
- people.clearTalking();
- if (_talkToAbort)
- return RET_EXIT;
-
- ui.clearWindow();
- _yp = CONTROLS_Y + 12;
- _charCount = _line = 0;
-
- _speaker = *++str - 1;
- people.setTalking(_speaker);
- pullSequence();
- pushSequence(_speaker);
- setSequence(_speaker);
-
- return RET_SUCCESS;
-}
-
OpcodeReturn Talk::cmdToggleObject(const byte *&str) {
Scene &scene = *_vm->_scene;
Common::String tempString;
@@ -1739,397 +1165,26 @@ OpcodeReturn Talk::cmdWalkToCAnimation(const byte *&str) {
++str;
CAnim &animation = scene._cAnim[str[0] - 1];
- people.walkToCoords(animation._goto, animation._gotoDir);
+ people[HOLMES].walkToCoords(animation._goto[0], animation._goto[0]._facing);
return _talkToAbort ? RET_EXIT : RET_SUCCESS;
}
-OpcodeReturn Talk::cmdWalkToCoords(const byte *&str) {
- People &people = *_vm->_people;
- ++str;
-
- people.walkToCoords(Common::Point(((str[0] - 1) * 256 + str[1] - 1) * 100,
- str[2] * 100), str[3] - 1);
- if (_talkToAbort)
- return RET_EXIT;
-
- str += 3;
- return RET_SUCCESS;
-}
-
-/*----------------------------------------------------------------*/
-
-ScalpelTalk::ScalpelTalk(SherlockEngine *vm) : Talk(vm) {
- static OpcodeMethod OPCODE_METHODS[] = {
- (OpcodeMethod)&ScalpelTalk::cmdSwitchSpeaker,
- (OpcodeMethod)&ScalpelTalk::cmdRunCAnimation,
- (OpcodeMethod)&ScalpelTalk::cmdAssignPortraitLocation,
-
- (OpcodeMethod)&ScalpelTalk::cmdPause,
- (OpcodeMethod)&ScalpelTalk::cmdRemovePortrait,
- (OpcodeMethod)&ScalpelTalk::cmdClearWindow,
- (OpcodeMethod)&ScalpelTalk::cmdAdjustObjectSequence,
- (OpcodeMethod)&ScalpelTalk::cmdWalkToCoords,
- (OpcodeMethod)&ScalpelTalk::cmdPauseWithoutControl,
- (OpcodeMethod)&ScalpelTalk::cmdBanishWindow,
- (OpcodeMethod)&ScalpelTalk::cmdSummonWindow,
- (OpcodeMethod)&ScalpelTalk::cmdSetFlag,
- (OpcodeMethod)&ScalpelTalk::cmdSfxCommand,
-
- (OpcodeMethod)&ScalpelTalk::cmdToggleObject,
- (OpcodeMethod)&ScalpelTalk::cmdStealthModeActivate,
- (OpcodeMethod)&ScalpelTalk::cmdIf,
- (OpcodeMethod)&ScalpelTalk::cmdElse,
- nullptr,
- (OpcodeMethod)&ScalpelTalk::cmdStealthModeDeactivate,
- (OpcodeMethod)&ScalpelTalk::cmdHolmesOff,
- (OpcodeMethod)&ScalpelTalk::cmdHolmesOn,
- (OpcodeMethod)&ScalpelTalk::cmdGotoScene,
- (OpcodeMethod)&ScalpelTalk::cmdPlayPrologue,
-
- (OpcodeMethod)&ScalpelTalk::cmdAddItemToInventory,
- (OpcodeMethod)&ScalpelTalk::cmdSetObject,
- (OpcodeMethod)&ScalpelTalk::cmdCallTalkFile,
- (OpcodeMethod)&ScalpelTalk::cmdMoveMouse,
- (OpcodeMethod)&ScalpelTalk::cmdDisplayInfoLine,
- (OpcodeMethod)&ScalpelTalk::cmdClearInfoLine,
- (OpcodeMethod)&ScalpelTalk::cmdWalkToCAnimation,
- (OpcodeMethod)&ScalpelTalk::cmdRemoveItemFromInventory,
- (OpcodeMethod)&ScalpelTalk::cmdEnableEndKey,
- (OpcodeMethod)&ScalpelTalk::cmdDisableEndKey,
-
- (OpcodeMethod)&ScalpelTalk::cmdCarriageReturn,
- nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
- nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
- nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
- nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
- nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
- nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
- nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr
- };
-
- _opcodeTable = OPCODE_METHODS;
-}
-
-OpcodeReturn ScalpelTalk::cmdAssignPortraitLocation(const byte *&str) {
- People &people = *_vm->_people;
-
- ++str;
- switch (str[0] & 15) {
- case 1:
- people._portraitSide = 20;
- break;
- case 2:
- people._portraitSide = 220;
- break;
- case 3:
- people._portraitSide = 120;
- break;
- default:
- break;
- }
-
- if (str[0] > 15)
- people._speakerFlip = true;
-
- return RET_SUCCESS;
-}
-
-OpcodeReturn ScalpelTalk::cmdClearInfoLine(const byte *&str) {
- UserInterface &ui = *_vm->_ui;
-
- ui._infoFlag = true;
- ui.clearInfo();
-
- return RET_SUCCESS;
-}
-
-OpcodeReturn ScalpelTalk::cmdClearWindow(const byte *&str) {
- UserInterface &ui = *_vm->_ui;
-
- ui.clearWindow();
- _yp = CONTROLS_Y + 12;
- _charCount = _line = 0;
-
- return RET_SUCCESS;
-}
-
-OpcodeReturn ScalpelTalk::cmdDisplayInfoLine(const byte *&str) {
- Screen &screen = *_vm->_screen;
- UserInterface &ui = *_vm->_ui;
- Common::String tempString;
-
- ++str;
- for (int idx = 0; idx < str[0]; ++idx)
- tempString += str[idx + 1];
- str += str[0];
-
- screen.print(Common::Point(0, INFO_LINE + 1), INFO_FOREGROUND, "%s", tempString.c_str());
- ui._menuCounter = 30;
-
- return RET_SUCCESS;
-}
-
-OpcodeReturn ScalpelTalk::cmdElse(const byte *&str) {
- // If this is encountered here, it means that a preceeding IF statement was found,
- // and evaluated to true. Now all the statements for the true block are finished,
- // so skip over the block of code that would have executed if the result was false
- _wait = 0;
- do {
- ++str;
- } while (str[0] && str[0] != _opcodes[OP_END_IF_STATEMENT]);
-
- return RET_SUCCESS;
-}
+void Talk::talkWait(const byte *&str) {
+ if (!_pauseFlag && _charCount < 160)
+ _charCount = 160;
-OpcodeReturn ScalpelTalk::cmdIf(const byte *&str) {
- ++str;
- int flag = (str[0] - 1) * 256 + str[1] - 1 - (str[1] == 1 ? 1 : 0);
- ++str;
- _wait = 0;
+ _wait = waitForMore(_charCount);
+ if (_wait == -1)
+ _endStr = true;
- bool result = flag < 0x8000;
- if (_vm->readFlags(flag & 0x7fff) != result) {
- do {
- ++str;
- } while (str[0] && str[0] != _opcodes[OP_ELSE_STATEMENT] && str[0] != _opcodes[OP_END_IF_STATEMENT]);
-
- if (!str[0])
- _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 (str[0] == _opcodes[OP_SFX_COMMAND])
+ str += 9;
}
- return RET_SUCCESS;
-}
-
-OpcodeReturn ScalpelTalk::cmdMoveMouse(const byte *&str) {
- Events &events = *_vm->_events;
-
- ++str;
- events.moveMouse(Common::Point((str[0] - 1) * 256 + str[1] - 1, str[2]));
- if (_talkToAbort)
- return RET_EXIT;
- str += 3;
-
- return RET_SUCCESS;
-}
-
-OpcodeReturn ScalpelTalk::cmdPlayPrologue(const byte *&str) {
- Animation &anim = *_vm->_animation;
- Common::String tempString;
-
- ++str;
- for (int idx = 0; idx < 8 && str[idx] != '~'; ++idx)
- tempString += str[idx];
-
- anim.play(tempString, 1, 3, true, 4);
-
- return RET_SUCCESS;
-}
-
-OpcodeReturn ScalpelTalk::cmdRemovePortrait(const byte *&str) {
- People &people = *_vm->_people;
-
- if (_speaker >= 0 && _speaker < SPEAKER_REMOVE)
- people.clearTalking();
- pullSequence();
- if (_talkToAbort)
- return RET_EXIT;
-
- _speaker |= SPEAKER_REMOVE;
- return RET_SUCCESS;
-}
-
-OpcodeReturn ScalpelTalk::cmdSfxCommand(const byte *&str) {
- Sound &sound = *_vm->_sound;
- Common::String tempString;
-
- ++str;
- if (sound._voices) {
- for (int idx = 0; idx < 8 && str[idx] != '~'; ++idx)
- tempString += str[idx];
- sound.playSound(tempString, WAIT_RETURN_IMMEDIATELY);
-
- // Set voices to wait for more
- sound._voices = 2;
- sound._speechOn = (*sound._soundIsOn);
- }
-
- _wait = 1;
- str += 7;
-
- return RET_SUCCESS;
-}
-
-OpcodeReturn ScalpelTalk::cmdSummonWindow(const byte *&str) {
- Events &events = *_vm->_events;
- Screen &screen = *_vm->_screen;
-
- drawInterface();
- events._pressed = events._released = false;
- events.clearKeyboard();
- _noTextYet = false;
-
- if (_speaker != -1) {
- screen.buttonPrint(Common::Point(119, CONTROLS_Y), COMMAND_NULL, false, "Exit");
- screen.buttonPrint(Common::Point(159, CONTROLS_Y), COMMAND_NULL, false, "Up");
- screen.buttonPrint(Common::Point(200, CONTROLS_Y), COMMAND_NULL, false, "Down");
- }
-
- return RET_SUCCESS;
-}
-
-OpcodeReturn ScalpelTalk::cmdCarriageReturn(const byte *&str) {
- return RET_SUCCESS;
-}
-
-/*----------------------------------------------------------------*/
-
-TattooTalk::TattooTalk(SherlockEngine *vm) : Talk(vm) {
- static OpcodeMethod OPCODE_METHODS[] = {
- nullptr, nullptr,
- nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
- nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
- nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
- nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
- (OpcodeMethod)&TattooTalk::cmdSwitchSpeaker,
-
- (OpcodeMethod)&TattooTalk::cmdRunCAnimation,
- (OpcodeMethod)&TattooTalk::cmdCallTalkFile,
- (OpcodeMethod)&TattooTalk::cmdPause,
- (OpcodeMethod)&TattooTalk::cmdMouseOnOff,
- (OpcodeMethod)&TattooTalk::cmdSetWalkControl,
- (OpcodeMethod)&TattooTalk::cmdAdjustObjectSequence,
- (OpcodeMethod)&TattooTalk::cmdWalkToCoords,
- (OpcodeMethod)&TattooTalk::cmdPauseWithoutControl,
- (OpcodeMethod)&TattooTalk::cmdBanishWindow,
- (OpcodeMethod)&TattooTalk::cmdSetTalkSequence,
-
- (OpcodeMethod)&TattooTalk::cmdSetFlag,
- (OpcodeMethod)&TattooTalk::cmdPlaySong,
- (OpcodeMethod)&TattooTalk::cmdToggleObject,
- (OpcodeMethod)&TattooTalk::cmdStealthModeActivate,
- (OpcodeMethod)&TattooTalk::cmdWalkNPCToCAnimation,
- (OpcodeMethod)&TattooTalk::cmdWalkNPCToCoords,
- (OpcodeMethod)&TattooTalk::cmdWalkHomesAndNPCToCoords,
- (OpcodeMethod)&TattooTalk::cmdStealthModeDeactivate,
- (OpcodeMethod)&TattooTalk::cmdHolmesOff,
- (OpcodeMethod)&TattooTalk::cmdHolmesOn,
-
- (OpcodeMethod)&TattooTalk::cmdGotoScene,
- (OpcodeMethod)&TattooTalk::cmdSetNPCPathDest,
- (OpcodeMethod)&TattooTalk::cmdAddItemToInventory,
- (OpcodeMethod)&TattooTalk::cmdSetObject,
- (OpcodeMethod)&TattooTalk::cmdNextSong,
- (OpcodeMethod)&TattooTalk::cmdSetNPCPathPause,
- (OpcodeMethod)&TattooTalk::cmdPassword,
- (OpcodeMethod)&TattooTalk::cmdSetSceneEntryFlag,
- (OpcodeMethod)&TattooTalk::cmdWalkToCAnimation,
- (OpcodeMethod)&TattooTalk::cmdRemoveItemFromInventory,
-
- (OpcodeMethod)&TattooTalk::cmdEnableEndKey,
- (OpcodeMethod)&TattooTalk::cmdDisableEndKey,
- nullptr,
- (OpcodeMethod)&TattooTalk::cmdWalkHomesAndNPCToCoords,
- (OpcodeMethod)&TattooTalk::cmdSetNPCTalkFile,
- (OpcodeMethod)&TattooTalk::cmdSetNPCOff,
- (OpcodeMethod)&TattooTalk::cmdSetNPCOn,
- (OpcodeMethod)&TattooTalk::cmdSetNPCDescOnOff,
- (OpcodeMethod)&TattooTalk::cmdSetNPCPathPauseTakingNotes,
- (OpcodeMethod)&TattooTalk::cmdSetNPCPathPauseLookingHolmes,
-
- (OpcodeMethod)&TattooTalk::cmdTalkInterruptsEnable,
- (OpcodeMethod)&TattooTalk::cmdTalkInterruptsDisable,
- (OpcodeMethod)&TattooTalk::cmdSetNPCInfoLine,
- (OpcodeMethod)&TattooTalk::cmdSetNPCPosition,
- (OpcodeMethod)&TattooTalk::cmdNPCLabelSet,
- (OpcodeMethod)&TattooTalk::cmdNPCLabelGoto,
- (OpcodeMethod)&TattooTalk::cmdNPCLabelIfFlagGoto,
- (OpcodeMethod)&TattooTalk::cmdSetNPCWalkGraphics,
- nullptr,
- (OpcodeMethod)&TattooTalk::cmdSetNPCVerb,
-
- (OpcodeMethod)&TattooTalk::cmdSetNPCVerbCAnimation,
- (OpcodeMethod)&TattooTalk::cmdSetNPCVerbScript,
- nullptr,
- (OpcodeMethod)&TattooTalk::cmdRestorePeopleSequence,
- (OpcodeMethod)&TattooTalk::cmdSetNPCVerbTarget,
- (OpcodeMethod)&TattooTalk::cmdTurnSoundsOff
- };
-
- _opcodeTable = OPCODE_METHODS;
-}
-
-OpcodeReturn TattooTalk::cmdMouseOnOff(const byte *&str) { error("TODO: script opcode"); }
-
-OpcodeReturn TattooTalk::cmdNextSong(const byte *&str) {
- Sound &sound = *_vm->_sound;
-
- // Get the name of the next song to play
- ++str;
- sound._nextSongName = "";
- for (int idx = 0; idx < 8; ++idx) {
- if (str[idx] != '~')
- sound._nextSongName += str[idx];
- else
- break;
- }
- str += 7;
-
- return RET_SUCCESS;
-}
-
-OpcodeReturn TattooTalk::cmdNPCLabelGoto(const byte *&str) { error("TODO: script opcode"); }
-OpcodeReturn TattooTalk::cmdNPCLabelIfFlagGoto(const byte *&str) { error("TODO: script opcode"); }
-OpcodeReturn TattooTalk::cmdNPCLabelSet(const byte *&str) { error("TODO: script opcode"); }
-OpcodeReturn TattooTalk::cmdPassword(const byte *&str) { error("TODO: script opcode"); }
-OpcodeReturn TattooTalk::cmdPlaySong(const byte *&str) { error("TODO: script opcode"); }
-OpcodeReturn TattooTalk::cmdRestorePeopleSequence(const byte *&str) { error("TODO: script opcode"); }
-OpcodeReturn TattooTalk::cmdSetNPCDescOnOff(const byte *&str) { error("TODO: script opcode"); }
-OpcodeReturn TattooTalk::cmdSetNPCInfoLine(const byte *&str) { error("TODO: script opcode"); }
-OpcodeReturn TattooTalk::cmdSetNPCOff(const byte *&str) { error("TODO: script opcode"); }
-OpcodeReturn TattooTalk::cmdSetNPCOn(const byte *&str) { error("TODO: script opcode"); }
-OpcodeReturn TattooTalk::cmdSetNPCPathDest(const byte *&str) { error("TODO: script opcode"); }
-OpcodeReturn TattooTalk::cmdSetNPCPathPause(const byte *&str) { error("TODO: script opcode"); }
-OpcodeReturn TattooTalk::cmdSetNPCPathPauseTakingNotes(const byte *&str) { error("TODO: script opcode"); }
-OpcodeReturn TattooTalk::cmdSetNPCPathPauseLookingHolmes(const byte *&str) { error("TODO: script opcode"); }
-OpcodeReturn TattooTalk::cmdSetNPCPosition(const byte *&str) { error("TODO: script opcode"); }
-OpcodeReturn TattooTalk::cmdSetNPCTalkFile(const byte *&str) { error("TODO: script opcode"); }
-OpcodeReturn TattooTalk::cmdSetNPCVerb(const byte *&str) { error("TODO: script opcode"); }
-OpcodeReturn TattooTalk::cmdSetNPCVerbCAnimation(const byte *&str) { error("TODO: script opcode"); }
-OpcodeReturn TattooTalk::cmdSetNPCVerbScript(const byte *&str) { error("TODO: script opcode"); }
-OpcodeReturn TattooTalk::cmdSetNPCVerbTarget(const byte *&str) { error("TODO: script opcode"); }
-
-OpcodeReturn TattooTalk::cmdSetNPCWalkGraphics(const byte *&str) {
- ++str;
- int npc = *str - 1;
- People &people = *_vm->_people;
- Person &person = people[npc];
-
- // Build up walk library name for the given NPC
- person._walkVGSName = "";
- for (int idx = 0; idx < 8; ++idx) {
- if (str[idx + 1] != '~')
- person._walkVGSName += str[idx + 1];
- else
- break;
- }
- person._walkVGSName += ".VGS";
-
- people._forceWalkReload = true;
- str += 8;
-
- return RET_SUCCESS;
+ _pauseFlag = false;
}
-OpcodeReturn TattooTalk::cmdSetSceneEntryFlag(const byte *&str) { error("TODO: script opcode"); }
-OpcodeReturn TattooTalk::cmdSetTalkSequence(const byte *&str) { error("TODO: script opcode"); }
-OpcodeReturn TattooTalk::cmdSetWalkControl(const byte *&str) { error("TODO: script opcode"); }
-OpcodeReturn TattooTalk::cmdTalkInterruptsDisable(const byte *&str) { error("TODO: script opcode"); }
-OpcodeReturn TattooTalk::cmdTalkInterruptsEnable(const byte *&str) { error("TODO: script opcode"); }
-OpcodeReturn TattooTalk::cmdTurnSoundsOff(const byte *&str) { error("TODO: script opcode"); }
-OpcodeReturn TattooTalk::cmdWalkHolmesAndNPCToCAnimation(const byte *&str) { error("TODO: script opcode"); }
-OpcodeReturn TattooTalk::cmdWalkNPCToCAnimation(const byte *&str) { error("TODO: script opcode"); }
-OpcodeReturn TattooTalk::cmdWalkNPCToCoords(const byte *&str) { error("TODO: script opcode"); }
-OpcodeReturn TattooTalk::cmdWalkHomesAndNPCToCoords(const byte *&str) { error("TODO: script opcode"); }
-
} // End of namespace Sherlock
diff --git a/engines/sherlock/talk.h b/engines/sherlock/talk.h
index ebfe8f1732..a22a39db94 100644
--- a/engines/sherlock/talk.h
+++ b/engines/sherlock/talk.h
@@ -26,14 +26,15 @@
#include "common/scummsys.h"
#include "common/array.h"
#include "common/rect.h"
-#include "common/serializer.h"
#include "common/stream.h"
#include "common/stack.h"
+#include "sherlock/objects.h"
+#include "sherlock/saveload.h"
namespace Sherlock {
+#define SPEAKER_REMOVE 0x80
#define MAX_TALK_SEQUENCES 11
-#define MAX_TALK_FILES 500
enum {
OP_SWITCH_SPEAKER = 0,
@@ -69,7 +70,7 @@ enum {
OP_REMOVE_ITEM_FROM_INVENTORY = 30,
OP_ENABLE_END_KEY = 31,
OP_DISABLE_END_KEY = 32,
- OP_CARRIAGE_RETURN = 33,
+ OP_END_TEXT_WINDOW = 33,
OP_MOUSE_OFF_ON = 34,
OP_SET_WALK_CONTROL = 35,
@@ -82,27 +83,29 @@ enum {
OP_NEED_PASSWORD = 42,
OP_SET_SCENE_ENTRY_FLAG = 43,
OP_WALK_NPC_TO_CANIM = 44,
- OP_WALK_HOLMES_AND_NPC_TO_COORDS = 45,
- OP_SET_NPC_TALK_FILE = 46,
- OP_TURN_NPC_OFF = 47,
- OP_TURN_NPC_ON = 48,
- OP_NPC_DESC_ON_OFF = 49,
- OP_NPC_PATH_PAUSE_TAKING_NOTES = 50,
- OP_NPC_PATH_PAUSE_LOOKING_HOLMES = 51,
- OP_ENABLE_TALK_INTERRUPTS = 52,
- OP_DISABLE_TALK_INTERRUPTS = 53,
- OP_SET_NPC_INFO_LINE = 54,
- OP_SET_NPC_POSITION = 54,
- OP_NPC_PATH_LABEL = 55,
- OP_PATH_GOTO_LABEL = 56,
- OP_PATH_IF_FLAG_GOTO_LABEL = 57,
- OP_NPC_WALK_GRAPHICS = 58,
- OP_NPC_VERB = 59,
- OP_NPC_VERB_CANIM = 60,
- OP_NPC_VERB_SCRIPT = 61,
- OP_RESTORE_PEOPLE_SEQUENCE = 62,
- OP_NPC_VERB_TARGET = 63,
- OP_TURN_SOUNDS_OFF = 64
+ OP_WALK_NPC_TO_COORDS = 45,
+ OP_WALK_HOLMES_AND_NPC_TO_COORDS = 46,
+ OP_SET_NPC_TALK_FILE = 47,
+ OP_TURN_NPC_OFF = 48,
+ OP_TURN_NPC_ON = 49,
+ OP_NPC_DESC_ON_OFF = 50,
+ OP_NPC_PATH_PAUSE_TAKING_NOTES = 51,
+ OP_NPC_PATH_PAUSE_LOOKING_HOLMES = 52,
+ OP_ENABLE_TALK_INTERRUPTS = 53,
+ OP_DISABLE_TALK_INTERRUPTS = 54,
+ OP_SET_NPC_INFO_LINE = 55,
+ OP_SET_NPC_POSITION = 56,
+ OP_NPC_PATH_LABEL = 57,
+ OP_PATH_GOTO_LABEL = 58,
+ OP_PATH_IF_FLAG_GOTO_LABEL = 59,
+ OP_NPC_WALK_GRAPHICS = 60,
+ OP_NPC_VERB = 61,
+ OP_NPC_VERB_CANIM = 62,
+ OP_NPC_VERB_SCRIPT = 63,
+ OP_RESTORE_PEOPLE_SEQUENCE = 64,
+ OP_NPC_VERB_TARGET = 65,
+ OP_TURN_SOUNDS_OFF = 66,
+ OP_NULL = 67
};
enum OpcodeReturn { RET_EXIT = -1, RET_SUCCESS = 0, RET_CONTINUE = 1 };
@@ -116,8 +119,13 @@ typedef OpcodeReturn(Talk::*OpcodeMethod)(const byte *&str);
struct SequenceEntry {
int _objNum;
Common::Array<byte> _sequences;
- int _frameNumber;
- int _seqTo;
+ Object *_obj; // Pointer to the bgshape that these values go to
+ short _frameNumber; // Frame number in frame sequence to draw
+ short _sequenceNumber; // Start frame of sequences that are repeated
+ int _seqStack; // Allows gosubs to return to calling frame
+ int _seqTo; // Allows 1-5, 8-3 type sequences encoded
+ int _seqCounter; // How many times this sequence has been executed
+ int _seqCounter2;
SequenceEntry();
};
@@ -139,11 +147,12 @@ struct Statement {
int _quotient;
int _talkMap;
Common::Rect _talkPos;
+ int _journal;
/**
* Load the data for a single statement within a talk file
*/
- void synchronize(Common::SeekableReadStream &s);
+ void load(Common::SeekableReadStream &s, bool isRoseTattoo);
};
struct TalkHistoryEntry {
@@ -153,16 +162,6 @@ struct TalkHistoryEntry {
bool &operator[](int index) { return _data[index]; }
};
-struct TalkSequences {
- byte _data[MAX_TALK_SEQUENCES];
-
- TalkSequences() { clear(); }
- TalkSequences(const byte *data);
-
- byte &operator[](int idx) { return _data[idx]; }
- void clear();
-};
-
class Talk {
friend class Scalpel::ScalpelUserInterface;
private:
@@ -170,48 +169,18 @@ private:
* Remove any voice commands from a loaded statement list
*/
void stripVoiceCommands();
-
- /**
- * Form a table of the display indexes for statements
- */
- void setTalkMap();
-
- /**
- * Display a list of statements in a window at the bottom of the screen that the
- * player can select from.
- */
- bool displayTalk(bool slamIt);
-
- /**
- * Prints a single conversation option in the interface window
- */
- int talkLine(int lineNum, int stateNum, byte color, int lineY, bool slamIt);
-
- /**
- * Parses a reply for control codes and display text. The found text is printed within
- * the text window, handles delays, animations, and animating portraits.
- */
- void doScript(const Common::String &script);
-
- /**
- * When the talk window has been displayed, waits a period of time proportional to
- * the amount of text that's been displayed
- */
- int waitForMore(int delay);
protected:
SherlockEngine *_vm;
OpcodeMethod *_opcodeTable;
Common::Stack<SequenceEntry> _savedSequences;
- Common::Stack<SequenceEntry> _sequenceStack;
Common::Stack<ScriptStackEntry> _scriptStack;
- Common::Array<Statement> _statements;
- TalkHistoryEntry _talkHistory[MAX_TALK_FILES];
- int _speaker;
+ Common::Array<TalkHistoryEntry> _talkHistory;
int _talkIndex;
int _scriptSelect;
int _talkStealth;
int _talkToFlag;
int _scriptSaveIndex;
+ int _3doSpeechIndex;
// These fields are used solely by doScript, but are fields because all the script opcodes are
// separate methods now, and need access to these fields
@@ -229,10 +198,9 @@ protected:
OpcodeReturn cmdAddItemToInventory(const byte *&str);
OpcodeReturn cmdAdjustObjectSequence(const byte *&str);
OpcodeReturn cmdBanishWindow(const byte *&str);
- OpcodeReturn cmdCallTalkFile(const byte *&str);
OpcodeReturn cmdDisableEndKey(const byte *&str);
OpcodeReturn cmdEnableEndKey(const byte *&str);
- OpcodeReturn cmdGotoScene(const byte *&str);
+ OpcodeReturn cmdEndTextWindow(const byte *&str);
OpcodeReturn cmdHolmesOff(const byte *&str);
OpcodeReturn cmdHolmesOn(const byte *&str);
OpcodeReturn cmdPause(const byte *&str);
@@ -243,20 +211,61 @@ protected:
OpcodeReturn cmdSetObject(const byte *&str);
OpcodeReturn cmdStealthModeActivate(const byte *&str);
OpcodeReturn cmdStealthModeDeactivate(const byte *&str);
- OpcodeReturn cmdSwitchSpeaker(const byte *&str);
OpcodeReturn cmdToggleObject(const byte *&str);
OpcodeReturn cmdWalkToCAnimation(const byte *&str);
- OpcodeReturn cmdWalkToCoords(const byte *&str);
+protected:
+ /**
+ * Checks, if a character is an opcode
+ */
+ bool isOpcode(byte checkCharacter);
+
+ /**
+ * Form a table of the display indexes for statements
+ */
+ void setTalkMap();
+
+ /**
+ * When the talk window has been displayed, waits a period of time proportional to
+ * the amount of text that's been displayed
+ */
+ int waitForMore(int delay);
+
+ /**
+ * Display the talk interface window
+ */
+ virtual void talkInterface(const byte *&str) = 0;
+
+ /**
+ * Pause when displaying a talk dialog on-screen
+ */
+ virtual void talkWait(const byte *&str);
+
+ /**
+ * Show the talk display
+ */
+ virtual void showTalk() = 0;
+
+ /**
+ * Called when a character being spoken to has no talk options to display
+ */
+ virtual void nothingToSay() = 0;
+
+ /**
+ * Called when the active speaker is switched
+ */
+ virtual void switchSpeaker() {}
public:
+ Common::Array<Statement> _statements;
bool _talkToAbort;
int _talkCounter;
int _talkTo;
int _scriptMoreFlag;
+ bool _openTalkWindow;
Common::String _scriptName;
bool _moreTalkUp, _moreTalkDown;
int _converseNum;
const byte *_opcodes;
-
+ int _speaker;
public:
static Talk *init(SherlockEngine *vm);
virtual ~Talk() {}
@@ -274,7 +283,13 @@ public:
* In their case, the conversation display is simply suppressed, and control is passed on to
* doScript to implement whatever action is required.
*/
- void talkTo(const Common::String &filename);
+ virtual void talkTo(const Common::String filename);
+
+ /**
+ * Parses a reply for control codes and display text. The found text is printed within
+ * the text window, handles delays, animations, and animating portraits.
+ */
+ void doScript(const Common::String &script);
/**
* Main method for handling conversations when a character to talk to has been
@@ -282,7 +297,7 @@ public:
* interface window for the conversation and passes on control to give the
* player a list of options to make a selection from
*/
- void talk(int objNum);
+ void initTalk(int objNum);
/**
* Clear loaded talk data
@@ -290,48 +305,26 @@ public:
void freeTalkVars();
/**
- * Draws the interface for conversation display
- */
- void drawInterface();
-
- /**
* Opens the talk file 'talk.tlk' and searches the index for the specified
* conversation. If found, the data for that conversation is loaded
*/
void loadTalkFile(const Common::String &filename);
/**
- * Change the sequence of a background object corresponding to a given speaker.
- * The new sequence will display the character as "listening"
- */
- void setStillSeq(int speaker);
-
- /**
- * Clears the stack of pending object sequences associated with speakers in the scene
- */
- void clearSequences();
-
- /**
- * Pulls a background object sequence from the sequence stack and restore's the
- * object's sequence
- */
- void pullSequence();
-
- /**
* Push the sequence of a background object that's an NPC that needs to be
* saved onto the sequence stack.
*/
void pushSequence(int speaker);
/**
- * Change the sequence of the scene background object associated with the current speaker.
+ * Push the details of a passed object onto the saved sequences stack
*/
- void setSequence(int speaker);
+ virtual void pushSequenceEntry(Object *obj) = 0;
/**
- * Returns true if the script stack is empty
+ * Clears the stack of pending object sequences associated with speakers in the scene
*/
- bool isSequencesEmpty() const { return _scriptStack.empty(); }
+ virtual void clearSequences() = 0;
/**
* Pops an entry off of the script stack
@@ -341,66 +334,34 @@ public:
/**
* Synchronize the data for a savegame
*/
- void synchronize(Common::Serializer &s);
-};
+ void synchronize(Serializer &s);
-class ScalpelTalk : public Talk {
-protected:
- OpcodeReturn cmdAssignPortraitLocation(const byte *&str);
- OpcodeReturn cmdClearInfoLine(const byte *&str);
- OpcodeReturn cmdClearWindow(const byte *&str);
- OpcodeReturn cmdDisplayInfoLine(const byte *&str);
- OpcodeReturn cmdElse(const byte *&str);
- OpcodeReturn cmdIf(const byte *&str);
- OpcodeReturn cmdMoveMouse(const byte *&str);
- OpcodeReturn cmdPlayPrologue(const byte *&str);
- OpcodeReturn cmdRemovePortrait(const byte *&str);
- OpcodeReturn cmdSfxCommand(const byte *&str);
- OpcodeReturn cmdSummonWindow(const byte *&str);
- OpcodeReturn cmdCarriageReturn(const byte *&str);
-public:
- ScalpelTalk(SherlockEngine *vm);
- virtual ~ScalpelTalk() {}
-};
+ /**
+ * Draws the interface for conversation display
+ */
+ virtual void drawInterface() {}
-class TattooTalk : public Talk {
-protected:
- OpcodeReturn cmdMouseOnOff(const byte *&str);
- OpcodeReturn cmdNextSong(const byte *&str);
- OpcodeReturn cmdPassword(const byte *&str);
- OpcodeReturn cmdPlaySong(const byte *&str);
- OpcodeReturn cmdRestorePeopleSequence(const byte *&str);
- OpcodeReturn cmdSetNPCDescOnOff(const byte *&str);
- OpcodeReturn cmdSetNPCInfoLine(const byte *&str);
- OpcodeReturn cmdNPCLabelGoto(const byte *&str);
- OpcodeReturn cmdNPCLabelIfFlagGoto(const byte *&str);
- OpcodeReturn cmdNPCLabelSet(const byte *&str);
- OpcodeReturn cmdSetNPCOff(const byte *&str);
- OpcodeReturn cmdSetNPCOn(const byte *&str);
- OpcodeReturn cmdSetNPCPathDest(const byte *&str);
- OpcodeReturn cmdSetNPCPathPause(const byte *&str);
- OpcodeReturn cmdSetNPCPathPauseTakingNotes(const byte *&str);
- OpcodeReturn cmdSetNPCPathPauseLookingHolmes(const byte *&str);
- OpcodeReturn cmdSetNPCPosition(const byte *&str);
- OpcodeReturn cmdSetNPCTalkFile(const byte *&str);
- OpcodeReturn cmdSetNPCVerb(const byte *&str);
- OpcodeReturn cmdSetNPCVerbCAnimation(const byte *&str);
- OpcodeReturn cmdSetNPCVerbScript(const byte *&str);
- OpcodeReturn cmdSetNPCVerbTarget(const byte *&str);
- OpcodeReturn cmdSetNPCWalkGraphics(const byte *&str);
- OpcodeReturn cmdSetSceneEntryFlag(const byte *&str);
- OpcodeReturn cmdSetTalkSequence(const byte *&str);
- OpcodeReturn cmdSetWalkControl(const byte *&str);
- OpcodeReturn cmdTalkInterruptsDisable(const byte *&str);
- OpcodeReturn cmdTalkInterruptsEnable(const byte *&str);
- OpcodeReturn cmdTurnSoundsOff(const byte *&str);
- OpcodeReturn cmdWalkHolmesAndNPCToCAnimation(const byte *&str);
- OpcodeReturn cmdWalkNPCToCAnimation(const byte *&str);
- OpcodeReturn cmdWalkNPCToCoords(const byte *&str);
- OpcodeReturn cmdWalkHomesAndNPCToCoords(const byte *&str);
-public:
- TattooTalk(SherlockEngine *vm);
- virtual ~TattooTalk() {}
+ /**
+ * Display a list of statements in a window at the bottom of the screen that the
+ * player can select from.
+ */
+ virtual bool displayTalk(bool slamIt) { return false; }
+
+ /**
+ * Prints a single conversation option in the interface window
+ */
+ virtual int talkLine(int lineNum, int stateNum, byte color, int lineY, bool slamIt) { return 0; }
+
+ /**
+ * Pulls a background object sequence from the sequence stack and restore's the
+ * object's sequence
+ */
+ virtual void pullSequence(int slot = -1) = 0;
+
+ /**
+ * Returns true if the script stack is empty
+ */
+ virtual bool isSequencesEmpty() const = 0;
};
} // End of namespace Sherlock
diff --git a/engines/sherlock/tattoo/tattoo.cpp b/engines/sherlock/tattoo/tattoo.cpp
index 368b24bfcd..bfb35565bc 100644
--- a/engines/sherlock/tattoo/tattoo.cpp
+++ b/engines/sherlock/tattoo/tattoo.cpp
@@ -20,20 +20,34 @@
*
*/
-#include "sherlock/tattoo/tattoo.h"
+#include "common/config-manager.h"
#include "engines/util.h"
+#include "sherlock/tattoo/tattoo.h"
+#include "sherlock/tattoo/tattoo_fixed_text.h"
+#include "sherlock/tattoo/tattoo_resources.h"
+#include "sherlock/tattoo/tattoo_scene.h"
+#include "sherlock/tattoo/tattoo_user_interface.h"
+#include "sherlock/tattoo/widget_base.h"
+#include "sherlock/people.h"
namespace Sherlock {
namespace Tattoo {
TattooEngine::TattooEngine(OSystem *syst, const SherlockGameDescription *gameDesc) :
- SherlockEngine(syst, gameDesc) {
- _creditsActive = false;
+ SherlockEngine(syst, gameDesc), _darts(this), _foolscapWidget(this) {
+ _runningProlog = false;
+ _fastMode = false;
+ _allowFastMode = true;
+ _transparentMenus = true;
+ _textWindowsOn = true;
+}
+
+TattooEngine::~TattooEngine() {
}
void TattooEngine::showOpening() {
- // TODO
+ // No implementation - opening is done using in-game scenes
}
void TattooEngine::initialize() {
@@ -42,20 +56,83 @@ void TattooEngine::initialize() {
// Initialize the base engine
SherlockEngine::initialize();
- _flags.resize(100 * 8);
+ // Initialise the global flags
+ _flags.resize(3200);
+ _flags[1] = _flags[4] = _flags[76] = true;
+ _runningProlog = true;
// Add some more files to the cache
_res->addToCache("walk.lib");
+
+ // Set up list of people
+ for (int idx = 0; idx < TATTOO_MAX_PEOPLE; ++idx) {
+ _people->_characters.push_back(PersonData(
+ getLanguage() == Common::FR_FRA ? FRENCH_NAMES[idx] : ENGLISH_NAMES[idx],
+ PORTRAITS[idx], nullptr, nullptr));
+ }
+
+ // Load the inventory
+ loadInventory();
// Starting scene
- _scene->_goToScene = 91;
+ _scene->_goToScene = STARTING_INTRO_SCENE;
// Load an initial palette
loadInitialPalette();
}
void TattooEngine::startScene() {
- // TODO
+ TattooUserInterface &ui = *(TattooUserInterface *)_ui;
+
+ switch (_scene->_goToScene) {
+ case 7:
+ case 8:
+ case 18:
+ case 53:
+ case 68:
+ // Load overlay mask(s) for the scene
+ ui._mask = _res->load(Common::String::format("res%02d.msk", _scene->_goToScene));
+ if (_scene->_goToScene == 8)
+ ui._mask1 = _res->load("res08a.msk");
+ else if (_scene->_goToScene == 18 || _scene->_goToScene == 68)
+ ui._mask1 = _res->load("res08a.msk");
+ break;
+
+ case STARTING_INTRO_SCENE:
+ // Disable input so that the intro can't be skipped until the game's logo has been shown
+ ui._lockoutTimer = STARTUP_KEYS_DISABLED_DELAY;
+ break;
+
+ case OVERHEAD_MAP:
+ case OVERHEAD_MAP2:
+ // Show the map
+ _scene->_currentScene = OVERHEAD_MAP;
+ _scene->_goToScene = _map->show();
+
+ _people->_savedPos = Common::Point(-1, -1);
+ _people->_savedPos._facing = -1;
+ break;
+
+ case 101:
+ // Darts Board minigame
+ _darts.playDarts(GAME_CRICKET);
+ break;
+
+ case 102:
+ // Darts Board minigame
+ _darts.playDarts(GAME_301);
+ break;
+
+ case 103:
+ // Darts Board minigame
+ _darts.playDarts(GAME_501);
+ break;
+
+ default:
+ break;
+ }
+
+ _events->setCursor(ARROW);
}
void TattooEngine::loadInitialPalette() {
@@ -68,14 +145,65 @@ void TattooEngine::loadInitialPalette() {
delete stream;
}
-void TattooEngine::drawCredits() {
- // TODO
+void TattooEngine::loadInventory() {
+ Inventory &inv = *_inventory;
+
+ Common::String inv1 = _fixedText->getText(kFixedText_Inv1);
+ Common::String inv2 = _fixedText->getText(kFixedText_Inv2);
+ Common::String inv3 = _fixedText->getText(kFixedText_Inv3);
+ Common::String inv4 = _fixedText->getText(kFixedText_Inv4);
+ Common::String inv5 = _fixedText->getText(kFixedText_Inv5);
+ Common::String inv6 = _fixedText->getText(kFixedText_Inv6);
+ Common::String inv7 = _fixedText->getText(kFixedText_Inv7);
+ Common::String inv8 = _fixedText->getText(kFixedText_Inv8);
+ Common::String invDesc1 = _fixedText->getText(kFixedText_InvDesc1);
+ Common::String invDesc2 = _fixedText->getText(kFixedText_InvDesc2);
+ Common::String invDesc3 = _fixedText->getText(kFixedText_InvDesc3);
+ Common::String invDesc4 = _fixedText->getText(kFixedText_InvDesc4);
+ Common::String invDesc5 = _fixedText->getText(kFixedText_InvDesc5);
+ Common::String invDesc6 = _fixedText->getText(kFixedText_InvDesc6);
+ Common::String invDesc7 = _fixedText->getText(kFixedText_InvDesc7);
+ Common::String invDesc8 = _fixedText->getText(kFixedText_InvDesc8);
+ Common::String solve = _fixedText->getText(kFixedText_Solve);
+
+ // Initial inventory
+ inv._holdings = 5;
+ inv.push_back(InventoryItem(0, inv1, invDesc1, "_ITEM01A"));
+ inv.push_back(InventoryItem(0, inv2, invDesc2, "_ITEM02A"));
+ inv.push_back(InventoryItem(0, inv3, invDesc3, "_ITEM03A"));
+ inv.push_back(InventoryItem(0, inv4, invDesc4, "_ITEM04A"));
+ inv.push_back(InventoryItem(0, inv5, invDesc5, "_ITEM05A"));
+
+ // Hidden items
+ inv.push_back(InventoryItem(295, inv6, invDesc6, "_PAP212D", solve));
+ inv.push_back(InventoryItem(294, inv7, invDesc7, "_PAP212I"));
+ inv.push_back(InventoryItem(818, inv8, invDesc8, "_LANT02I"));
+}
+
+void TattooEngine::doFoolscapPuzzle() {
+ _foolscapWidget.show();
+}
+
+void TattooEngine::loadConfig() {
+ SherlockEngine::loadConfig();
+
+ _transparentMenus = ConfMan.getBool("transparent_windows");
+ _textWindowsOn = ConfMan.getBool("subtitles") || !_sound->_speechOn;
+}
+
+void TattooEngine::saveConfig() {
+ SherlockEngine::saveConfig();
+
+ ConfMan.setBool("transparent_windows", _transparentMenus);
+ ConfMan.setBool("subtitles", _textWindowsOn);
+ ConfMan.flushToDisk();
}
-void TattooEngine::eraseCredits() {
- // TODO
+bool TattooEngine::canSaveGameStateCurrently() {
+ TattooUserInterface &ui = *(TattooUserInterface *)_ui;
+ return _canLoadSave && !ui._creditsWidget.active() && !_runningProlog;
}
} // End of namespace Tattoo
-} // End of namespace Scalpel
+} // End of namespace Sherlock
diff --git a/engines/sherlock/tattoo/tattoo.h b/engines/sherlock/tattoo/tattoo.h
index bb6310dbe3..71872ab1b9 100644
--- a/engines/sherlock/tattoo/tattoo.h
+++ b/engines/sherlock/tattoo/tattoo.h
@@ -24,17 +24,48 @@
#define SHERLOCK_TATTOO_H
#include "sherlock/sherlock.h"
+#include "sherlock/tattoo/tattoo_darts.h"
+#include "sherlock/tattoo/widget_foolscap.h"
namespace Sherlock {
namespace Tattoo {
+enum {
+ INV_FOREGROUND = 167,
+ INV_BACKGROUND = 1,
+ INFO_FOREGROUND = 233,
+ INFO_BACKGROUND = 239,
+ INFO_TOP = 185,
+ INFO_MIDDLE = 186,
+ INFO_BOTTOM = 188,
+ MENU_BACKGROUND = 225,
+ COMMAND_FOREGROUND = 15,
+ COMMAND_HIGHLIGHTED = 254,
+ COMMAND_NULL = 193,
+ PEN_COLOR = 248,
+ PEN_HIGHLIGHT_COLOR = 129
+};
+
+enum {
+ FLAG_PLAYER_IS_HOLMES = 76,
+ FLAG_ALT_MAP_MUSIC = 525
+};
+
class TattooEngine : public SherlockEngine {
private:
+ Darts _darts;
+ WidgetFoolscap _foolscapWidget;
+
/**
* Loads the initial palette for the game
*/
void loadInitialPalette();
+
+ /**
+ * Load the initial inventory
+ */
+ void loadInventory();
protected:
/**
* Initialize the engine
@@ -47,21 +78,34 @@ protected:
* Starting a scene within the game
*/
virtual void startScene();
+
+ /**
+ * Load configuration options
+ */
+ virtual void loadConfig();
public:
- bool _creditsActive;
+ bool _runningProlog;
+ bool _fastMode, _allowFastMode;
+ bool _transparentMenus;
+ bool _textWindowsOn;
public:
TattooEngine(OSystem *syst, const SherlockGameDescription *gameDesc);
- virtual ~TattooEngine() {}
+ virtual ~TattooEngine();
+
+ /**
+ * Shows the foolscap puzzle
+ */
+ void doFoolscapPuzzle();
/**
- * Draw credits on the screen
+ * Save the game configuration
*/
- void drawCredits();
+ virtual void saveConfig();
/**
- * Erase any area of the screen covered by credits
+ * Returns true if the game can be saved
*/
- void eraseCredits();
+ virtual bool canSaveGameStateCurrently();
};
} // End of namespace Tattoo
diff --git a/engines/sherlock/tattoo/tattoo_darts.cpp b/engines/sherlock/tattoo/tattoo_darts.cpp
new file mode 100644
index 0000000000..cb4b52b01a
--- /dev/null
+++ b/engines/sherlock/tattoo/tattoo_darts.cpp
@@ -0,0 +1,1000 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public 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_darts.h"
+#include "sherlock/tattoo/tattoo_fixed_text.h"
+#include "sherlock/tattoo/tattoo.h"
+
+namespace Sherlock {
+
+namespace Tattoo {
+
+enum {
+ DART_COLOR_FORE = 5,
+ PLAYER_COLOR = 11
+};
+
+static const int STATUS_INFO_X = 430;
+static const int STATUS_INFO_Y = 50;
+static const int STATUS_INFO_WIDTH = 205;
+static const int STATUS_INFO_HEIGHT = 330;
+static const int STATUS2_INFO_X = 510;
+static const int STATUS2_X_ADD = STATUS2_INFO_X - STATUS_INFO_X;
+static const int DART_BAR_VX = 10;
+static const int DART_HEIGHT_Y = 121;
+static const int DART_BAR_SIZE = 150;
+static const int DARTBOARD_LEFT = 73;
+static const int DARTBOARD_TOP = 68;
+static const int DARTBOARD_WIDTH = 257;
+static const int DARTBOARD_HEIGHT = 256;
+static const int DARTBOARD_TOTALX = DARTBOARD_WIDTH * 120 / 100;
+static const int DARTBOARD_TOTALY = DARTBOARD_HEIGHT * 120 / 100;
+static const int DARTBOARD_TOTALTOP = DARTBOARD_TOP - DARTBOARD_WIDTH / 10;
+static const int DARTBOARD_TOTALLEFT = DARTBOARD_LEFT - DARTBOARD_HEIGHT / 10;
+static const int CRICKET_VALUE[7] = { 20, 19, 18, 17, 16, 15, 25 };
+
+Darts::Darts(SherlockEngine *vm) : _vm(vm) {
+ _gameType = GAME_301;
+ _hand1 = _hand2 = nullptr;
+ _dartGraphics = nullptr;
+ _dartsLeft = nullptr;
+ _dartMap = nullptr;
+ _dartBoard = nullptr;
+ Common::fill(&_cricketScore[0][0], &_cricketScore[0][7], 0);
+ Common::fill(&_cricketScore[1][0], &_cricketScore[1][7], 0);
+ _score1 = _score2 = 0;
+ _roundNum = 0;
+ _roundScore = 0;
+ _level = 0;
+ _oldDartButtons = false;
+ _handX = 0;
+ _compPlay = 1;
+ _escapePressed = false;
+}
+
+void Darts::playDarts(GameType gameType) {
+ Events &events = *_vm->_events;
+ Scene &scene = *_vm->_scene;
+ Screen &screen = *_vm->_screen;
+ int oldFontType = screen.fontNumber();
+ int playerNum = 0;
+ int roundStart, score;
+ int lastDart;
+ int numHits = 0;
+ bool gameOver = false;
+ bool done = false;
+ const char *const NUM_HITS_STR[3] = { "a", FIXED(Double), FIXED(Triple) };
+
+ screen.setFont(7);
+ _spacing = screen.fontHeight() + 2;
+
+ // Load dart graphics and initialize values
+ loadDarts();
+ initDarts();
+
+ while (!done && !_vm->shouldQuit()) {
+ roundStart = score = (playerNum == 0) ? _score1 : _score2;
+
+ showNames(playerNum);
+ showStatus(playerNum);
+ _roundScore = 0;
+
+ for (int idx = 0; idx < 3 && !_vm->shouldQuit(); ++idx) {
+ if (_compPlay == 1)
+ lastDart = throwDart(idx + 1, playerNum * 2); /* Throw one dart */
+ else
+ if (_compPlay == 2)
+ lastDart = throwDart(idx + 1, playerNum + 1); /* Throw one dart */
+ else
+ lastDart = throwDart(idx + 1, 0); /* Throw one dart */
+
+ if (_gameType == GAME_301) {
+ score -= lastDart;
+ _roundScore += lastDart;
+ } else {
+ numHits = lastDart >> 16;
+ if (numHits == 0)
+ numHits = 1;
+ if (numHits > 3)
+ numHits = 3;
+
+ lastDart = lastDart & 0xffff;
+ updateCricketScore(playerNum, lastDart, numHits);
+ score = (playerNum == 0) ? _score1 : _score2;
+ }
+
+ // Special case for ScummVM: I'm making pressing Escape to exit out of the Darts game as a way to skip
+ // it entirely if you don't want to play all the way through it
+ if (_escapePressed) {
+ gameOver = true;
+ done = true;
+ playerNum = 0;
+ }
+
+
+ if (_gameType == GAME_301) {
+ if (playerNum == 0)
+ _score1 = score;
+ else
+ _score2 = score;
+
+ if (score == 0)
+ // Someone won
+ gameOver = true;
+ } else {
+ // check for cricket game over
+ bool allClosed = true;
+ int nOtherScore;
+
+ for (int y = 0; y < 7; y++) {
+ if (_cricketScore[playerNum][y] < 3)
+ allClosed = false;
+ }
+
+ if (allClosed) {
+ nOtherScore = (playerNum == 0) ? _score2 : _score1;
+ if (score >= nOtherScore)
+ gameOver = true;
+ }
+ }
+
+ // Show scores
+ showStatus(playerNum);
+ screen._backBuffer2.blitFrom(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);
+
+ 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));
+ } 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));
+ }
+
+ if (score != 0 && playerNum == 0 && !gameOver)
+ screen.print(Common::Point(_dartInfo.left, _dartInfo.top + _spacing * 3), 0,
+ "%s", FIXED(PressAKey));
+
+ if (gameOver) {
+ screen.print(Common::Point(_dartInfo.left, _dartInfo.top + _spacing * 3),
+ 0, "%s", FIXED(GameOver));
+ if (playerNum == 0) {
+ screen.print(Common::Point(_dartInfo.left, _dartInfo.top + _spacing * 4), 0,
+ "%s %s", FIXED(Holmes), FIXED(Wins));
+ _vm->setFlagsDirect(531);
+ } else {
+ screen.print(Common::Point(_dartInfo.left, _dartInfo.top + _spacing * 4), 0,
+ "%s %s!", _opponent.c_str(), FIXED(Wins));
+ _vm->setFlagsDirect(530);
+ }
+
+ screen.print(Common::Point(_dartInfo.left, _dartInfo.top + _spacing * 5), 0,
+ "%s", FIXED(PressAKey));
+
+ 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));
+
+ // End turn
+ idx = 10;
+ score = roundStart;
+ if (playerNum == 0)
+ _score1 = score;
+ else
+ _score2 = score;
+ }
+
+ // Clear keyboard events
+ events.clearEvents();
+
+ if ((playerNum == 0 && _compPlay == 1) || _compPlay == 0 || done) {
+ if (_escapePressed) {
+ done = true;
+ break;
+ }
+ } else {
+ events.wait(20);
+ }
+
+ screen._backBuffer1.blitFrom(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);
+ }
+
+ playerNum ^= 1;
+ if (!playerNum)
+ ++_roundNum;
+
+ if (!done) {
+ screen._backBuffer2.blitFrom((*_dartBoard)[0], Common::Point(0, 0));
+ screen._backBuffer1.blitFrom(screen._backBuffer2);
+ screen.blitFrom(screen._backBuffer2);
+ }
+ }
+
+ // Wait for a keypress
+ do {
+ events.pollEventsAndWait();
+ events.setButtonState();
+ } while (!_vm->shouldQuit() && !events.kbHit() && !events._pressed);
+ events.clearEvents();
+
+ closeDarts();
+ screen.fadeToBlack();
+ screen.setFont(oldFontType);
+
+ // Flag to return to the Billard's Academy scene
+ scene._goToScene = 26;
+}
+
+void Darts::initDarts() {
+ _dartInfo = Common::Rect(430, 245, 430 + 205, 245 + 150);
+ _escapePressed = false;
+
+ if (_gameType == GAME_CRICKET) {
+ _dartInfo = Common::Rect(430, 245, 430 + 205, 245 + 150);
+ }
+
+ Common::fill(&_cricketScore[0][0], &_cricketScore[0][7], 0);
+ Common::fill(&_cricketScore[1][0], &_cricketScore[1][7], 0);
+
+ switch (_gameType) {
+ case GAME_501:
+ _score1 = _score2 = 501;
+ _gameType = GAME_301;
+ break;
+
+ case GAME_301:
+ _score1 = _score2 = 301;
+ break;
+
+ default:
+ // Cricket
+ _score1 = _score2 = 0;
+ break;
+ }
+
+ _roundNum = 1;
+
+ if (_level == 9) {
+ // No computer players
+ _compPlay = 0;
+ _level = 0;
+ } else if (_level == 8) {
+ _level = _vm->getRandomNumber(3);
+ _compPlay = 2;
+ } else {
+ // Check for opponent flags
+ for (int idx = 0; idx < 4; ++idx) {
+ if (_vm->readFlags(314 + idx))
+ _level = idx;
+ }
+ }
+
+ _opponent = FIXED(Jock);
+}
+
+void Darts::loadDarts() {
+ Resources &res = *_vm->_res;
+ Screen &screen = *_vm->_screen;
+ byte palette[PALETTE_SIZE];
+
+ // Load images
+ _hand1 = new ImageFile("hand1.vgs");
+ _hand2 = new ImageFile("hand2.vgs");
+ _dartGraphics = new ImageFile("darts.vgs");
+ _dartsLeft = new ImageFile("DartsLft.vgs");
+ _dartMap = new ImageFile("DartMap.vgs");
+ _dartBoard = new ImageFile("DartBd.vgs");
+
+ // Load and set the palette
+ Common::SeekableReadStream *stream = res.load("DartBd.pal");
+ stream->read(palette, PALETTE_SIZE);
+ screen.translatePalette(palette);
+ screen.setPalette(palette);
+ delete stream;
+
+ // Load the initial background
+ screen._backBuffer1.blitFrom((*_dartBoard)[0], Common::Point(0, 0));
+ screen._backBuffer2.blitFrom(screen._backBuffer1);
+ screen.blitFrom(screen._backBuffer1);
+}
+
+void Darts::closeDarts() {
+ delete _dartBoard;
+ delete _dartsLeft;
+ delete _dartGraphics;
+ delete _dartMap;
+ delete _hand1;
+ delete _hand2;
+}
+
+void Darts::showNames(int playerNum) {
+ Screen &screen = *_vm->_screen;
+ 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._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,
+ STATUS_INFO_X + 50, STATUS_INFO_Y + _spacing + 3), color);
+
+ color = playerNum == 1 ? PLAYER_COLOR : DART_COLOR_FORE;
+ screen.print(Common::Point(STATUS2_INFO_X, STATUS_INFO_Y), 0, "%s", _opponent.c_str());
+ screen._backBuffer1.fillRect(Common::Rect(STATUS2_INFO_X, STATUS_INFO_Y + _spacing + 1,
+ STATUS2_INFO_X + 50, STATUS_INFO_Y + _spacing + 3), color);
+ 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);
+}
+
+void Darts::showStatus(int playerNum) {
+ Screen &screen = *_vm->_screen;
+ const char *const CRICKET_SCORE_NAME[7] = { "20", "19", "18", "17", "16", "15", FIXED(Bull) };
+
+ screen._backBuffer1.blitFrom(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);
+
+ 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);
+
+ if (_gameType == GAME_301) {
+ screen.print(Common::Point(STATUS_INFO_X, STATUS_INFO_Y + 75), 0, "%s: %d", FIXED(TurnTotal), _roundScore);
+ } else {
+ // Show cricket scores
+ for (int x = 0; x < 7; ++x) {
+ screen.print(Common::Point(STATUS_INFO_X, STATUS_INFO_Y + 40 + x * _spacing), 0, "%s:", CRICKET_SCORE_NAME[x]);
+
+ for (int y = 0; y < 2; ++y) {
+ switch (CRICKET_SCORE_NAME[y][x]) {
+ case 1:
+ screen.print(Common::Point(STATUS_INFO_X + 38 + y*STATUS2_X_ADD, STATUS_INFO_Y + 40 + x * _spacing), 0, "/");
+ break;
+ case 2:
+ screen.print(Common::Point(STATUS_INFO_X + 38 + y*STATUS2_X_ADD, STATUS_INFO_Y + 40 + x * _spacing), 0, "X");
+ break;
+ case 3:
+ screen.print(Common::Point(STATUS_INFO_X + 38 + y * STATUS2_X_ADD - 1, STATUS_INFO_Y + 40 + x * _spacing), 0, "X");
+ screen.print(Common::Point(STATUS_INFO_X + 37 + y * STATUS2_X_ADD, STATUS_INFO_Y + 40 + x * _spacing), 0, "O");
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ }
+
+ screen.blitFrom(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));
+}
+
+void Darts::erasePowerBars() {
+ Screen &screen = *_vm->_screen;
+
+ // 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.slamArea(DART_BAR_VX - 1, DART_HEIGHT_Y - 1, 10, DART_BAR_SIZE + 2);
+}
+
+bool Darts::dartHit() {
+ Events &events = *_vm->_events;
+ events.pollEventsAndWait();
+ events.setButtonState();
+
+ // Keyboard check
+ if (events.kbHit()) {
+ if (events.getKey().keycode == Common::KEYCODE_ESCAPE)
+ _escapePressed = true;
+
+ events.clearEvents();
+ return true;
+ }
+
+ bool result = events._pressed && !_oldDartButtons;
+ _oldDartButtons = events._pressed;
+ return result;
+}
+
+int Darts::doPowerBar(const Common::Point &pt, byte color, int goToPower, int orientation) {
+ Events &events = *_vm->_events;
+ Screen &screen = *_vm->_screen;
+ int idx = 0;
+
+ events.clearEvents();
+ events.delay(100);
+
+ while (!_vm->shouldQuit()) {
+ if (idx >= DART_BAR_SIZE)
+ break;
+
+ if ((goToPower - 1) == idx)
+ break;
+ else if (goToPower == 0) {
+ if (dartHit())
+ break;
+ }
+
+ 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.slamArea(pt.x, pt.y + DART_BAR_SIZE - 1 - idx, 8, 2);
+
+ if (!(idx % 8))
+ events.wait(1);
+
+ ++idx;
+ }
+
+ return MIN(idx * 100 / DART_BAR_SIZE, 100);
+}
+
+int Darts::drawHand(int goToPower, int computer) {
+ Events &events = *_vm->_events;
+ Screen &screen = *_vm->_screen;
+ const int HAND_OFFSET[2] = { 72, 44 };
+ ImageFile *hands;
+ int hand;
+
+ goToPower = (goToPower * DARTBOARD_WIDTH) / 150;
+
+ if (!computer) {
+ hand = 0;
+ hands = _hand1;
+ } else {
+ hand = 1;
+ hands = _hand2;
+ }
+
+ _handSize.x = (*hands)[0]._offset.x + (*hands)[0]._width;
+ _handSize.y = (*hands)[0]._offset.y + (*hands)[0]._height;
+
+ // Clear keyboard buffer
+ events.clearEvents();
+ events.delay(100);
+
+ 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)
+ break;
+ else if (goToPower == 0) {
+ if (dartHit())
+ break;
+ }
+
+ screen._backBuffer1.transBlitFrom((*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));
+
+ if (!(x % 8))
+ events.wait(1);
+
+ ++x;
+ ++pt.x;
+ }
+
+ _handX = pt.x - 1;
+
+ return MIN(x * 100 / DARTBOARD_WIDTH, 100);
+}
+
+Common::Point Darts::convertFromScreenToScoreCoords(const Common::Point &pt) const {
+ return Common::Point(CLIP((int)pt.x, 0, DARTBOARD_WIDTH), CLIP((int)pt.y, 0, DARTBOARD_HEIGHT));
+}
+
+int Darts::dartScore(const Common::Point &pt) {
+ Common::Point pos(pt.x - DARTBOARD_LEFT, pt.y - DARTBOARD_TOP);
+ if (pos.x < 0 || pos.y < 0)
+ return 0;
+ int score;
+
+ if (pos.x < DARTBOARD_WIDTH && pos.y < DARTBOARD_HEIGHT) {
+ pos = convertFromScreenToScoreCoords(pos);
+ score = *(const byte *)(*_dartMap)[0]._frame.getBasePtr(pos.x, pos.y);
+
+ if (_gameType == GAME_301) {
+ if (score >= 100) {
+ if (score <= 120)
+ // Hit a double
+ score = (score - 100) * 2;
+ else
+ // Hit a triple
+ score = (score - 120) * 3;
+ }
+ } else if (score >= 100) {
+ if (score >= 120)
+ // Hit a double
+ score = (2 << 16) + (score - 100);
+ else
+ // Hit a triple
+ score = (3 << 16) + (score - 120);
+ }
+ } else {
+ score = 0;
+ }
+
+ return score;
+}
+
+void Darts::drawDartThrow(const Common::Point &dartPos, int computer) {
+ Events &events = *_vm->_events;
+ Screen &screen = *_vm->_screen;
+ int cx, cy;
+ int handCy;
+ int drawX = 0, drawY = 0, oldDrawX = 0, oldDrawY = 0;
+ int xSize = 0, ySize = 0, oldxSize = 0, oldySize = 0;
+ int handOCx, handOCy;
+ int ocx, ocy;
+ int handOldxSize, handOldySize;
+ int delta = 9;
+ int dartNum;
+ int hddy;
+
+ // Draw the animation of the hand throwing the dart first
+ // See which hand animation to use
+ ImageFile &hands = !computer ? *_hand1 : *_hand2;
+ int numFrames = !computer ? 14 : 13;
+
+ ocx = ocy = handOCx = handOCy = 0;
+ oldxSize = oldySize = handOldxSize = handOldySize = 1;
+ cx = dartPos.x;
+ cy = SHERLOCK_SCREEN_HEIGHT - _handSize.y - 20;
+
+ hddy = (cy - dartPos.y) / (numFrames - 7);
+ hddy += 2;
+ hddy = hddy * 10 / 8;
+ if (dartPos.y > 275)
+ hddy += 3;
+
+ for (int idx = 0; idx < numFrames; ++idx) {
+ _handSize.x = hands[idx]._offset.x + hands[idx]._width;
+ _handSize.y = hands[idx]._offset.y + hands[idx]._height;
+ handCy = SHERLOCK_SCREEN_HEIGHT - _handSize.y;
+
+ screen._backBuffer1.transBlitFrom(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));
+
+ handOCx = _handX;
+ handOCy = handCy;
+ handOldxSize = _handSize.x;
+ handOldySize = _handSize.y;
+
+ if (idx > 6) {
+ dartNum = idx - 6;
+ if (computer)
+ dartNum += 19;
+
+ xSize = (*_dartGraphics)[dartNum]._width;
+ ySize = (*_dartGraphics)[dartNum]._height;
+
+ ocx = drawX = cx - (*_dartGraphics)[dartNum]._width / 2;
+ ocy = drawY = cy - (*_dartGraphics)[dartNum]._height;
+
+ // Draw dart
+ screen._backBuffer1.transBlitFrom((*_dartGraphics)[dartNum], dartPos);
+
+ if (drawX < 0) {
+ xSize += drawX;
+ if (xSize < 0)
+ xSize = 1;
+ drawX = 0;
+ }
+
+ if (drawY < 0) {
+ ySize += drawY;
+ if (ySize < 0)
+ ySize = 1;
+ drawY = 0;
+ }
+
+ // Flush the drawn dart to the screen
+ screen.slamArea(drawX, drawY, xSize, ySize);
+ if (oldDrawX != -1)
+ // Flush the erased dart area
+ screen.slamArea(oldDrawX, oldDrawY, oldxSize, oldySize);
+
+ screen._backBuffer1.blitFrom(screen._backBuffer2, Common::Point(drawX, drawY),
+ Common::Rect(drawX, drawY, drawX + xSize, drawY + ySize));
+
+ oldDrawX = drawX;
+ oldDrawY = drawY;
+ oldxSize = xSize;
+ oldySize = ySize;
+
+ cy -= hddy;
+ }
+
+ events.wait(1);
+ }
+
+ // Clear the last little bit of the hand from the screen
+ screen.slamArea(handOCx, handOCy, handOldxSize, handOldySize);
+
+ // Erase the old dart
+ if (oldDrawX != -1)
+ screen.slamArea(oldDrawX, oldDrawY, oldxSize, oldySize);
+
+ screen._backBuffer1.blitFrom(screen._backBuffer2, Common::Point(drawX, drawY),
+ Common::Rect(drawX, drawY, drawX + xSize, drawY + ySize));
+
+ cx = dartPos.x;
+ cy = dartPos.y + 2;
+ oldDrawX = oldDrawY = -1;
+
+ for (int idx = 5; idx <= 23; ++idx) {
+ dartNum = idx - 4;
+ if (computer)
+ dartNum += 19;
+
+ if (idx < 14)
+ cy -= delta--;
+ else
+ if (idx == 14)
+ delta = 1;
+ if (idx > 14)
+ cy += delta++;
+
+ xSize = (*_dartGraphics)[dartNum]._width;
+ ySize = (*_dartGraphics)[dartNum]._height;
+
+ ocx = drawX = cx - (*_dartGraphics)[dartNum]._width / 2;
+ ocy = drawY = cy - (*_dartGraphics)[dartNum]._height;
+
+ screen._backBuffer1.transBlitFrom((*_dartGraphics)[dartNum], Common::Point(drawX, drawY));
+
+ if (drawX < 0) {
+ xSize += drawX;
+ if (xSize < 0)
+ xSize = 1;
+ drawX = 0;
+ }
+
+ if (drawY < 0) {
+ ySize += drawY;
+ if (ySize < 0)
+ ySize = 1;
+ drawY = 0;
+ }
+
+ // flush the dart
+ screen.slamArea(drawX, drawY, xSize, ySize);
+ if (oldDrawX != -1)
+ screen.slamArea(oldDrawX, oldDrawY, oldxSize, oldySize);
+
+ if (idx != 23)
+ screen._backBuffer1.blitFrom(screen._backBuffer2, Common::Point(drawX, drawY),
+ Common::Rect(drawX, drawY, drawX + xSize, drawY + ySize)); // erase dart
+
+ events.wait(1);
+
+ oldDrawX = drawX;
+ oldDrawY = drawY;
+ oldxSize = xSize;
+ oldySize = ySize;
+ }
+
+ dartNum = 19;
+ if (computer)
+ dartNum += 19;
+ xSize = (*_dartGraphics)[dartNum]._width;
+ 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.slamArea(ocx, ocy, xSize, ySize);
+}
+
+int Darts::findNumberOnBoard(int aim, Common::Point &pt) {
+ ImageFrame &img = (*_dartMap)[0];
+
+ if ((aim > 20) && ((aim != 25) && (aim != 50))) {
+ if ((aim <= 40) && ((aim & 1) == 0)) {
+ aim /= 2;
+ aim += 100;
+ } else {
+ aim /= 3;
+ aim += 120;
+ }
+ }
+
+ bool done = false;
+ for (int y = 0; y < img._width && !done; ++y) {
+ for (int x = 0; x < img._height && !done; ++x) {
+ byte score = *(const byte *)img._frame.getBasePtr(x, y);
+
+ if (score == aim) {
+ // Found a match. Aim at non-double/triple numbers whenever possible.
+ // ie. Aim at 18 instead of triple 6 or double 9
+ done = true;
+
+ if (aim < 21) {
+ pt.x = x + 10;
+ pt.y = y + 10;
+
+ score = *(const byte *)img._frame.getBasePtr(x, y);
+ if (score != aim)
+ done = false;
+ } else {
+ // Aiming at double or triple
+ pt.x = x + 3;
+ pt.y = y + 3;
+ }
+ }
+ }
+ }
+
+ pt = convertFromScreenToScoreCoords(pt);
+
+ if (aim == 3)
+ pt.y += 30;
+ if (aim == 17)
+ pt.y += 10;
+
+ if (aim == 15) {
+ pt.y += 5;
+ pt.x += 5;
+ }
+
+ pt.y = DARTBOARD_HEIGHT - pt.y;
+ return done;
+}
+
+void Darts::getComputerNumber(int playerNum, Common::Point &targetPos) {
+ int score;
+ int aim = 0;
+ Common::Point pt;
+ bool done = false;
+ int cricketaimset = false;
+ bool shootBull = false;
+
+ score = (playerNum == 0) ? _score1 : _score2;
+
+ if (_gameType == GAME_301) {
+ // Try to hit number
+ aim = score;
+ if(score > 60)
+ shootBull = true;
+ } else {
+ if (_cricketScore[playerNum][6] < 3) {
+ // shoot at bull first
+ aim = CRICKET_VALUE[6];
+ cricketaimset = true;
+ } else {
+ // Now check and shoot in this order: 20,19,18,17,16,15
+ for (int idx = 0; idx < 7; ++idx) {
+ if (_cricketScore[playerNum][idx] < 3) {
+ aim = CRICKET_VALUE[idx];
+ cricketaimset = true;
+ break;
+ }
+ }
+ }
+
+ if (!cricketaimset) {
+ // Everything is closed
+ // just in case we don't get set in loop below, which should never happen
+ aim = 14;
+ for (int idx = 0; idx < 7; ++idx) {
+ if (_cricketScore[playerNum^1][idx] < 3) {
+ // Opponent has this open
+ aim = CRICKET_VALUE[idx];
+
+ if (idx == 6)
+ shootBull = true;
+ }
+ }
+ }
+ }
+
+ if (shootBull) {
+ // Aim at bulls eye
+ targetPos.x = targetPos.y = 75;
+
+ if (_level <= 1) {
+ if (_vm->getRandomNumber(1) == 1) {
+ targetPos.x += (_vm->getRandomNumber(20)-10);
+ targetPos.y += (_vm->getRandomNumber(20)-10);
+ }
+ }
+ } else {
+ // Loop in case number does not exist on board
+ do {
+ done = findNumberOnBoard(aim, pt);
+ --aim;
+ } while (!done);
+
+ pt.x += DARTBOARD_TOTALLEFT * 70 / 100;
+ pt.y += DARTBOARD_TOTALTOP * 70 / 100;
+
+ // old * 3/2
+ targetPos.x = pt.x * 100 / DARTBOARD_TOTALX * 3 / 2;
+ targetPos.y = pt.y * 100 / DARTBOARD_TOTALY * 3 / 2;
+ }
+
+ // the higher the level, the more accurate the throw
+ int v = _vm->getRandomNumber(9);
+ v += _level * 2;
+
+ if (v <= 2) {
+ targetPos.x += _vm->getRandomNumber(70) - 35;
+ targetPos.y += _vm->getRandomNumber(70) - 35;
+ } else if (v <= 4) {
+ targetPos.x += _vm->getRandomNumber(50) - 25;
+ targetPos.y += _vm->getRandomNumber(50) - 25;
+ } else if (v <= 6) {
+ targetPos.x += _vm->getRandomNumber(30) - 15;
+ targetPos.y += _vm->getRandomNumber(30) - 15;
+ } else if (v <= 8) {
+ targetPos.x += _vm->getRandomNumber(20) -10;
+ targetPos.y += _vm->getRandomNumber(20) -10;
+ } else if (v <= 10) {
+ targetPos.x += _vm->getRandomNumber(11) - 5;
+ targetPos.y += _vm->getRandomNumber(11) - 5;
+ }
+
+ if (targetPos.x < 1)
+ targetPos.x = 1;
+ if (targetPos.y < 1)
+ targetPos.y = 1;
+}
+
+int Darts::throwDart(int dartNum, int computer) {
+ Events &events = *_vm->_events;
+ Screen &screen = *_vm->_screen;
+ int height;
+ int horiz;
+ Common::Point targetPos;
+ Common::String temp;
+
+ /* clear keyboard buffer */
+ events.clearEvents();
+
+ erasePowerBars();
+ screen.print(Common::Point(_dartInfo.left, _dartInfo.top), 0, "%s # %d", FIXED(Dart), dartNum);
+
+ 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));
+ }
+
+ if (!computer) {
+ // Wait for a hit
+ while (!dartHit() && !_vm->shouldQuit())
+ ;
+ if (_escapePressed)
+ return 0;
+ } else {
+ events.wait(1);
+ }
+
+ drawDartsLeft(dartNum + 1, computer);
+ screen._backBuffer1.blitFrom(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),
+ Common::Rect(_dartInfo.left, _dartInfo.top - 1, _dartInfo.right, _dartInfo.bottom - 1));
+
+ if (computer) {
+ getComputerNumber(computer - 1, targetPos);
+ } else {
+ // Keyboard control
+ targetPos = Common::Point(0, 0);
+ }
+
+ horiz = drawHand(targetPos.x, computer);
+ if (_escapePressed)
+ return 0;
+
+ height = doPowerBar(Common::Point(DART_BAR_VX, DART_HEIGHT_Y), DART_COLOR_FORE, targetPos.y, 1);
+ if (_escapePressed)
+ return 0;
+
+ // Invert height
+ 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),
+ Common::Rect(DART_BAR_VX - 1, DART_HEIGHT_Y - 1, DART_BAR_VX - 1 + 10,
+ DART_HEIGHT_Y - 1 + DART_BAR_SIZE + 2));
+
+ Common::Point dartPos(DARTBOARD_TOTALLEFT + horiz*DARTBOARD_TOTALX / 100,
+ DARTBOARD_TOTALTOP + height * DARTBOARD_TOTALY / 100);
+
+ dartPos.x += 2 - _vm->getRandomNumber(4);
+ dartPos.y += 2 - _vm->getRandomNumber(4);
+
+ drawDartThrow(dartPos, computer);
+ return dartScore(dartPos);
+}
+
+void Darts::doCricketScoreHits(int player, int scoreIndex, int numHits) {
+ while (numHits--) {
+ if (_cricketScore[player][scoreIndex] < 3)
+ _cricketScore[player][scoreIndex]++;
+ else if (_cricketScore[player ^ 1][scoreIndex] < 3) {
+ if (player == 0)
+ _score1 += CRICKET_VALUE[scoreIndex];
+ else
+ _score2 += CRICKET_VALUE[scoreIndex];
+ }
+ }
+}
+
+void Darts::updateCricketScore(int player, int dartVal, int multiplier) {
+ if (dartVal < 15)
+ return;
+
+ if (dartVal <= 20)
+ doCricketScoreHits(player, 20 - dartVal, multiplier);
+ else if (dartVal == 25)
+ doCricketScoreHits(player, 6, multiplier);
+}
+
+void Darts::drawDartsLeft(int dartNum, int computer) {
+ Screen &screen = *_vm->_screen;
+ const int DART_X1[3] = { 391, 451, 507 };
+ const int DART_Y1[3] = { 373, 373, 373 };
+ 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]),
+ 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]));
+ else
+ screen._backBuffer1.transBlitFrom((*_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]);
+}
+
+} // End of namespace Tattoo
+
+} // End of namespace Sherlock
diff --git a/engines/sherlock/tattoo/tattoo_darts.h b/engines/sherlock/tattoo/tattoo_darts.h
new file mode 100644
index 0000000000..ab6b1c8204
--- /dev/null
+++ b/engines/sherlock/tattoo/tattoo_darts.h
@@ -0,0 +1,173 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public 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_DARTS_H
+#define SHERLOCK_TATTOO_DARTS_H
+
+#include "common/scummsys.h"
+#include "sherlock/image_file.h"
+
+namespace Sherlock {
+
+class SherlockEngine;
+
+namespace Tattoo {
+
+enum GameType { GAME_301, GAME_CRICKET, GAME_501 };
+
+class Darts {
+private:
+ SherlockEngine *_vm;
+ GameType _gameType;
+ ImageFile *_hand1, *_hand2;
+ ImageFile *_dartGraphics;
+ ImageFile *_dartsLeft;
+ ImageFile *_dartMap;
+ ImageFile *_dartBoard;
+ Common::Rect _dartInfo;
+ int _cricketScore[2][7];
+ int _score1, _score2;
+ int _roundNum;
+ int _roundScore;
+ int _level;
+ int _compPlay;
+ Common::String _opponent;
+ int _spacing;
+ bool _oldDartButtons;
+ int _handX;
+ Common::Point _handSize;
+ bool _escapePressed;
+
+ /**
+ * Initialize game variables
+ */
+ void initDarts();
+
+ /**
+ * Load dartboard graphics
+ */
+ void loadDarts();
+
+ /**
+ * Free loaded dart images
+ */
+ void closeDarts();
+
+ /**
+ * Show the player names
+ */
+ void showNames(int playerNum);
+
+ /**
+ * Show the current scores
+ */
+ void showStatus(int playerNum);
+
+ /**
+ * Erases the power bars
+ */
+ void erasePowerBars();
+
+ /**
+ * Returns true if a mouse button or key is pressed
+ */
+ bool dartHit();
+
+ /**
+ * Shows a power bar and increments it until a key or mouse button is pressed. If the bar
+ * reaches the end, it will also end. The reached power bar number is returned.
+ * @param pt Bar position
+ * @param color draw color
+ * @param goToPower If provided, input is ignored, and the bar is increased up to the specified level
+ * @param orientation 0=Horizontal, 1=Vertical
+ */
+ int doPowerBar(const Common::Point &pt, byte color, int goToPower, int orientation);
+
+ /**
+ * This is similar to doPowerBar, except it draws the player's hand moving across the
+ * bottom of the screen to indicate the positioning of the darts
+ */
+ int drawHand(int goToPower, int computer);
+
+ /**
+ * Converts a passed co-ordinates from screen co-ordinates to an offset within the dartboard
+ */
+ Common::Point convertFromScreenToScoreCoords(const Common::Point &pt) const;
+
+ /**
+ * Return the score a dart at the given position will get
+ */
+ int dartScore(const Common::Point &pt);
+
+ /**
+ * Draw a dart travelling to the board
+ */
+ void drawDartThrow(const Common::Point &dartPos, int computer);
+
+ /**
+ * Looks for the passed number on the dartboard. If it finds it, it will return
+ * the co-ordinates of the center of the number
+ */
+ int findNumberOnBoard(int aim, Common::Point &pt);
+
+ /**
+ * Calculates a position for the comptuer wants to throw, and then calculates where they
+ * actually did throw. The computer will not always hit what it's aiming it.
+ */
+ void getComputerNumber(int playerNum, Common::Point &targetPos);
+
+ /**
+ * Throw one dart. If computer is 1 or 2, the computer will throw the dart, and user input
+ * will be ignored.
+ * @param computer 1=1st computer player, 2=2nd computer player
+ */
+ int throwDart(int dartNum, int computer);
+
+ /**
+ * This will update the number of hits for the target score, as well as updating the
+ * score if it's closed
+ */
+ void doCricketScoreHits(int player, int scoreIndex, int numHits);
+
+ /**
+ * Updates the score based upon what the dart hit
+ */
+ void updateCricketScore(int player, int dartVal, int multiplier);
+
+ /**
+ * Draw the darts left
+ */
+ void drawDartsLeft(int dartNum, int computer);
+public:
+ Darts(SherlockEngine *vm);
+
+ /**
+ * Play the darts game
+ */
+ void playDarts(GameType gameType);
+};
+
+} // End of namespace Tattoo
+
+} // End of namespace Sherlock
+
+#endif
diff --git a/engines/zvision/detection.h b/engines/sherlock/tattoo/tattoo_debugger.cpp
index f80cac79ec..8d59b4c592 100644
--- a/engines/zvision/detection.h
+++ b/engines/sherlock/tattoo/tattoo_debugger.cpp
@@ -20,24 +20,16 @@
*
*/
-#ifndef ZVISION_DETECTION_H
-#define ZVISION_DETECTION_H
+#include "sherlock/tattoo/tattoo_debugger.h"
+#include "sherlock/sherlock.h"
-#include "engines/advancedDetector.h"
+namespace Sherlock {
-namespace ZVision {
-
-enum ZVisionGameId {
- GID_NONE = 0,
- GID_NEMESIS = 1,
- GID_GRANDINQUISITOR = 2
-};
-
-struct ZVisionGameDescription {
- ADGameDescription desc;
- ZVisionGameId gameId;
-};
+namespace Tattoo {
+TattooDebugger::TattooDebugger(SherlockEngine *vm) : Debugger(vm) {
}
-#endif
+} // End of namespace Tattoo
+
+} // End of namespace Sherlock
diff --git a/engines/sherlock/tattoo/tattoo_debugger.h b/engines/sherlock/tattoo/tattoo_debugger.h
new file mode 100644
index 0000000000..e729262b11
--- /dev/null
+++ b/engines/sherlock/tattoo/tattoo_debugger.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_DEBUGGER_H
+#define SHERLOCK_TATTOO_DEBUGGER_H
+
+#include "sherlock/debugger.h"
+
+namespace Sherlock {
+
+class SherlockEngine;
+
+namespace Tattoo {
+
+class TattooDebugger : public Debugger {
+public:
+ TattooDebugger(SherlockEngine *vm);
+ virtual ~TattooDebugger() {}
+};
+
+} // End of namespace Tattoo
+
+} // End of namespace Sherlock
+
+#endif /* SHERLOCK_TATTOO_DEBUGGER_H */
diff --git a/engines/sherlock/tattoo/tattoo_fixed_text.cpp b/engines/sherlock/tattoo/tattoo_fixed_text.cpp
new file mode 100644
index 0000000000..c9345e44d1
--- /dev/null
+++ b/engines/sherlock/tattoo/tattoo_fixed_text.cpp
@@ -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.
+ *
+ */
+
+#include "sherlock/tattoo/tattoo_fixed_text.h"
+#include "sherlock/sherlock.h"
+
+namespace Sherlock {
+
+namespace Tattoo {
+
+static const char *const FIXED_TEXT_ENGLISH[] = {
+ "Money",
+ "Card",
+ "Tobacco",
+ "Timetable",
+ "Summons",
+ "Foolscap",
+ "Damp Paper",
+ "Bull's Eye",
+
+ "Money",
+ "Card",
+ "Tobacco",
+ "Timetable",
+ "Summons",
+ "Foolscap",
+ "Foolscap",
+ "Bull's Eye Lantern",
+
+ "Open",
+ "Look",
+ "Talk",
+ "Use",
+ "Journal",
+ "Inventory",
+ "Options",
+ "Solve",
+ "with",
+ "No effect...",
+ "This person has nothing to say at the moment",
+ "Picked up",
+
+ "Page %d",
+ "Close Journal",
+ "Search Journal",
+ "Save Journal",
+ "Abort Search",
+ "Search Backwards",
+ "Search Forwards",
+ "Text Not Found !",
+
+ "Holmes",
+ "Jock",
+ "Bull",
+ "Round",
+ "Turn Total",
+ "Dart",
+ "to start",
+ "Hit a key",
+ "Press a key",
+ "bullseye",
+ "GAME OVER",
+ "BUSTED",
+ "Wins",
+ "Scored",
+ "points",
+ "Hit",
+ "Double",
+ "Triple",
+
+ "Apply",
+ "Water",
+ "Heat",
+ "Load Game",
+ "Save Game",
+ "Music",
+ "Sound Effects",
+ "Voices",
+ "Text Windows",
+ "Transparent Menus",
+ "Change Font Style",
+ "Off",
+ "On",
+ "Quit",
+ "Are you sure you",
+ "wish to Quit ?",
+ "Yes",
+ "No",
+ "Enter Password",
+ "Going East"
+};
+
+static const char *const FIXED_TEXT_GERMAN[] = {
+ "Geld",
+ "S. Holmes",
+ "Tabak",
+ "Plan",
+ "Aufforderg.",
+ "Blatt pap.",
+ "Dunstig pap",
+ "Handlampe",
+
+ "Geld",
+ "S. Holmes",
+ "Tabak",
+ "Plan",
+ "Aufforderg.",
+ "Pergament",
+ "Dunstig pap",
+ "Handlampe",
+
+ "ffne",
+ "Schau",
+ "Rede",
+ "Benutze",
+ "Journal",
+ "Inventory",
+ "Options",
+ "Losen",
+ "mit",
+ "Keine Wirkung...",
+ "Diese Person weic im Augenblick nichts zu berichten.",
+
+ "Seite %d",
+ "Schliecen",
+ "Lessen",
+ "In Datei sichern",
+ "Suche abbrechen",
+ "Rbckwarts suchen ",
+ "Vorwarts suchen ",
+ "Text nicht gefunden",
+
+ "Holmes",
+ "Jock",
+ "Bull",
+ "Runde",
+ "Gesamt",
+ "Pfeil",
+ "zum Starten",
+ "Taste dracken",
+ "Taste dracken",
+ "Bullseye",
+ "SPIEL BEENDET",
+ "VERLOREN",
+ "Gewinnt",
+ "Erzielte",
+ "Punkte",
+ "Treffer",
+ "Doppel",
+ "Dreifach",
+
+ "Benutze",
+ "Wasser",
+ "Erhitze",
+ "Spiel laden",
+ "Spiel sichern",
+ "Musik",
+ "Soundeffekte",
+ "Voices",
+ "Textfenster",
+ "Transparente Menbs",
+ "Schriftart andern",
+ "Aus",
+ "An",
+ "Ende",
+ "Spiel beenden? ",
+ "Sind Sie sicher ?",
+ "Ja",
+ "Nein",
+ "Pacwort eingeben",
+ "Going East"
+};
+
+TattooFixedText::TattooFixedText(SherlockEngine *vm) : FixedText(vm) {
+ if (vm->getLanguage() == Common::DE_DEU)
+ _fixedText = FIXED_TEXT_GERMAN;
+ else
+ _fixedText = FIXED_TEXT_ENGLISH;
+}
+
+const char *TattooFixedText::getText(int fixedTextId) {
+ return _fixedText[fixedTextId];
+}
+
+const Common::String TattooFixedText::getActionMessage(FixedTextActionId actionId, int messageIndex) {
+ return Common::String();
+}
+
+
+} // End of namespace Tattoo
+
+} // End of namespace Sherlock
diff --git a/engines/sherlock/tattoo/tattoo_fixed_text.h b/engines/sherlock/tattoo/tattoo_fixed_text.h
new file mode 100644
index 0000000000..3f43678ca2
--- /dev/null
+++ b/engines/sherlock/tattoo/tattoo_fixed_text.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 SHERLOCK_TATTOO_FIXED_TEXT_H
+#define SHERLOCK_TATTOO_FIXED_TEXT_H
+
+#include "sherlock/fixed_text.h"
+
+namespace Sherlock {
+
+namespace Tattoo {
+
+enum FixedTextId {
+ kFixedText_Inv1,
+ kFixedText_Inv2,
+ kFixedText_Inv3,
+ kFixedText_Inv4,
+ kFixedText_Inv5,
+ kFixedText_Inv6,
+ kFixedText_Inv7,
+ kFixedText_Inv8,
+ kFixedText_InvDesc1,
+ kFixedText_InvDesc2,
+ kFixedText_InvDesc3,
+ kFixedText_InvDesc4,
+ kFixedText_InvDesc5,
+ kFixedText_InvDesc6,
+ kFixedText_InvDesc7,
+ kFixedText_InvDesc8,
+ kFixedText_Open,
+ kFixedText_Look,
+ kFixedText_Talk,
+ kFixedText_Use,
+ kFixedText_Journal,
+ kFixedText_Inventory,
+ kFixedText_Options,
+ kFixedText_Solve,
+ kFixedText_With,
+ kFixedText_NoEffect,
+ kFixedText_NothingToSay,
+ kFixedText_PickedUp,
+
+ kFixedText_Page,
+ kFixedText_CloseJournal,
+ kFixedText_SearchJournal,
+ kFixedText_SaveJournal,
+ kFixedText_AbortSearch,
+ kFixedText_SearchBackwards,
+ 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_Apply,
+ kFixedText_Water,
+ kFixedText_Heat,
+ kFixedText_LoadGame,
+ kFixedText_SaveGame,
+ kFixedText_Music,
+ kFixedText_SoundEffects,
+ kFixedText_Voices,
+ kFixedText_TextWindows,
+ kFixedText_TransparentMenus,
+ kFixedText_ChangeFont,
+ kFixedText_Off,
+ kFixedText_On,
+ kFixedText_Quit,
+ kFixedText_AreYouSureYou,
+ kFixedText_WishToQuit,
+ kFixedText_Yes,
+ kFixedText_No,
+ kFixedText_EnterPassword,
+ kFixedText_CorrectPassword
+};
+
+class TattooFixedText: public FixedText {
+private:
+ const char *const *_fixedText;
+public:
+ TattooFixedText(SherlockEngine *vm);
+ virtual ~TattooFixedText() {}
+
+ /**
+ * Gets text
+ */
+ virtual const char *getText(int fixedTextId);
+
+ /**
+ * Get action message
+ */
+ virtual const Common::String getActionMessage(FixedTextActionId actionId, int messageIndex);
+};
+
+} // End of namespace Scalpel
+
+} // End of namespace Sherlock
+
+#endif
diff --git a/engines/sherlock/tattoo/tattoo_inventory.cpp b/engines/sherlock/tattoo/tattoo_inventory.cpp
new file mode 100644
index 0000000000..6bd1822c10
--- /dev/null
+++ b/engines/sherlock/tattoo/tattoo_inventory.cpp
@@ -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.
+ *
+ */
+
+#include "sherlock/tattoo/tattoo_inventory.h"
+#include "sherlock/tattoo/tattoo.h"
+
+namespace Sherlock {
+
+namespace Tattoo {
+
+TattooInventory::TattooInventory(SherlockEngine *vm) : Inventory(vm) {
+ _invShapes.resize(8);
+}
+
+TattooInventory::~TattooInventory() {
+}
+
+void TattooInventory::loadInv() {
+ // Exit if the inventory names are already loaded
+ if (_names.size() > 0)
+ return;
+
+ // Load the inventory names
+ Common::SeekableReadStream *stream = _vm->_res->load("invent.txt");
+
+ int count = stream->readByte();
+ char c;
+
+ for (int idx = 0; idx < count; ++idx) {
+ Common::String name;
+ while ((c = stream->readByte()) != 0)
+ name += c;
+
+ _names.push_back(name);
+ }
+
+ delete stream;
+
+ loadGraphics();
+}
+
+} // End of namespace Tattoo
+
+} // End of namespace Sherlock
diff --git a/engines/sherlock/tattoo/tattoo_inventory.h b/engines/sherlock/tattoo/tattoo_inventory.h
new file mode 100644
index 0000000000..a18324b785
--- /dev/null
+++ b/engines/sherlock/tattoo/tattoo_inventory.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 SHERLOCK_TATTOO_INVENTORY_H
+#define SHERLOCK_TATTOO_INVENTORY_H
+
+#include "sherlock/inventory.h"
+
+namespace Sherlock {
+
+namespace Tattoo {
+
+class TattooInventory : public Inventory {
+public:
+ TattooInventory(SherlockEngine *vm);
+ ~TattooInventory();
+
+ /**
+ * Load the list of names the inventory items correspond to, if not already loaded,
+ * and then calls loadGraphics to load the associated graphics
+ */
+ virtual void loadInv();
+};
+
+} // End of namespace Tattoo
+
+} // End of namespace Sherlock
+
+#endif
diff --git a/engines/sherlock/tattoo/tattoo_journal.cpp b/engines/sherlock/tattoo/tattoo_journal.cpp
new file mode 100644
index 0000000000..29b40096cb
--- /dev/null
+++ b/engines/sherlock/tattoo/tattoo_journal.cpp
@@ -0,0 +1,939 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public 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_journal.h"
+#include "sherlock/tattoo/tattoo_fixed_text.h"
+#include "sherlock/tattoo/tattoo_scene.h"
+#include "sherlock/tattoo/tattoo_user_interface.h"
+#include "sherlock/tattoo/tattoo.h"
+
+namespace Sherlock {
+
+namespace Tattoo {
+
+#define JOURNAL_BAR_WIDTH 450
+
+TattooJournal::TattooJournal(SherlockEngine *vm) : Journal(vm) {
+ _journalImages = nullptr;
+ _selector = _oldSelector = JH_NONE;
+ _wait = false;
+ _exitJournal = false;
+ _scrollingTimer = 0;
+ _savedIndex = _savedSub = _savedPage = 0;
+
+ loadLocations();
+}
+
+void TattooJournal::show() {
+ Events &events = *_vm->_events;
+ Resources &res = *_vm->_res;
+ Screen &screen = *_vm->_screen;
+ TattooUserInterface &ui = *(TattooUserInterface *)_vm->_ui;
+ byte palette[PALETTE_SIZE];
+
+ Common::Point oldScroll = screen._currentScroll;
+ screen._currentScroll = Common::Point(0, 0);
+
+ // Load journal images
+ _journalImages = new ImageFile("journal.vgs");
+
+ // Load palette
+ Common::SeekableReadStream *stream = res.load("journal.pal");
+ stream->read(palette, PALETTE_SIZE);
+ ui.setupBGArea(palette);
+ screen.translatePalette(palette);
+ delete stream;
+
+ // Set screen to black, and set background
+ screen._backBuffer1.blitFrom((*_journalImages)[0], Common::Point(0, 0));
+ screen.empty();
+ screen.setPalette(palette);
+
+ if (_journal.empty()) {
+ _up = _down = false;
+ } else {
+ drawJournal(0, 0);
+ }
+ drawControls(0);
+ screen.slamRect(Common::Rect(0, 0, SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT));
+
+ _exitJournal = false;
+ _scrollingTimer = 0;
+
+ do {
+ events.pollEventsAndWait();
+ events.setButtonState();
+ _wait = true;
+
+ handleKeyboardEvents();
+ highlightJournalControls(true);
+
+ handleButtons();
+
+ if (_wait)
+ events.wait(2);
+
+ } while (!_vm->shouldQuit() && !_exitJournal);
+
+ // Clear events
+ events.clearEvents();
+
+ // Free the images
+ delete _journalImages;
+ _journalImages = nullptr;
+
+ // Reset back to whatever scroll was active for the screen
+ screen._currentScroll = oldScroll;
+}
+
+void TattooJournal::handleKeyboardEvents() {
+ Events &events = *_vm->_events;
+ Screen &screen = *_vm->_screen;
+ Common::Point mousePos = events.mousePos();
+
+ if (!events.kbHit())
+ return;
+
+ Common::KeyState keyState = events.getKey();
+
+ if (keyState.keycode == Common::KEYCODE_TAB && (keyState.flags & Common::KBD_SHIFT)) {
+ // Shift tab
+ Common::Rect r(JOURNAL_BAR_WIDTH, BUTTON_SIZE + screen.fontHeight() + 13);
+ r.moveTo((SHERLOCK_SCREEN_WIDTH - r.width()) / 2, SHERLOCK_SCREEN_HEIGHT - r.height());
+
+ // See if mouse is over any of the journal controls
+ _selector = JH_NONE;
+ if (Common::Rect(r.left + 3, r.top + 3, r.right - 3, r.top + screen.fontHeight() + 4).contains(mousePos))
+ _selector = (mousePos.x - r.left) / (r.width() / 3);
+
+ // If the mouse is not over an option, move the mouse to that it points to the first option
+ if (_selector == JH_NONE) {
+ events.warpMouse(Common::Point(r.left + r.width() / 3 - 10, r.top + screen.fontHeight() + 2));
+ } else {
+ if (_selector == JH_CLOSE)
+ _selector = JH_PRINT;
+ else
+ --_selector;
+
+ events.warpMouse(Common::Point(r.left + (r.width() / 3) * (_selector + 1) - 10, mousePos.y));
+ }
+
+ } else if (keyState.keycode == Common::KEYCODE_PAGEUP) {
+ // See if they have Shift held down to go forward 10 pages
+ if (keyState.flags & Common::KBD_SHIFT) {
+ if (_page > 1) {
+ // Scroll Up 10 pages if possible
+ if (_page < 11)
+ drawJournal(1, (_page - 1) * LINES_PER_PAGE);
+ else
+ drawJournal(1, 10 * LINES_PER_PAGE);
+
+ drawScrollBar();
+ screen.slamArea(0, 0, SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT);
+ _wait = false;
+ }
+ } else {
+ if (_page > 1) {
+ // Scroll Up 1 page
+ drawJournal(1, LINES_PER_PAGE);
+ drawScrollBar();
+ drawJournal(0, 0);
+ screen.slamArea(0, 0, SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT);
+ _wait = false;
+ }
+ }
+
+ } else if (keyState.keycode == Common::KEYCODE_PAGEDOWN) {
+ if (keyState.flags & Common::KBD_SHIFT) {
+ if (_down) {
+ // Scroll down 10 Pages
+ if (_page + 10 > _maxPage)
+ drawJournal(2, (_maxPage - _page) * LINES_PER_PAGE);
+ else
+ drawJournal(2, 10 * LINES_PER_PAGE);
+ drawScrollBar();
+ screen.slamArea(0, 0, SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT);
+
+ _wait = false;
+ }
+ } else {
+ if (_down) {
+ // Scroll down 1 page
+ drawJournal(2, LINES_PER_PAGE);
+ drawScrollBar();
+ drawJournal(0, 0);
+ screen.slamArea(0, 0, SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT);
+
+ _wait = false;
+ }
+ }
+
+ } else if (keyState.keycode == Common::KEYCODE_HOME) {
+ // Scroll to start of journal
+ if (_page > 1) {
+ // Go to the beginning of the journal
+ _index = _sub = _up = _down = 0;
+ _page = 1;
+
+ drawFrame();
+ drawJournal(0, 0);
+
+ drawScrollBar();
+ screen.slamArea(0, 0, SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT);
+
+ _wait = false;
+ }
+
+ } else if (keyState.keycode == Common::KEYCODE_END) {
+ // Scroll to end of journal
+ if (_down) {
+ // Go to the end of the journal
+ drawJournal(2, 100000);
+ drawScrollBar();
+ screen.slamArea(0, 0, SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT);
+
+ _wait = false;
+ }
+ } else if (keyState.keycode == Common::KEYCODE_RETURN) {
+ events._pressed = false;
+ events._released = true;
+ events._oldButtons = 0;
+ } else if (keyState.keycode == Common::KEYCODE_ESCAPE) {
+ _exitJournal = true;
+ } else if (keyState.keycode == Common::KEYCODE_TAB) {
+ Common::Rect r(JOURNAL_BAR_WIDTH, BUTTON_SIZE + screen.fontHeight() + 13);
+ r.moveTo((SHERLOCK_SCREEN_WIDTH - r.width()) / 2, SHERLOCK_SCENE_HEIGHT - r.height());
+
+ // See if the mouse is over any of the journal controls
+ _selector = JH_NONE;
+ if (Common::Rect(r.left + 3, r.top + 3, r.right - 3, r.top + screen.fontHeight() + 4).contains(mousePos))
+ _selector = (mousePos.x - r.left) / (r.width() / 3);
+
+ // If the mouse is not over any of the options, move the mouse so that it points to the first option
+ if (_selector == JH_NONE) {
+ events.warpMouse(Common::Point(r.left + r.width() / 3 - 10, r.top + screen.fontHeight() + 2));
+ } else {
+ if (_selector == JH_PRINT)
+ _selector = JH_NONE;
+ else
+ ++_selector;
+
+ events.warpMouse(Common::Point(r.left + (r.width() / 3) * (_selector + 1) - 10, mousePos.y));
+ }
+ }
+}
+
+void TattooJournal::handleButtons() {
+ Events &events = *_vm->_events;
+ Screen &screen = *_vm->_screen;
+ uint32 frameCounter = events.getFrameCounter();
+ Common::Point mousePos = events.mousePos();
+
+ // If they're dragging the scrollbar thumb, keep it selected whilst the button is being held
+ if ((events._pressed || events._released) && _selector == JH_THUMBNAIL) {
+ // FIgure out the left of the scrollbar scroll area and paging data
+ const int scrollingWidth = JOURNAL_BAR_WIDTH - BUTTON_SIZE * 2 - 6;
+ const int scrollingLeft = (SHERLOCK_SCREEN_WIDTH - JOURNAL_BAR_WIDTH) / 2 + BUTTON_SIZE + 3;
+ const int numPages = (_maxPage + LINES_PER_PAGE - 1) / LINES_PER_PAGE - 1;
+ const int barWidth = CLIP(scrollingWidth / numPages, BUTTON_SIZE, JOURNAL_BAR_WIDTH - BUTTON_SIZE * 2 - 6);
+
+ const int scrollOffset = mousePos.x - scrollingLeft;
+ const int page = scrollOffset * FIXED_INT_MULTIPLIER / ((scrollingWidth - barWidth) * (FIXED_INT_MULTIPLIER / (numPages - 1))) + 1;
+
+ if (page != _page) {
+ if (page < _page)
+ drawJournal(1, (_page - page) * LINES_PER_PAGE);
+ else
+ drawJournal(2, (page - _page) * LINES_PER_PAGE);
+ drawScrollBar();
+ screen.slamArea(0, 0, SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT);
+ _wait = false;
+ }
+ } else if (_selector != JH_NONE && events._pressed) {
+ if (frameCounter >= _scrollingTimer) {
+ // Set next scrolling time
+ _scrollingTimer = frameCounter + 6;
+
+ // Handle different scrolling actions
+ switch (_selector) {
+ case JH_SCROLL_LEFT:
+ // Scroll left (1 page back)
+ if (_page > 1) {
+ // Scroll Up
+ drawJournal(1, LINES_PER_PAGE);
+ drawScrollBar();
+ screen.slamArea(0, 0, SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT);
+ _wait = false;
+ }
+ break;
+
+ case JH_PAGE_LEFT:
+ // Page left (10 pages back)
+ if (_page > 1) {
+ // Scroll Up 10 Pages if possible
+ if (_page < 11)
+ drawJournal(1, (_page - 1) * LINES_PER_PAGE);
+ else
+ drawJournal(1, 10 * LINES_PER_PAGE);
+ drawScrollBar();
+ drawJournal(0, 0);
+ screen.slamArea(0, 0, SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT);
+ _wait = false;
+ }
+ break;
+
+ case JH_PAGE_RIGHT:
+ // Page right (10 pages ahead)
+ if (_down) {
+ // Scroll Down 10 Pages
+ if (_page + 10 > _maxPage)
+ drawJournal(2, (_maxPage - _page) * LINES_PER_PAGE);
+ else
+ drawJournal(2, 10 * LINES_PER_PAGE);
+ drawScrollBar();
+ screen.slamArea(0, 0, SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT);
+ _wait = false;
+ }
+ break;
+
+ case JH_SCROLL_RIGHT:
+ // Scroll right (1 Page Ahead)
+ if (_down) {
+ // Scroll Down
+ drawJournal(2, LINES_PER_PAGE);
+ drawScrollBar();
+ screen.slamArea(0, 0, SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT);
+ _wait = false;
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+ }
+
+ if (events._released || events._rightReleased) {
+ _scrollingTimer = 0;
+
+ switch (_selector) {
+ case JH_CLOSE:
+ _exitJournal = true;
+ break;
+
+ case JH_SEARCH: {
+ // Search Journal
+ disableControls();
+
+ bool notFound = false;
+ int dir;
+
+ do {
+ if ((dir = getFindName(notFound)) != 0) {
+ _savedIndex = _index;
+ _savedSub = _sub;
+ _savedPage = _page;
+
+ if (drawJournal(dir + 2, 1000 * LINES_PER_PAGE) == 0)
+ {
+ _index = _savedIndex;
+ _sub = _savedSub;
+ _page = _savedPage;
+
+ drawFrame();
+ drawJournal(0, 0);
+ notFound = true;
+ } else {
+ break;
+ }
+
+ highlightJournalControls(false);
+ screen.slamArea(0, 0, SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT);
+ } else {
+ break;
+ }
+ } while (!_vm->shouldQuit());
+ break;
+ }
+
+ case JH_PRINT:
+ // Print Journal - not implemented in ScummVM
+ break;
+
+ default:
+ break;
+ }
+ }
+}
+
+void TattooJournal::loadLocations() {
+ Resources &res = *_vm->_res;
+
+ _directory.clear();
+ _locations.clear();
+
+ Common::SeekableReadStream *dir = res.load("talk.lib");
+ dir->skip(4); // Skip header
+
+ // Get the numer of entries
+ _directory.resize(dir->readUint16LE());
+ dir->seek((_directory.size() + 1) * 8, SEEK_CUR);
+
+ // Read in each entry
+ char buffer[17];
+ for (uint idx = 0; idx < _directory.size(); ++idx) {
+ dir->read(buffer, 17);
+ buffer[16] = '\0';
+
+ _directory[idx] = Common::String(buffer);
+ }
+
+ delete dir;
+
+ // Load in the locations stored in journal.txt
+ Common::SeekableReadStream *loc = res.load("journal.txt");
+
+ // Initialize locations
+ _locations.resize(100);
+ for (int idx = 0; idx < 100; ++idx)
+ _locations[idx] = "No Description";
+
+ while (loc->pos() < loc->size()) {
+ // In Rose Tattoo, each location line starts with the location
+ // number, followed by a dot, some spaces and its description
+ // in quotes
+ Common::String line = loc->readLine();
+ Common::String locNumStr;
+ int locNum = 0;
+ int i = 0;
+ Common::String locDesc;
+
+ // Get the location
+ while (Common::isDigit(line[i])) {
+ locNumStr += line[i];
+ i++;
+ }
+ locNum = atoi(locNumStr.c_str()) - 1;
+
+ // Skip the dot, spaces and initial quotation mark
+ while (line[i] == ' ' || line[i] == '.' || line[i] == '\"')
+ i++;
+
+ do {
+ locDesc += line[i];
+ i++;
+ } while (line[i] != '\"');
+
+ _locations[locNum] = locDesc;
+ }
+
+ delete loc;
+}
+
+void TattooJournal::drawFrame() {
+ Screen &screen = *_vm->_screen;
+
+ screen._backBuffer1.blitFrom((*_journalImages)[0], Common::Point(0, 0));
+ drawControls(0);
+
+}
+
+void TattooJournal::drawControls(int mode) {
+ TattooEngine &vm = *(TattooEngine *)_vm;
+ Screen &screen = *_vm->_screen;
+ TattooUserInterface &ui = *(TattooUserInterface *)_vm->_ui;
+ ImageFile &images = *ui._interfaceImages;
+
+ Common::Rect r(JOURNAL_BAR_WIDTH, !mode ? (BUTTON_SIZE + screen.fontHeight() + 13) :
+ (screen.fontHeight() + 4) * 2 + 9);
+ r.moveTo((SHERLOCK_SCREEN_WIDTH - r.width()) / 2, !mode ? (SHERLOCK_SCREEN_HEIGHT - r.height()) :
+ (SHERLOCK_SCREEN_HEIGHT - r.height()) / 2);
+
+ Common::Rect inner = r;
+ inner.grow(-3);
+
+ if (vm._transparentMenus)
+ ui.makeBGArea(inner);
+ else
+ 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));
+
+ // 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 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));
+
+ // Draw the bar above the scroll bar
+ screen._backBuffer1.hLine(r.left + images[4]._width, yp, r.right - images[5]._width, INFO_TOP);
+ screen._backBuffer1.hLine(r.left + images[4]._width, yp + 1, r.right - images[5]._width, INFO_MIDDLE);
+ screen._backBuffer1.hLine(r.left + images[4]._width, yp + 2, r.right - images[5]._width, INFO_BOTTOM);
+
+ if (mode != 2) {
+ // Draw the Bars separating the Journal Commands
+ int xp = r.right / 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.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;
+ }
+ }
+
+ int savedSelector = _oldSelector;
+ _oldSelector = 100;
+
+ switch (mode) {
+ case 0:
+ highlightJournalControls(false);
+ break;
+ case 1:
+ highlightSearchControls(false);
+ break;
+ default:
+ break;
+ }
+
+ _oldSelector = savedSelector;
+}
+
+void TattooJournal::highlightJournalControls(bool slamIt) {
+ Events &events = *_vm->_events;
+ Screen &screen = *_vm->_screen;
+ 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;
+ } else {
+ // Calculate the Scroll Position Bar
+ int numPages = (_maxPage + LINES_PER_PAGE - 1) / LINES_PER_PAGE - 1;
+ int barWidth = (r.width() - BUTTON_SIZE * 2 - 6) / numPages;
+ barWidth = CLIP(barWidth, BUTTON_SIZE, r.width() - BUTTON_SIZE * 2 - 6);
+
+ int barX = (numPages <= 1) ? r.left + 3 + BUTTON_SIZE : (r.width() - BUTTON_SIZE * 2 - 6 - barWidth)
+ * FIXED_INT_MULTIPLIER / (numPages - 1) * (_page - 1) / FIXED_INT_MULTIPLIER + r.left + 3 + BUTTON_SIZE;
+
+ // See if the mouse is over any of the Journal Controls
+ Common::Rect bounds(r.left, r.top, r.right - 3, r.top + screen.fontHeight() + 7);
+ _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))
+ // Press on the Scroll Left button
+ _selector = JH_SCROLL_LEFT;
+ else if (mousePos.x >= (r.left + BUTTON_SIZE + 3) && mousePos.x < barX)
+ // Press on area to the left of the thumb, for scrolling back 10 pages
+ _selector = JH_PAGE_LEFT;
+ else if (mousePos.x >= (barX + barWidth) && mousePos.x < (r.right - BUTTON_SIZE - 3))
+ // Press on area to the right of the thumb, for scrolling forward 10 pages
+ _selector = JH_PAGE_RIGHT;
+ else if (mousePos.x >= (r.right - BUTTON_SIZE) && mousePos.x < r.right)
+ // Press of the Scroll Right button
+ _selector = JH_SCROLL_RIGHT;
+ else if (mousePos.x >= barX && mousePos.x < (barX + barWidth))
+ // Mouse on thumbnail
+ _selector = JH_THUMBNAIL;
+ }
+ }
+
+ // See if the Search was selected, but is not available
+ if (_journal.empty() && (_selector == JH_SEARCH || _selector == JH_PRINT))
+ _selector = JH_NONE;
+
+ if (_selector == JH_PAGE_LEFT && _oldSelector == JH_PAGE_RIGHT)
+ _selector = JH_PAGE_RIGHT;
+ else if (_selector == JH_PAGE_RIGHT && _oldSelector == JH_PAGE_LEFT)
+ _selector = JH_PAGE_LEFT;
+
+ // See if they're pointing at a different control
+ if (_selector != _oldSelector) {
+ // Print the Journal commands
+ int xp = r.left + r.width() / 6;
+ byte color = (_selector == JH_CLOSE) ? COMMAND_HIGHLIGHTED : INFO_TOP;
+
+ screen.gPrint(Common::Point(xp - screen.stringWidth(FIXED(CloseJournal)) / 2, r.top + 5),
+ color, "%s", FIXED(CloseJournal));
+ xp += r.width() / 3;
+
+ if (!_journal.empty())
+ color = (_selector == JH_SEARCH) ? COMMAND_HIGHLIGHTED : INFO_TOP;
+ else
+ color = INFO_BOTTOM;
+ screen.gPrint(Common::Point(xp - screen.stringWidth(FIXED(SearchJournal)) / 2, r.top + 5),
+ color, "%s", FIXED(SearchJournal));
+ xp += r.width() / 3;
+
+ color = INFO_BOTTOM;
+ screen.gPrint(Common::Point(xp - screen.stringWidth(FIXED(SaveJournal)) / 2, r.top + 5),
+ color, "%s", FIXED(SaveJournal));
+
+ // Draw the horizontal scrollbar
+ drawScrollBar();
+
+ if (slamIt)
+ screen.slamRect(r);
+
+ _oldSelector = _selector;
+ }
+}
+
+void TattooJournal::highlightSearchControls(bool slamIt) {
+ Events &events = *_vm->_events;
+ Screen &screen = *_vm->_screen;
+ Common::Point mousePos = events.mousePos();
+ Common::Rect r(JOURNAL_BAR_WIDTH, (screen.fontHeight() + 4) * 2 + 9);
+ r.moveTo((SHERLOCK_SCREEN_WIDTH - r.width()) / 2, (SHERLOCK_SCREEN_HEIGHT - r.height()) / 2);
+ const char *SEARCH_COMMANDS[3] = { FIXED(AbortSearch), FIXED(SearchBackwards), FIXED(SearchForwards) };
+
+ // See if the mouse is over any of the Journal Controls
+ _selector = JH_NONE;
+ if (Common::Rect(r.left + 3, r.top + 3, r.right - 3, r.top + 7 + screen.fontHeight()).contains(mousePos))
+ _selector = (mousePos.x - r.left) / (r.width() / 3);
+
+ // See if they're pointing at a different control
+ if (_selector != _oldSelector) {
+ // Print the search commands
+ int xp = r.left + r.width() / 6;
+
+ for (int idx = 0; idx < 3; ++idx) {
+ byte color = (_selector == idx) ? COMMAND_HIGHLIGHTED : INFO_TOP;
+ screen.gPrint(Common::Point(xp - screen.stringWidth(SEARCH_COMMANDS[idx]) / 2,
+ r.top + 5), color, "%s", SEARCH_COMMANDS[idx]);
+ xp += r.width() / 3;
+ }
+
+ if (slamIt)
+ screen.slamRect(r);
+
+ _oldSelector = _selector;
+ }
+}
+
+void TattooJournal::drawScrollBar() {
+ Screen &screen = *_vm->_screen;
+ TattooUserInterface &ui = *(TattooUserInterface *)_vm->_ui;
+ bool raised;
+ byte color;
+
+ Common::Rect r(JOURNAL_BAR_WIDTH, BUTTON_SIZE + screen.fontHeight() + 13);
+ r.moveTo((SHERLOCK_SCREEN_WIDTH - r.width()) / 2, SHERLOCK_SCREEN_HEIGHT - r.height());
+
+ // Calculate the Scroll Position Bar
+ int numPages = (_maxPage + LINES_PER_PAGE - 1) / LINES_PER_PAGE - 1;
+ int barWidth = (r.width() - BUTTON_SIZE * 2 - 6) / numPages;
+ barWidth = CLIP(barWidth, BUTTON_SIZE, r.width() - BUTTON_SIZE * 2 - 6);
+ int barX;
+ if (numPages <= 1) {
+ barX = r.left + 3 + BUTTON_SIZE;
+ } else {
+ barX = (r.width() - BUTTON_SIZE * 2 - 6 - barWidth) * FIXED_INT_MULTIPLIER / (numPages - 1) *
+ (_page - 1) / FIXED_INT_MULTIPLIER + r.left + 3 + BUTTON_SIZE;
+ if (barX + BUTTON_SIZE > r.left + r.width() - BUTTON_SIZE - 3)
+ barX = r.right - BUTTON_SIZE * 2 - 3;
+ }
+
+ // Draw the scroll bar here
+ // Draw the Scroll Left button
+ 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,
+ r.top + screen.fontHeight() + 10 + BUTTON_SIZE), raised);
+
+ color = (_page > 1) ? INFO_BOTTOM + 2 : INFO_BOTTOM;
+ screen._backBuffer1.vLine(r.left + 1 + BUTTON_SIZE / 2, r.top + screen.fontHeight() + 10 + BUTTON_SIZE / 2,
+ r.top + screen.fontHeight() + 10 + BUTTON_SIZE / 2, color);
+ screen._backBuffer1.vLine(r.left + 2 + BUTTON_SIZE / 2, r.top + screen.fontHeight() + 9 + BUTTON_SIZE / 2,
+ r.top + screen.fontHeight() + 11 + BUTTON_SIZE / 2, color);
+ screen._backBuffer1.vLine(r.left + 3 + BUTTON_SIZE / 2, r.top + screen.fontHeight() + 8 + BUTTON_SIZE / 2,
+ r.top + screen.fontHeight() + 12 + BUTTON_SIZE / 2, color);
+ screen._backBuffer1.vLine(r.left + 4 + BUTTON_SIZE / 2, r.top + screen.fontHeight() + 7 + BUTTON_SIZE / 2,
+ r.top + screen.fontHeight() + 13 + BUTTON_SIZE / 2, color);
+
+ // 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,
+ 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,
+ 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,
+ 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);
+ screen._backBuffer1.vLine(r.right - 4 - BUTTON_SIZE + BUTTON_SIZE / 2, r.top + screen.fontHeight() + 7 + BUTTON_SIZE / 2,
+ r.top + screen.fontHeight() + 13 + BUTTON_SIZE / 2, color);
+
+ // Draw the scroll bar
+ screen._backBuffer1.fillRect(Common::Rect(barX + 2, r.top + screen.fontHeight() + 12, barX + barWidth - 3,
+ r.top + screen.fontHeight() + BUTTON_SIZE + 9), INFO_MIDDLE);
+ ui.drawDialogRect(screen._backBuffer1, Common::Rect(barX, r.top + screen.fontHeight() + 10, barX + barWidth,
+ r.top + screen.fontHeight() + 10 + BUTTON_SIZE), true);
+}
+
+void TattooJournal::disableControls() {
+ Screen &screen = *_vm->_screen;
+ Common::Rect r(JOURNAL_BAR_WIDTH, BUTTON_SIZE + screen.fontHeight() + 13);
+ r.moveTo((SHERLOCK_SCREEN_HEIGHT - r.width()) / 2, SHERLOCK_SCREEN_HEIGHT - r.height());
+ const char *JOURNAL_COMMANDS[3] = { FIXED(CloseJournal), FIXED(SearchJournal), FIXED(SaveJournal) };
+
+ // Print the Journal commands
+ int xp = r.left + r.width() / 6;
+ for (int idx = 0; idx < 2; ++idx) {
+ screen.gPrint(Common::Point(xp - screen.stringWidth(JOURNAL_COMMANDS[idx]) / 2, r.top + 5),
+ INFO_BOTTOM, "%s", JOURNAL_COMMANDS[idx]);
+
+ xp += r.width() / 3;
+ }
+
+ screen.slamRect(r);
+}
+
+int TattooJournal::getFindName(bool printError) {
+ Events &events = *_vm->_events;
+ Screen &screen = *_vm->_screen;
+ Talk &talk = *_vm->_talk;
+ int result = 0;
+ int done = 0;
+ Common::String name;
+ int cursorX, cursorY;
+ bool flag = false;
+
+ Common::Rect r(JOURNAL_BAR_WIDTH, (screen.fontHeight() + 4) * 2 + 9);
+ r.moveTo((SHERLOCK_SCREEN_WIDTH - r.width()) / 2, (SHERLOCK_SCREEN_HEIGHT - r.height()) / 2);
+
+ // Set the cursors Y position
+ cursorY = r.top + screen.fontHeight() + 12;
+
+ drawControls(1);
+
+ // 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,
+ r.right - 3, cursorY + screen.fontHeight()));
+
+ if (printError) {
+ screen.gPrint(Common::Point(0, cursorY), INFO_TOP, "%s", FIXED(TextNotFound));
+ } else {
+ // If there was a name already entered, copy it to name and display it
+ if (!_find.empty()) {
+ screen.gPrint(Common::Point(r.left + screen.widestChar() + 3, cursorY), COMMAND_HIGHLIGHTED, "%s", _find.c_str());
+ name = _find;
+ }
+ }
+
+ screen.slamRect(r);
+
+ if (printError) {
+ // Pause to allow error to be shown
+ int timer = 0;
+
+ do {
+ events.pollEvents();
+ events.setButtonState();
+
+ ++timer;
+ events.wait(2);
+ } while (!_vm->shouldQuit() && !events.kbHit() && !events._released && !events._rightReleased && timer < 40);
+
+ events.clearEvents();
+
+ // Restore the text background
+ screen._backBuffer1.blitFrom(bgSurface, Common::Point(r.left, cursorY));
+
+ // If there was a name already entered, copy it to name and display it
+ if (!_find.empty()) {
+ screen.gPrint(Common::Point(r.left + screen.widestChar() + 3, cursorY), COMMAND_HIGHLIGHTED, "%s", _find.c_str());
+ name = _find;
+ }
+
+ screen.slamArea(r.left + 3, cursorY, r.width() - 6, screen.fontHeight());
+ }
+
+ // Set the cursors X position
+ cursorX = r.left + screen.widestChar() + 3 + screen.stringWidth(name);
+
+ do {
+ events._released = events._rightReleased = false;
+
+ while (!events.kbHit() && !events._released && !events._rightReleased) {
+ if (talk._talkToAbort)
+ return 0;
+
+ // See if a key or a mouse button is pressed
+ events.pollEventsAndWait();
+ events.setButtonState();
+
+ // Handle blinking cursor
+ flag = !flag;
+ if (flag) {
+ // Draw cursor
+ screen._backBuffer1.fillRect(Common::Rect(cursorX, cursorY, cursorX + 7, cursorY + 8), COMMAND_HIGHLIGHTED);
+ screen.slamArea(cursorX, cursorY, 8, 9);
+ } else {
+ // Erase cursor by restoring background and writing current text
+ screen._backBuffer1.blitFrom(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, r.top, r.width() - 3, screen.fontHeight());
+ }
+
+ highlightSearchControls(true);
+
+ events.wait(2);
+ }
+
+ if (events.kbHit()) {
+ Common::KeyState keyState = events.getKey();
+ Common::Point mousePos = events.mousePos();
+
+ if (keyState.keycode == Common::KEYCODE_BACKSPACE && !name.empty()) {
+ cursorX -= screen.charWidth(name.lastChar());
+ name.deleteLastChar();
+ }
+
+ if (keyState.keycode == Common::KEYCODE_RETURN)
+ done = 1;
+
+ else if (keyState.keycode == Common::KEYCODE_ESCAPE)
+ done = -1;
+
+ if (keyState.keycode == Common::KEYCODE_TAB) {
+ r = Common::Rect(JOURNAL_BAR_WIDTH, BUTTON_SIZE + screen.fontHeight() + 13);
+ r.moveTo((SHERLOCK_SCREEN_WIDTH - r.width()) / 2, (SHERLOCK_SCREEN_HEIGHT - r.height()) / 2);
+
+ // See if the mouse is over any of the journal controls
+ _selector = JH_NONE;
+ if (Common::Rect(r.left + 3, r.top + 3, r.right - 3, r.top + screen.fontHeight() + 4).contains(mousePos))
+ _selector = (mousePos.x - r.left) / (r.width() / 3);
+
+ // If the mouse is not over any of the options, move the mouse so that it points to the first option
+ if (_selector == JH_NONE) {
+ events.warpMouse(Common::Point(r.left + r.width() / 3, r.top + screen.fontHeight() + 2));
+ } else {
+ if (keyState.keycode & Common::KBD_SHIFT) {
+ if (_selector == JH_CLOSE)
+ _selector = JH_PRINT;
+ else
+ --_selector;
+ } else {
+ if (_selector == JH_PRINT)
+ _selector = JH_CLOSE;
+ else
+ ++_selector;
+ }
+
+ events.warpMouse(Common::Point(r.left + (r.width() / 3) * (_selector + 1) - 10, mousePos.y));
+ }
+ }
+
+ if (keyState.ascii && keyState.ascii != '@' && name.size() < 50) {
+ if ((cursorX + screen.charWidth(keyState.ascii)) < (r.right - screen.widestChar() * 3)) {
+ cursorX += screen.charWidth(keyState.ascii);
+ name += toupper(keyState.ascii);
+ }
+ }
+
+ // Redraw the text
+ screen._backBuffer1.blitFrom(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());
+ }
+
+ if (events._released || events._rightReleased) {
+ switch (_selector) {
+ case JH_CLOSE:
+ done = -1;
+ break;
+ case JH_SEARCH:
+ done = 2;
+ break;
+ case JH_PRINT:
+ done = 1;
+ break;
+ default:
+ break;
+ }
+ }
+ } while (!done);
+
+ if (done != -1) {
+ _find = name;
+ result = done;
+ } else {
+ result = 0;
+ }
+
+ drawFrame();
+ drawJournal(0, 0);
+ screen.slamArea(0, 0, SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT);
+
+ return result;
+}
+
+void TattooJournal::record(int converseNum, int statementNum, bool replyOnly) {
+ TattooEngine &vm = *(TattooEngine *)_vm;
+
+ // Only record activity in the Journal if the player is Holmes (i.e. we're paast the prologoue)
+ if (_vm->readFlags(FLAG_PLAYER_IS_HOLMES) && !vm._runningProlog)
+ Journal::record(converseNum, statementNum, replyOnly);
+}
+
+} // End of namespace Tattoo
+
+} // End of namespace Sherlock
diff --git a/engines/sherlock/tattoo/tattoo_journal.h b/engines/sherlock/tattoo/tattoo_journal.h
new file mode 100644
index 0000000000..96c1c6cab4
--- /dev/null
+++ b/engines/sherlock/tattoo/tattoo_journal.h
@@ -0,0 +1,114 @@
+/* ScummVM - Graphic Adventure Engine
+*
+* ScummVM is the legal property of its developers, whose names
+* are too numerous to list here. Please refer to the COPYRIGHT
+* file distributed with this source distribution.
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License
+* as published by the Free Software Foundation; either version 2
+* of the License, or (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public 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_JOURNAL_H
+#define SHERLOCK_TATTOO_JOURNAL_H
+
+#include "sherlock/journal.h"
+#include "sherlock/image_file.h"
+
+namespace Sherlock {
+
+namespace Tattoo {
+
+enum JournalHighlight {
+ JH_NONE = -1, JH_CLOSE = 0, JH_SEARCH = 1, JH_PRINT = 2,
+ JH_SCROLL_LEFT = 3, JH_PAGE_LEFT = 4, JH_PAGE_RIGHT = 5, JH_SCROLL_RIGHT = 6, JH_THUMBNAIL = 7
+};
+
+class TattooJournal : public Journal {
+private:
+ ImageFile *_journalImages;
+ int _selector, _oldSelector;
+ bool _wait;
+ bool _exitJournal;
+ uint32 _scrollingTimer;
+ int _savedIndex, _savedSub, _savedPage;
+
+ /**
+ * Load the list of journal locations
+ */
+ void loadLocations();
+
+ /**
+ * Displays the controls used by the journal
+ * @param mode 0: Normal journal buttons, 1: Search interface
+ */
+ void drawControls(int mode);
+
+ /**
+ * Draw the journal controls used by the journal
+ */
+ void highlightJournalControls(bool slamIt);
+
+ /**
+ * Draw the journal controls used in search mode
+ */
+ void highlightSearchControls(bool slamIt);
+
+ void drawScrollBar();
+
+ /**
+ * Check for and handle any pending keyboard events
+ */
+ void handleKeyboardEvents();
+
+ /**
+ * Handle mouse presses on interface buttons
+ */
+ void handleButtons();
+
+ /**
+ * Disable the journal controls
+ */
+ void disableControls();
+
+ /**
+ * Get in a name to search through the journal for
+ */
+ int getFindName(bool printError);
+public:
+ TattooJournal(SherlockEngine *vm);
+ virtual ~TattooJournal() {}
+
+ /**
+ * Show the journal
+ */
+ void show();
+public:
+ /**
+ * Draw the journal background, frame, and interface buttons
+ */
+ virtual void drawFrame();
+
+ /**
+ * Records statements that are said, in the order which they are said. The player
+ * can then read the journal to review them
+ */
+ virtual void record(int converseNum, int statementNum, bool replyOnly = false);
+};
+
+} // End of namespace Tattoo
+
+} // End of namespace Sherlock
+
+#endif
diff --git a/engines/sherlock/tattoo/tattoo_map.cpp b/engines/sherlock/tattoo/tattoo_map.cpp
new file mode 100644
index 0000000000..4bd85bd5c0
--- /dev/null
+++ b/engines/sherlock/tattoo/tattoo_map.cpp
@@ -0,0 +1,434 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public 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_map.h"
+#include "sherlock/tattoo/tattoo_scene.h"
+#include "sherlock/tattoo/tattoo.h"
+
+namespace Sherlock {
+
+namespace Tattoo {
+
+#define MAP_NAME_COLOR 131
+#define CLOSEUP_STEPS 30
+#define SCROLL_SPEED 16
+
+/*-------------------------------------------------------------------------*/
+
+void MapEntry::clear() {
+ _iconNum = -1;
+ _description = "";
+}
+
+/*-------------------------------------------------------------------------*/
+
+TattooMap::TattooMap(SherlockEngine *vm) : Map(vm), _mapTooltip(vm) {
+ _iconImages = nullptr;
+ _bgFound = _oldBgFound = 0;
+
+ loadData();
+}
+
+int TattooMap::show() {
+ Debugger &debugger = *_vm->_debugger;
+ Events &events = *_vm->_events;
+ Music &music = *_vm->_music;
+ Resources &res = *_vm->_res;
+ TattooScene &scene = *(TattooScene *)_vm->_scene;
+ Screen &screen = *_vm->_screen;
+ int result = 0;
+
+ // Check if we need to keep track of how many times player has been to the map
+ for (uint idx = 0; idx < scene._sceneTripCounters.size(); ++idx) {
+ SceneTripEntry &entry = scene._sceneTripCounters[idx];
+
+ if (entry._sceneNumber == OVERHEAD_MAP || entry._sceneNumber == OVERHEAD_MAP2) {
+ if (--entry._numTimes == 0) {
+ _vm->setFlagsDirect(entry._flag);
+ scene._sceneTripCounters.remove_at(idx);
+ }
+ }
+ }
+
+ if (music._musicOn) {
+ // See if Holmes or Watson is the active character
+ Common::String song;
+ if (_vm->readFlags(FLAG_PLAYER_IS_HOLMES))
+ // Player is Holmes
+ song = "Cue9";
+ else if (_vm->readFlags(FLAG_ALT_MAP_MUSIC))
+ song = "Cue8";
+ else
+ song = "Cue7";
+
+ if (music.loadSong(song)) {
+ music.startSong();
+ }
+ }
+
+ screen.initPaletteFade(1364485);
+
+ // Load the custom mouse cursors for the map
+ ImageFile cursors("omouse.vgs");
+ events.setCursor(cursors[0]._frame);
+ events.warpMouse();
+
+ // Load the data for the map
+ _iconImages = new ImageFile("mapicons.vgs");
+ loadData();
+
+ // Load the palette
+ Common::SeekableReadStream *stream = res.load("map.pal");
+ stream->read(screen._cMap, PALETTE_SIZE);
+ screen.translatePalette(screen._cMap);
+ delete stream;
+
+ // 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));
+ delete map;
+
+ screen.clear();
+ screen.setPalette(screen._cMap);
+ drawMapIcons();
+
+ // 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);
+
+ // Display the built map to the screen
+ screen.slamArea(0, 0, SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT);
+
+ // Set initial scroll position
+ _targetScroll = _bigPos;
+ screen._currentScroll = Common::Point(-1, -1);
+
+ do {
+ // Allow for event processing and get the current mouse position
+ events.pollEventsAndWait();
+ events.setButtonState();
+ Common::Point mousePos = events.screenMousePos();
+
+ if (debugger._showAllLocations == LOC_REFRESH) {
+ drawMapIcons();
+ screen.slamArea(screen._currentScroll.x, screen._currentScroll.y, SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_WIDTH);
+ }
+
+ checkMapNames(true);
+
+ if (mousePos.x < (SHERLOCK_SCREEN_WIDTH / 6))
+ _targetScroll.x -= 2 * SCROLL_SPEED * (SHERLOCK_SCREEN_WIDTH / 6 - mousePos.x) / (SHERLOCK_SCREEN_WIDTH / 6);
+ if (mousePos.x > (SHERLOCK_SCREEN_WIDTH * 5 / 6))
+ _targetScroll.x += 2 * SCROLL_SPEED * (mousePos.x - (SHERLOCK_SCREEN_WIDTH * 5 / 6)) / (SHERLOCK_SCREEN_WIDTH / 6);
+ if (mousePos.y < (SHERLOCK_SCREEN_HEIGHT / 6))
+ _targetScroll.y -= 2 * SCROLL_SPEED * (SHERLOCK_SCREEN_HEIGHT / 6 - mousePos.y) / (SHERLOCK_SCREEN_HEIGHT / 6);
+ if (mousePos.y > (SHERLOCK_SCREEN_HEIGHT * 5 / 6))
+ _targetScroll.y += 2 * SCROLL_SPEED * (mousePos.y - SHERLOCK_SCREEN_HEIGHT * 5 / 6) / (SHERLOCK_SCREEN_HEIGHT / 6);
+
+ 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.y < 0)
+ _targetScroll.y = 0;
+ if ((_targetScroll.y + SHERLOCK_SCREEN_HEIGHT) > screen._backBuffer1.h())
+ _targetScroll.y = screen._backBuffer1.h() - SHERLOCK_SCREEN_HEIGHT;
+
+ // Check the keyboard
+ if (events.kbHit()) {
+ Common::KeyState keyState = events.getKey();
+
+ switch (keyState.keycode) {
+ case Common::KEYCODE_HOME:
+ _targetScroll.x = 0;
+ _targetScroll.y = 0;
+ break;
+
+ case Common::KEYCODE_END:
+ _targetScroll.x = screen._backBuffer1.w() - SHERLOCK_SCREEN_WIDTH;
+ _targetScroll.y = screen._backBuffer1.h() - SHERLOCK_SCREEN_HEIGHT;
+ break;
+
+ case Common::KEYCODE_PAGEUP:
+ _targetScroll.y -= SHERLOCK_SCREEN_HEIGHT;
+ if (_targetScroll.y < 0)
+ _targetScroll.y = 0;
+ break;
+
+ 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;
+ break;
+
+ case Common::KEYCODE_SPACE:
+ events._pressed = false;
+ events._oldButtons = 0;
+ events._released = true;
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ // Handle any scrolling of the map
+ if (screen._currentScroll != _targetScroll) {
+ // If there is a Text description being displayed, restore the area under it
+ _mapTooltip.erase();
+
+ screen._currentScroll = _targetScroll;
+
+ checkMapNames(false);
+ screen.slamArea(_targetScroll.x, _targetScroll.y, SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT);
+ }
+
+ // Handling if a location has been clicked on
+ if (events._released && _bgFound != -1) {
+ // If there is a Text description being displayed, restore the area under it
+ _mapTooltip.erase();
+
+ // Save the current scroll position on the map
+ _bigPos = screen._currentScroll;
+
+ showCloseUp(_bgFound);
+ result = _bgFound + 1;
+ }
+ } while (!result && !_vm->shouldQuit());
+
+ music.stopMusic();
+ events.clearEvents();
+ _mapTooltip.banishWindow();
+
+ // 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);
+
+ return result;
+}
+
+void TattooMap::loadData() {
+ Resources &res = *_vm->_res;
+ char c;
+
+ Common::SeekableReadStream *stream = res.load("map.txt");
+
+ _data.resize(100);
+ for (uint idx = 0; idx < _data.size(); ++idx)
+ _data[idx].clear();
+
+ do
+ {
+ // Find the start of the number
+ do {
+ c = stream->readByte();
+ if (stream->pos() >= stream->size())
+ break;
+ } while (c < '0' || c > '9');
+ if (stream->pos() >= stream->size())
+ break;
+
+ // Get the scene number
+ Common::String locStr;
+ locStr += c;
+ while ((c = stream->readByte()) != '.')
+ locStr += c;
+ MapEntry &mapEntry = _data[atoi(locStr.c_str()) - 1];
+
+ // Get the location name
+ while (stream->readByte() != '"')
+ ;
+
+ while ((c = stream->readByte()) != '"')
+ mapEntry._description += c;
+
+ // Find the ( specifying the (X,Y) position of the Icon
+ while (stream->readByte() != '(')
+ ;
+
+ // Get the X Position of the icon
+ Common::String numStr;
+ while ((c = stream->readByte()) != ',')
+ numStr += c;
+ mapEntry.x = atoi(numStr.c_str());
+
+ // Get the Y position of the icon
+ numStr = "";
+ while ((c = stream->readByte()) != ')')
+ numStr += c;
+ mapEntry.y = atoi(numStr.c_str());
+
+ // Find and get the location's icon number
+ while (stream->readByte() != '#')
+ ;
+
+ Common::String iconStr;
+ while (stream->pos() < stream->size() && (c = stream->readByte()) != '\r')
+ iconStr += c;
+
+ mapEntry._iconNum = atoi(iconStr.c_str()) - 1;
+ } while (stream->pos() < stream->size());
+
+ delete stream;
+}
+
+void TattooMap::drawMapIcons() {
+ Debugger &debugger = *_vm->_debugger;
+ Screen &screen = *_vm->_screen;
+
+ for (uint idx = 0; idx < _data.size(); ++idx) {
+ if (debugger._showAllLocations != LOC_DISABLED)
+ _vm->setFlagsDirect(idx + 1);
+
+ 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,
+ mapEntry.y - img._height / 2));
+ }
+ }
+
+ if (debugger._showAllLocations == LOC_REFRESH)
+ debugger._showAllLocations = LOC_ALL;
+}
+
+void TattooMap::checkMapNames(bool slamIt) {
+ Events &events = *_vm->_events;
+ Common::Point mapPos = events.mousePos();
+
+ // See if the mouse is pointing at any of the map locations
+ _bgFound = -1;
+
+ for (uint idx = 0; idx < _data.size(); ++idx) {
+ if (_data[idx]._iconNum != -1 && _vm->readFlags(idx + 1)) {
+ MapEntry &mapEntry = _data[idx];
+ ImageFrame &img = (*_iconImages)[mapEntry._iconNum];
+ Common::Rect r(mapEntry.x - img._width / 2, mapEntry.y - img._height / 2,
+ mapEntry.x + img._width / 2, mapEntry.y + img._height / 2);
+
+ if (r.contains(mapPos)) {
+ _bgFound = idx;
+ break;
+ }
+ }
+ }
+
+ // Handle updating the tooltip
+ if (_bgFound != _oldBgFound) {
+ if (_bgFound == -1) {
+ _mapTooltip.setText("");
+ } else {
+ const Common::String &desc = _data[_bgFound]._description;
+ _mapTooltip.setText(desc);
+ }
+
+ _oldBgFound = _bgFound;
+ }
+
+ _mapTooltip.handleEvents();
+ if (slamIt)
+ _mapTooltip.draw();
+}
+
+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()));
+
+ if (!r.isEmpty())
+ screen._backBuffer1.blitFrom(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);
+
+ // Get the closeup images
+ Common::String fname = Common::String::format("res%02d.vgs", closeUpNum + 1);
+ ImageFile pic(fname);
+
+ Point32 closeUp(_data[closeUpNum].x * 100, _data[closeUpNum].y * 100);
+ Point32 delta((SHERLOCK_SCREEN_WIDTH / 2 - closeUp.x / 100) * 100 / CLOSEUP_STEPS,
+ (SHERLOCK_SCREEN_HEIGHT / 2 - closeUp.y / 100) * 100 / CLOSEUP_STEPS);
+ Common::Rect oldBounds(closeUp.x / 100, closeUp.y / 100, closeUp.x / 100 + 1, closeUp.y / 100 + 1);
+ int size = 64;
+ int n = 256;
+ int deltaVal = 512;
+ bool minimize = false;
+ int scaleVal, newSize;
+
+ do {
+ scaleVal = n;
+ newSize = pic[0].sDrawXSize(n);
+
+ if (newSize > size) {
+ if (minimize)
+ deltaVal /= 2;
+ n += deltaVal;
+ } else {
+ minimize = true;
+ deltaVal /= 2;
+ n -= deltaVal;
+ if (n < 1)
+ n = 1;
+ }
+ } while (deltaVal && size != newSize);
+
+ int deltaScale = (SCALE_THRESHOLD - scaleVal) / CLOSEUP_STEPS;
+
+ 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);
+
+ restoreArea(oldBounds);
+ screen._backBuffer1.transBlitFrom(pic[0], pt, false, 0, scaleVal);
+
+ screen.slamRect(oldBounds);
+ screen.slamArea(pt.x, pt.y, picSize.x, picSize.y);
+
+ oldBounds = Common::Rect(pt.x, pt.y, pt.x + picSize.x + 1, pt.y + picSize.y + 1);
+ closeUp += delta;
+ scaleVal += deltaScale;
+
+ events.wait(1);
+ }
+
+ // 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);
+
+ restoreArea(oldBounds);
+ screen._backBuffer1.transBlitFrom(pic[0], Common::Point(r.left, r.top));
+ screen.slamRect(oldBounds);
+ screen.slamRect(r);
+ events.wait(60);
+}
+
+} // End of namespace Tattoo
+
+} // End of namespace Sherlock
diff --git a/engines/sherlock/tattoo/tattoo_map.h b/engines/sherlock/tattoo/tattoo_map.h
new file mode 100644
index 0000000000..1c7173bdb0
--- /dev/null
+++ b/engines/sherlock/tattoo/tattoo_map.h
@@ -0,0 +1,93 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public 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_MAP_H
+#define SHERLOCK_TATTOO_MAP_H
+
+#include "common/scummsys.h"
+#include "sherlock/map.h"
+#include "sherlock/resources.h"
+#include "sherlock/surface.h"
+#include "sherlock/tattoo/widget_tooltip.h"
+
+namespace Sherlock {
+
+class SherlockEngine;
+
+namespace Tattoo {
+
+struct MapEntry : Common::Point {
+ int _iconNum;
+ Common::String _description;
+
+ MapEntry() : Common::Point(), _iconNum(-1) {}
+ MapEntry(int posX, int posY, int iconNum) : Common::Point(posX, posY), _iconNum(iconNum) {}
+ void clear();
+};
+
+class TattooMap : public Map {
+private:
+ Common::Array<MapEntry> _data;
+ ImageFile *_iconImages;
+ int _bgFound, _oldBgFound;
+ WidgetMapTooltip _mapTooltip;
+ Common::Point _targetScroll;
+
+ /**
+ * Load data needed for the map
+ */
+ void loadData();
+
+ /**
+ * Draws all available location icons onto the back buffer
+ */
+ void drawMapIcons();
+
+ /**
+ * Draws the location names of whatever the mouse moves over on the map
+ */
+ void checkMapNames(bool slamIt);
+
+ /**
+ * Restores an area of the map background
+ */
+ void restoreArea(const Common::Rect &bounds);
+
+ /**
+ * This will load a specified close up and zoom it up to the middle of the screen
+ */
+ void showCloseUp(int closeUpNum);
+public:
+ TattooMap(SherlockEngine *vm);
+ virtual ~TattooMap() {}
+
+ /**
+ * Show the map
+ */
+ virtual int show();
+};
+
+} // End of namespace Tattoo
+
+} // End of namespace Sherlock
+
+#endif
diff --git a/engines/sherlock/tattoo/tattoo_people.cpp b/engines/sherlock/tattoo/tattoo_people.cpp
new file mode 100644
index 0000000000..e3e957e35c
--- /dev/null
+++ b/engines/sherlock/tattoo/tattoo_people.cpp
@@ -0,0 +1,1503 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public 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_people.h"
+#include "sherlock/tattoo/tattoo_scene.h"
+#include "sherlock/tattoo/tattoo_talk.h"
+#include "sherlock/tattoo/tattoo_user_interface.h"
+#include "sherlock/tattoo/tattoo.h"
+
+namespace Sherlock {
+
+namespace Tattoo {
+
+#define FACING_PLAYER 16
+#define NUM_ADJUSTED_WALKS 21
+#define CHARACTERS_INDEX 256
+
+struct AdjustWalk {
+ char _vgsName[9];
+ int _xAdjust;
+ int _flipXAdjust;
+ int _yAdjust;
+} ;
+
+static const AdjustWalk ADJUST_WALKS[NUM_ADJUSTED_WALKS] = {
+ { "TUPRIGHT", -7, -19, 6 },
+ { "TRIGHT", 8, -14, 0 },
+ { "TDOWNRG", 14, -12, 0 },
+ { "TWUPRIGH", 12, 4, 2 },
+ { "TWRIGHT", 31, -14, 0 },
+ { "TWDOWNRG", 6, -24, 0 },
+ { "HTUPRIGH", 2, -20, 0 },
+ { "HTRIGHT", 28, -20, 0 },
+ { "HTDOWNRG", 8, -2, 0 },
+ { "GTUPRIGH", 4, -12, 0 },
+ { "GTRIGHT", 12, -16, 0 },
+ { "GTDOWNRG", 10, -18, 0 },
+ { "JTUPRIGH", 8, -10, 0 },
+ { "JTRIGHT", 22, -6, 0 },
+ { "JTDOWNRG", 4, -20, 0 },
+ { "CTUPRIGH", 10, 0, 0 },
+ { "CTRIGHT", 26, -22, 0 },
+ { "CTDOWNRI", 16, 4, 0 },
+ { "ITUPRIGH", 0, 0, 0 },
+ { "ITRIGHT", 20, 0, 0 },
+ { "ITDOWNRG", 8, 0, 0 }
+};
+
+static const int WALK_SPEED_X[99] = {
+ 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 98, 90, 90, 90, 90, 90, 91, 90, 90,
+ 90, 90,100, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90,100, 90,
+ 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90,103, 90, 90, 90, 90, 90, 90, 90,
+ 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90,
+ 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90
+};
+
+static const int WALK_SPEED_Y[99] = {
+ 28, 28, 28, 28, 28, 28, 28, 28, 28, 32, 32, 32, 28, 28, 28, 28, 28, 26, 28, 28,
+ 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
+ 32, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 31, 28, 28, 28, 28, 28, 28, 28,
+ 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
+ 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28
+};
+
+static const int WALK_SPEED_DIAG_X[99] = {
+ 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50,
+ 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50,
+ 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50,
+ 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 90, 50, 50, 50, 50, 50, 50, 50, 50, 50,
+ 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50
+};
+
+/*----------------------------------------------------------------*/
+
+SavedNPCPath::SavedNPCPath() {
+ Common::fill(&_path[0], &_path[MAX_NPC_PATH], 0);
+ _npcIndex = 0;
+ _npcPause = 0;
+ _npcFacing = 0;
+ _lookHolmes = false;
+}
+
+SavedNPCPath::SavedNPCPath(byte path[MAX_NPC_PATH], int npcIndex, int npcPause, const Point32 &position,
+ int npcFacing, bool lookHolmes) : _npcIndex(npcIndex), _npcPause(npcPause), _position(position),
+ _npcFacing(npcFacing), _lookHolmes(lookHolmes) {
+ Common::copy(&path[0], &path[MAX_NPC_PATH], &_path[0]);
+}
+
+/*----------------------------------------------------------------*/
+
+TattooPerson::TattooPerson() : Person() {
+ Common::fill(&_npcPath[0], &_npcPath[MAX_NPC_PATH], 0);
+ _tempX = _tempScaleVal = 0;
+ _npcIndex = 0;
+ _npcMoved = false;
+ _npcFacing = -1;
+ _resetNPCPath = true;
+ _savedNpcSequence = 0;
+ _savedNpcFrame = 0;
+ _updateNPCPath = true;
+ _npcPause = 0;
+ _lookHolmes = false;
+}
+
+void TattooPerson::freeAltGraphics() {
+ if (_altImages != nullptr) {
+ delete _altImages;
+ _altImages = nullptr;
+ }
+
+ _altSeq = 0;
+}
+
+void TattooPerson::adjustSprite() {
+ People &people = *_vm->_people;
+ TattooScene &scene = *(TattooScene *)_vm->_scene;
+ TattooUserInterface &ui = *(TattooUserInterface *)_vm->_ui;
+
+ if (_type == INVALID)
+ return;
+
+ if (_type == CHARACTER && _status) {
+ // Sprite waiting to move, so restart walk
+ _walkCount = _status;
+ _status = 0;
+
+ _walkDest = _walkTo.front();
+ setWalking();
+ } else if (_type == CHARACTER && _walkCount) {
+ if (_walkCount > 10) {
+ _walkDest = _nextDest;
+ setWalking();
+ }
+
+ _position += _delta;
+ if (_walkCount)
+ --_walkCount;
+
+ if (!_walkCount) {
+ // If there are remaining points to walk, move to the next one
+ if (!_walkTo.empty()) {
+ _walkDest = _walkTo.pop();
+ setWalking();
+ } else {
+ gotoStand();
+ }
+ }
+ }
+
+ if (_type != CHARACTER) {
+ if (_position.y > SHERLOCK_SCREEN_HEIGHT)
+ _position.y = SHERLOCK_SCREEN_HEIGHT;
+
+ if (_position.y < UPPER_LIMIT)
+ _position.y = UPPER_LIMIT;
+
+ if (_position.x < LEFT_LIMIT)
+ _position.x = LEFT_LIMIT;
+
+ if (_position.x > RIGHT_LIMIT)
+ _position.x = RIGHT_LIMIT;
+ }
+
+ int frameNum = _frameNumber;
+ if (frameNum == -1)
+ frameNum = 0;
+ int idx = _walkSequences[_sequenceNumber][frameNum];
+ if (idx > _maxFrames)
+ idx = 1;
+
+ // Set the image frame
+ if (_altSeq)
+ _imageFrame = &(*_altImages)[idx - 1];
+ else
+ _imageFrame = &(*_images)[idx - 1];
+
+ // See if the player has come to a stop after clicking on an Arrow zone to leave the scene.
+ // If so, this will set up the exit information for the scene transition
+ if (!_walkCount && ui._exitZone != -1 && scene._walkedInScene && scene._goToScene == -1 &&
+ !_description.compareToIgnoreCase(people[HOLMES]._description)) {
+ Exit &exit = scene._exits[ui._exitZone];
+ scene._goToScene = exit._scene;
+
+ if (exit._newPosition.x != 0) {
+ people._savedPos = exit._newPosition;
+
+ if (people._savedPos._facing > 100 && people._savedPos.x < 1)
+ people._savedPos.x = 100;
+ }
+ }
+}
+
+void TattooPerson::gotoStand() {
+ TattooPeople &people = *(TattooPeople *)_vm->_people;
+
+ // If the misc field is set, then we're running a special talk sequence, so don't interrupt it.
+ if (_misc)
+ return;
+
+ _walkTo.clear();
+ _walkCount = 0;
+ int oldFacing = _sequenceNumber;
+
+ // If the person was talking or listening, just return it to the standing sequence
+ // in the direction they were pointing
+ if (_sequenceNumber >= TALK_UPRIGHT && _sequenceNumber <= LISTEN_UPLEFT) {
+ switch (_sequenceNumber) {
+ case TALK_UPRIGHT:
+ case LISTEN_UPRIGHT:
+ _sequenceNumber = STOP_UPRIGHT;
+ break;
+ case TALK_RIGHT:
+ case LISTEN_RIGHT:
+ _sequenceNumber = STOP_RIGHT;
+ break;
+ case TALK_DOWNRIGHT:
+ case LISTEN_DOWNRIGHT:
+ _sequenceNumber = STOP_DOWNRIGHT;
+ break;
+ case TALK_DOWNLEFT:
+ case LISTEN_DOWNLEFT:
+ _sequenceNumber = STOP_DOWNLEFT;
+ break;
+ case TALK_LEFT:
+ case LISTEN_LEFT:
+ _sequenceNumber = STOP_LEFT;
+ break;
+ case TALK_UPLEFT:
+ case LISTEN_UPLEFT:
+ _sequenceNumber = STOP_UPLEFT;
+ break;
+ default:
+ break;
+ }
+
+ if (_seqTo) {
+ // Reset to previous value
+ _walkSequences[oldFacing]._sequences[_frameNumber] = _seqTo;
+ _seqTo = 0;
+ }
+
+ // Set the Frame number to the last frame so we don't move
+ _frameNumber = 0;
+
+ checkWalkGraphics();
+
+ _oldWalkSequence = -1;
+ people._allowWalkAbort = true;
+ return;
+ }
+
+ // If the sprite that is stopping is an NPC and he is supposed to face a certain direction
+ // when he stops, set that direction here
+ int npc = -1;
+ for (int idx = 1; idx < MAX_CHARACTERS; ++idx) {
+ if (_imageFrame == people[idx]._imageFrame)
+ npc = idx;
+ }
+
+ if (npc != -1 && people[npc]._npcFacing != -1) {
+ if (people[npc]._npcFacing == FACING_PLAYER) {
+ // See where Holmes is with respect to the NPC (x coords)
+ if (people[HOLMES]._position.x < people[npc]._position.x)
+ people[npc]._npcFacing = STOP_LEFT;
+ else
+ people[npc]._npcFacing = STOP_RIGHT;
+
+ // See where Holmes is with respect to the NPC (y coords)
+ if (people[HOLMES]._position.y < people[npc]._position.y - (10 * FIXED_INT_MULTIPLIER)) {
+ // Holmes is above the NPC so reset the facing to the diagonal ups
+ if (people[npc]._npcFacing == STOP_RIGHT)
+ people[npc]._npcFacing = STOP_UPRIGHT;
+ else
+ people[npc]._npcFacing = STOP_UPLEFT;
+ } else {
+ if (people[HOLMES]._position.y > people[npc]._position.y + (10 * FIXED_INT_MULTIPLIER)) {
+ // Holmes is below the NPC so reset the facing to the diagonal downs
+ if (people[npc]._npcFacing == STOP_RIGHT)
+ people[npc]._npcFacing = STOP_DOWNRIGHT;
+ else
+ people[npc]._npcFacing = STOP_DOWNLEFT;
+ }
+ }
+ }
+
+ _sequenceNumber = people[npc]._npcFacing;
+ } else {
+ switch (_sequenceNumber) {
+ case WALK_UP: _sequenceNumber = STOP_UP; break;
+ case WALK_UPRIGHT: _sequenceNumber = STOP_UPRIGHT; break;
+ case WALK_RIGHT: _sequenceNumber = STOP_RIGHT; break;
+ case WALK_DOWNRIGHT: _sequenceNumber = STOP_DOWNRIGHT; break;
+ case WALK_DOWN: _sequenceNumber = STOP_DOWN; break;
+ case WALK_DOWNLEFT: _sequenceNumber = STOP_DOWNLEFT;break;
+ case WALK_LEFT: _sequenceNumber = STOP_LEFT; break;
+ case WALK_UPLEFT: _sequenceNumber = STOP_UPLEFT; break;
+ }
+ }
+
+ // Only restart the frame number at 0 if the new sequence is different from the last sequence
+ // so we don't let Holmes repeat standing.
+ if (_oldWalkSequence != -1) {
+ if (_seqTo) {
+ // Reset to previous value
+ _walkSequences[oldFacing]._sequences[_frameNumber] = _seqTo;
+ _seqTo = 0;
+ }
+
+ _frameNumber = 0;
+ }
+
+ checkWalkGraphics();
+
+ _oldWalkSequence = -1;
+ people._allowWalkAbort = true;
+}
+
+void TattooPerson::setWalking() {
+ TattooScene &scene = *(TattooScene *)_vm->_scene;
+ int oldDirection, oldFrame;
+ Common::Point delta;
+ _nextDest = _walkDest;
+
+ // Flag that player has now walked in the scene
+ scene._walkedInScene = true;
+
+ // Stop any previous walking, since a new dest is being set
+ _walkCount = 0;
+ oldDirection = _sequenceNumber;
+ oldFrame = _frameNumber;
+
+ // Set speed to use horizontal and vertical movement
+ int scaleVal = scene.getScaleVal(_position);
+ Common::Point speed(MAX(WALK_SPEED_X[scene._currentScene - 1] * SCALE_THRESHOLD / scaleVal, 2),
+ MAX(WALK_SPEED_Y[scene._currentScene - 1] * SCALE_THRESHOLD / scaleVal, 2));
+ Common::Point diagSpeed(MAX(WALK_SPEED_DIAG_X[scene._currentScene - 1] * SCALE_THRESHOLD / scaleVal, 2),
+ MAX((WALK_SPEED_Y[scene._currentScene - 1] - 2) * SCALE_THRESHOLD / scaleVal, 2));
+
+ // If the player is already close to the given destination that no walking is needed,
+ // move to the next straight line segment in the overall walking route, if there is one
+ for (;;) {
+ if (_centerWalk || !_walkTo.empty()) {
+ // Since we want the player to be centered on the ultimate destination, and the player
+ // is drawn from the left side, move the cursor half the width of the player to center it
+ delta = Common::Point(_position.x / FIXED_INT_MULTIPLIER - _walkDest.x,
+ _position.y / FIXED_INT_MULTIPLIER - _walkDest.y);
+
+ int dir;
+ if (ABS(delta.x) > ABS(delta.y))
+ dir = (delta.x < 0) ? WALK_LEFT : WALK_RIGHT;
+ else
+ dir = (delta.y < 0) ? WALK_UP : WALK_DOWN;
+
+ scaleVal = scene.getScaleVal(Point32(_walkDest.x * FIXED_INT_MULTIPLIER,
+ _walkDest.y * FIXED_INT_MULTIPLIER));
+ _walkDest.x -= _stopFrames[dir]->sDrawXSize(scaleVal) / 2;
+ }
+
+ delta = Common::Point(
+ ABS(_position.x / FIXED_INT_MULTIPLIER - _walkDest.x),
+ ABS(_position.y / FIXED_INT_MULTIPLIER - _walkDest.y)
+ );
+
+ // If we're ready to move a sufficient distance, that's it. Otherwise,
+ // move onto the next portion of the walk path, if there is one
+ if ((delta.x > 3 || delta.y > 0) || _walkTo.empty())
+ break;
+
+ // Pop next walk segment off the walk route stack
+ _walkDest = _walkTo.pop();
+ }
+
+ // If a sufficient move is being done, then start the move
+ if (delta.x > 3 || delta.y) {
+ // See whether the major movement is horizontal or vertical
+ if (delta.x >= delta.y) {
+ // Set the initial frame sequence for the left and right, as well
+ // as setting the delta x depending on direction
+ if (_walkDest.x < (_position.x / FIXED_INT_MULTIPLIER)) {
+ _sequenceNumber = WALK_LEFT;
+ _delta.x = speed.x * -(FIXED_INT_MULTIPLIER / 10);
+ } else {
+ _sequenceNumber = WALK_RIGHT;
+ _delta.x = speed.x * (FIXED_INT_MULTIPLIER / 10);
+ }
+
+ // See if the x delta is too small to be divided by the speed, since
+ // this would cause a divide by zero error
+ if ((delta.x * 10) >= speed.x) {
+ // Det the delta y
+ _delta.y = (delta.y * FIXED_INT_MULTIPLIER) / ((delta.x * 10) / speed.x);
+ if (_walkDest.y < (_position.y / FIXED_INT_MULTIPLIER))
+ _delta.y = -_delta.y;
+
+ // Set how many times we should add the delta to the player's position
+ _walkCount = (delta.x * 10) / speed.x;
+ } else {
+ // The delta x was less than the speed (ie. we're really close to
+ // the destination). So set delta to 0 so the player won't move
+ _delta = Point32(0, 0);
+ _position = Point32(_walkDest.x * FIXED_INT_MULTIPLIER, _walkDest.y * FIXED_INT_MULTIPLIER);
+
+ _walkCount = 1;
+ }
+
+ // See if the sequence needs to be changed for diagonal walking
+ if (_delta.y > 1500) {
+ if (_sequenceNumber == WALK_LEFT || _sequenceNumber == WALK_RIGHT) {
+ _delta.x = _delta.x / speed.x * diagSpeed.x;
+ _delta.y = (delta.y * FIXED_INT_MULTIPLIER) / (delta.x * 10 / diagSpeed.x);
+
+ _walkCount = delta.x * 10 / diagSpeed.x;
+ }
+
+ switch (_sequenceNumber) {
+ case WALK_LEFT:
+ _sequenceNumber = WALK_DOWNLEFT;
+ break;
+ case WALK_RIGHT:
+ _sequenceNumber = WALK_DOWNRIGHT;
+ break;
+ }
+ } else if (_delta.y < -1500) {
+ if (_sequenceNumber == WALK_LEFT || _sequenceNumber == WALK_RIGHT) {
+ _delta.x = _delta.x / speed.x * diagSpeed.x;
+ _delta.y = -1 * (delta.y * FIXED_INT_MULTIPLIER) / (delta.x * 10 / diagSpeed.x);
+
+ _walkCount = (delta.x * 10) / diagSpeed.x;
+ }
+
+ switch (_sequenceNumber) {
+ case WALK_LEFT:
+ _sequenceNumber = WALK_UPLEFT;
+ break;
+ case WALK_RIGHT:
+ _sequenceNumber = WALK_UPRIGHT;
+ break;
+ }
+ }
+ } else {
+ // Major movement is vertical, so set the sequence for up and down,
+ // and set the delta Y depending on the direction
+ if (_walkDest.y < (_position.y / FIXED_INT_MULTIPLIER)) {
+ _sequenceNumber = WALK_UP;
+ _delta.y = speed.y * -(FIXED_INT_MULTIPLIER / 10);
+ } else {
+ speed.y = diagSpeed.y;
+ _sequenceNumber = WALK_DOWN;
+ _delta.y = speed.y * (FIXED_INT_MULTIPLIER / 10);
+ }
+
+ // Set the delta x
+ if (delta.y * 10 / speed.y)
+ _delta.x = (delta.x * FIXED_INT_MULTIPLIER) / (delta.y * 10 / speed.y);
+ else
+ _delta.x = (delta.x * FIXED_INT_MULTIPLIER) / delta.y;
+
+ if (_walkDest.x < _position.y / FIXED_INT_MULTIPLIER)
+ _delta.x = -_delta.x;
+
+ // Set how many times we should add the delta's to the players position
+ if (delta.y * 10 / speed.y)
+ _walkCount = delta.y * 10 / speed.y;
+ else
+ _walkCount = delta.y;
+ }
+ }
+
+ // See if the new walk sequence is the same as the old. If it's a new one,
+ // we need to reset the frame number to zero so its animation starts at
+ // its beginning. Otherwise, if it's the same sequence, we can leave it
+ // as is, so it keeps the animation going at wherever it was up to
+ if (_sequenceNumber != _oldWalkSequence) {
+ if (_seqTo) {
+ // Reset to previous value
+ _walkSequences[oldDirection]._sequences[_frameNumber] = _seqTo;
+ _seqTo = 0;
+ }
+ _frameNumber = 0;
+ }
+
+ checkWalkGraphics();
+ _oldWalkSequence = _sequenceNumber;
+
+ if (!_walkCount && _walkTo.empty())
+ gotoStand();
+
+ // If the sequence is the same as when we started, then Holmes was standing still and we're trying
+ // to re-stand him, so reset Holmes' rame to the old frame number from before it was reset to 0
+ if (_sequenceNumber == oldDirection)
+ _frameNumber = oldFrame;
+}
+
+void TattooPerson::walkToCoords(const Point32 &destPos, int destDir) {
+ TattooEngine &vm = *(TattooEngine *)_vm;
+ Events &events = *_vm->_events;
+ TattooPeople &people = *(TattooPeople *)_vm->_people;
+ TattooScene &scene = *(TattooScene *)_vm->_scene;
+ Talk &talk = *_vm->_talk;
+
+ CursorId oldCursor = events.getCursor();
+ events.setCursor(WAIT);
+
+ _walkDest = Common::Point(destPos.x / FIXED_INT_MULTIPLIER, destPos.y / FIXED_INT_MULTIPLIER);
+
+ bool isHolmes = this == &people[HOLMES];
+ if (isHolmes) {
+ people._allowWalkAbort = true;
+ } else {
+ // Clear the path Variables
+ _npcIndex = _npcPause = 0;
+ Common::fill(_npcPath, _npcPath + 100, 0);
+ _npcFacing = destDir;
+ }
+
+ _centerWalk = false;
+
+ // Only move the person if they're going an appreciable distance
+ if (ABS(_walkDest.x - (_position.x / FIXED_INT_MULTIPLIER)) > 8 ||
+ ABS(_walkDest.y - (_position.y / FIXED_INT_MULTIPLIER)) > 4) {
+ goAllTheWay();
+
+ do {
+ // Keep doing animations whilst walk is in progress
+ events.wait(1);
+ scene.doBgAnim();
+
+ if (events.kbHit()) {
+ Common::KeyState keyState = events.getKey();
+
+ if (keyState.keycode == Common::KEYCODE_ESCAPE && vm._runningProlog) {
+ vm.setFlags(-76);
+ vm.setFlags(396);
+ scene._goToScene = 1;
+ talk._talkToAbort = true;
+ }
+ }
+ } while (!_vm->shouldQuit() && _walkCount && !talk._talkToAbort);
+ }
+
+ _centerWalk = true;
+ if (!isHolmes)
+ _updateNPCPath = true;
+
+ if (!talk._talkToAbort) {
+ // put character exactly on right spot
+ _position = destPos;
+
+ if (_sequenceNumber != destDir) {
+ // Facing character to correct ending direction
+ _sequenceNumber = destDir;
+ gotoStand();
+ }
+
+ if (!isHolmes)
+ _updateNPCPath = false;
+
+ // Secondary walking wait loop
+ bool done = false;
+ while (!done && !_vm->shouldQuit()) {
+ events.wait(1);
+ scene.doBgAnim();
+
+ // See if we're past the initial goto stand sequence
+ for (int idx = 0; idx < _frameNumber; ++idx) {
+ if (_walkSequences[_sequenceNumber][idx] == 0) {
+ done = true;
+ break;
+ }
+ }
+
+ if (events.kbHit()) {
+ Common::KeyState keyState = events.getKey();
+
+ if (keyState.keycode == Common::KEYCODE_ESCAPE && vm._runningProlog) {
+ vm.setFlags(-76);
+ vm.setFlags(396);
+ scene._goToScene = 1;
+ talk._talkToAbort = true;
+ }
+ }
+ }
+
+ if (!isHolmes)
+ _updateNPCPath = true;
+
+ if (!talk._talkToAbort)
+ events.setCursor(oldCursor);
+ }
+}
+
+void TattooPerson::clearNPC() {
+ Common::fill(&_npcPath[0], &_npcPath[MAX_NPC_PATH], 0);
+ _npcIndex = 0;
+ _pathStack.clear();
+ _npcName = "";
+}
+
+void TattooPerson::updateNPC() {
+ People &people = *_vm->_people;
+ Talk &talk = *_vm->_talk;
+
+ // If the NPC isn't on, or it's in Talk or Listen Mode, then return without doing anything
+ if (_type != CHARACTER || _sequenceNumber >= TALK_UPRIGHT)
+ return;
+
+ // If the NPC is paused, just decrement his pause counter and exit
+ if (_npcPause) {
+ // Decrement counter
+ --_npcPause;
+
+ // Now see if we need to update the NPC's frame sequence so that he faces Holmes
+ if (_lookHolmes) {
+ // See where Holmes is with respect to the NPC (x coordinate)
+ _npcFacing = (people[HOLMES]._position.x < _position.x) ? STOP_LEFT : STOP_RIGHT;
+
+ // See where Holmes is with respect to the NPC (y coordinate)
+ if (people[HOLMES]._position.y < (_position.y - 10 * FIXED_INT_MULTIPLIER)) {
+ // Holmes is above the NPC so reset the facing to a diagonal up
+ _npcFacing = (_npcFacing == STOP_RIGHT) ? STOP_UPRIGHT : STOP_UPLEFT;
+ } else if (people[HOLMES]._position.y > (_position.y + 10 * FIXED_INT_MULTIPLIER)) {
+ // Holmes is below the NPC so reset the facing to a diagonal down
+ _npcFacing = (_npcFacing == STOP_RIGHT) ? STOP_DOWNRIGHT : STOP_DOWNLEFT;
+ }
+
+ // See if we need to set the old_walk_sequence so the NPC will put his arms
+ // up if he turns another way
+ if (_sequenceNumber != _npcFacing)
+ _oldWalkSequence = _sequenceNumber;
+
+ gotoStand();
+ }
+ } else {
+ // Reset the look flag so the NPC won't face Holmes anymore
+ _lookHolmes = false;
+
+ // See if the NPC is stopped or not. Don't do anything if he's moving
+ if (!_walkCount) {
+ // If there is no new command, reset the path back to the beginning
+ if (!_npcPath[_npcIndex])
+ _npcIndex = 0;
+
+ // The NPC is stopped and any pause he was doing is done. We can now see what
+ // the next command in the NPC path is.
+
+ // Scan Past any NPC Path Labels since they do nothing except mark places for If's and Goto's
+ while (_npcPath[_npcIndex] == NPCPATH_PATH_LABEL)
+ _npcIndex += 2;
+
+ if (_npcPath[_npcIndex]) {
+ _npcFacing = -1;
+
+ switch (_npcPath[_npcIndex]) {
+ case NPCPATH_SET_DEST: {
+ // Set the NPC's new destination
+ int xp = (_npcPath[_npcIndex + 1] - 1) * 256 + _npcPath[_npcIndex + 2] - 1;
+ if (xp > 16384)
+ xp = -1 * (xp - 16384);
+ _walkDest.x = xp;
+ _walkDest.y = (_npcPath[_npcIndex + 3] - 1) * 256 + _npcPath[_npcIndex + 4] - 1;
+ _npcFacing = _npcPath[_npcIndex + 5] - 1;
+
+ goAllTheWay();
+ _npcIndex += 6;
+ break;
+ }
+
+ case NPCPATH_PAUSE:
+ // Set the NPC to pause where he is
+ _npcPause = (_npcPath[_npcIndex + 1] - 1) * 256 + _npcPath[_npcIndex + 2] - 1;
+ _npcIndex += 3;
+ break;
+
+ case NPCPATH_SET_TALK_FILE: {
+ // Set the NPC's Talk File to use if Holmes talks to them
+ ++_npcIndex;
+
+ _npcName = "";
+ for (int idx = 0; idx < 8; ++idx) {
+ if (_npcPath[_npcIndex + idx] != '~')
+ _npcName += _npcPath[_npcIndex + idx];
+ else
+ break;
+ }
+
+ _npcIndex += 8;
+ break;
+ }
+
+ case NPCPATH_CALL_TALK_FILE: {
+ // Call a Talk File
+ ++_npcIndex;
+
+ Common::String name;
+ for (int idx = 0; idx < 8; ++idx) {
+ if (_npcPath[_npcIndex + idx] != '~')
+ name += _npcPath[_npcIndex + idx];
+ else
+ break;
+ }
+
+ _npcIndex += 8;
+ talk.talkTo(name);
+ break;
+ }
+
+ case NPCPATH_TAKE_NOTES:
+ // Set the NPC to Pause where he is and set his frame sequences
+ // so he takes notes while he's paused
+ _npcPause = (_npcPath[_npcIndex + 1] - 1) * 256 + _npcPath[_npcIndex + 2] - 1;
+ _npcIndex += 3;
+ break;
+
+ case NPCPATH_FACE_HOLMES:
+ // Set the NPC to Pause where he is and set his look flag so he will always face Holmes
+ // while he is paused
+ _npcPause = (_npcPath[_npcIndex + 1] - 1) * 256 + _npcPath[_npcIndex + 2] - 1;
+ _lookHolmes = true;
+ _npcIndex += 3;
+ break;
+
+ //case NPCPATH_PATH_LABEL: // No implementation needed here
+
+ case NPCPATH_GOTO_LABEL: {
+ // Goto NPC Path Label
+ int label = _npcPath[_npcIndex + 1];
+ _npcIndex = 0;
+
+ // Scan through NPC path data to find the label
+ bool found = false;
+ while (!found) {
+ switch (_npcPath[_npcIndex]) {
+ case NPCPATH_SET_DEST:
+ _npcIndex += 6;
+ break;
+ case NPCPATH_PAUSE:
+ case NPCPATH_TAKE_NOTES:
+ case NPCPATH_FACE_HOLMES:
+ _npcIndex += 3;
+ break;
+ case NPCPATH_SET_TALK_FILE:
+ case NPCPATH_CALL_TALK_FILE:
+ _npcIndex += 8;
+ break;
+ case NPCPATH_PATH_LABEL:
+ if (_npcPath[_npcIndex + 1] == label)
+ found = true;
+ _npcIndex += 2;
+ break;
+ case NPCPATH_GOTO_LABEL:
+ _npcIndex += 2;
+ break;
+ case NPCPATH_IFFLAG_GOTO_LABEL:
+ _npcIndex += 4;
+ break;
+ }
+ }
+ break;
+ }
+
+ case NPCPATH_IFFLAG_GOTO_LABEL: {
+ // If FLAG then Goto Label
+ int flag = (_npcPath[_npcIndex + 1] - 1) * 256 + _npcPath[_npcIndex + 2] - 1 - (_npcPath[_npcIndex + 2] == 1 ? 1 : 0);
+
+ // Set the value the flag should be for the if statement to succeed
+ bool flagVal = flag < 16384;
+
+ int label = _npcPath[_npcIndex + 3];
+ _npcIndex += 4;
+
+ // If the flag is set Correctly, move the NPC Index to the given label
+ if (_vm->readFlags(flag & 16383) == flagVal) {
+ _npcIndex = 0;
+ bool found = false;
+ while (!found)
+ {
+ switch (_npcPath[_npcIndex])
+ {
+ case NPCPATH_SET_DEST:
+ _npcIndex += 6;
+ break;
+ case NPCPATH_PAUSE:
+ case NPCPATH_TAKE_NOTES:
+ case NPCPATH_FACE_HOLMES:
+ _npcIndex += 3;
+ break;
+ case NPCPATH_SET_TALK_FILE:
+ case NPCPATH_CALL_TALK_FILE:
+ _npcIndex += 8;
+ break;
+ case NPCPATH_PATH_LABEL:
+ if (_npcPath[_npcIndex + 1] == label)
+ found = true;
+ _npcIndex += 2;
+ break;
+ case NPCPATH_GOTO_LABEL:
+ _npcIndex += 2;
+ break;
+ case NPCPATH_IFFLAG_GOTO_LABEL:
+ _npcIndex += 4;
+ break;
+ }
+ }
+ }
+
+ break;
+ }
+
+ default:
+ break;
+ }
+ }
+ }
+ }
+}
+
+void TattooPerson::pushNPCPath() {
+ assert(_pathStack.size() < 2);
+ SavedNPCPath savedPath(_npcPath, _npcIndex, _npcPause, _position, _sequenceNumber, _lookHolmes);
+ _pathStack.push(savedPath);
+}
+
+void TattooPerson::pullNPCPath() {
+ // Pop the stack entry and restore the fields
+ SavedNPCPath path = _pathStack.pop();
+ Common::copy(&path._path[0], &path._path[MAX_NPC_PATH], &_npcPath[0]);
+ _npcIndex = path._npcIndex;
+ _npcPause = path._npcPause;
+
+ // Handle the first case if the NPC was paused
+ if (_npcPause) {
+ _npcFacing = path._npcFacing;
+ _lookHolmes = path._lookHolmes;
+
+ // See if the NPC has moved from where they originally were
+ if (path._position != _position) {
+ _walkDest = Point32(path._position.x / FIXED_INT_MULTIPLIER, path._position.y / FIXED_INT_MULTIPLIER);
+ goAllTheWay();
+ _npcPause = 0;
+ _npcIndex -= 3;
+ } else {
+ // See if we need to set the old walk sequence so the NPC will put his arms up if he turns another way
+ if (_npcFacing != _sequenceNumber)
+ _oldWalkSequence = _sequenceNumber;
+
+ gotoStand();
+ }
+ } else {
+ // Handle the second case if the NPC was in motion
+ _npcIndex -= 6;
+ }
+}
+
+Common::Point TattooPerson::getSourcePoint() const {
+ TattooScene &scene = *(TattooScene *)_vm->_scene;
+ int scaleVal = scene.getScaleVal(_position);
+
+ return Common::Point(_position.x / FIXED_INT_MULTIPLIER + _imageFrame->sDrawXSize(scaleVal) / 2,
+ _position.y / FIXED_INT_MULTIPLIER);
+}
+
+void TattooPerson::setObjTalkSequence(int seq) {
+ assert(seq != -1 && _type == CHARACTER);
+
+ if (_seqTo) {
+ // reset to previous value
+ _walkSequences[_sequenceNumber]._sequences[_frameNumber] = _seqTo;
+ _seqTo = 0;
+ }
+
+ _sequenceNumber = _gotoSeq;
+ _frameNumber = 0;
+ checkWalkGraphics();
+}
+
+void TattooPerson::checkWalkGraphics() {
+ People &people = *_vm->_people;
+
+ if (_images == nullptr) {
+ freeAltGraphics();
+ return;
+ }
+
+ Common::String filename = Common::String::format("%s.vgs", _walkSequences[_sequenceNumber]._vgsName.c_str());
+
+ // Set the adjust depending on if we have to fine tune the x position of this particular graphic
+ _adjust.x = _adjust.y = 0;
+
+ for (int idx = 0; idx < NUM_ADJUSTED_WALKS; ++idx) {
+ if (!scumm_strnicmp(_walkSequences[_sequenceNumber]._vgsName.c_str(), ADJUST_WALKS[idx]._vgsName,
+ strlen(ADJUST_WALKS[idx]._vgsName))) {
+ if (_walkSequences[_sequenceNumber]._horizFlip)
+ _adjust.x = ADJUST_WALKS[idx]._flipXAdjust;
+ else
+ _adjust.x = ADJUST_WALKS[idx]._xAdjust;
+
+ _adjust.y = ADJUST_WALKS[idx]._yAdjust;
+ break;
+ }
+ }
+
+ // See if we're already using Alternate Graphics
+ if (_altSeq) {
+ // See if the VGS file called for is different than the alternate graphics already loaded
+ if (_walkSequences[_sequenceNumber]._vgsName.compareToIgnoreCase(_walkSequences[_altSeq - 1]._vgsName)) {
+ // Different AltGraphics, Free the old ones
+ freeAltGraphics();
+ }
+ }
+
+ // If there is no Alternate Sequence set, see if we need to load a new one
+ if (!_altSeq) {
+ int npcNum = -1;
+ // Find which NPC this is so we can check the name of the graphics loaded
+ for (int idx = 0; idx < MAX_CHARACTERS; ++idx) {
+ if (this == &people[idx]) {
+ npcNum = idx;
+ break;
+ }
+ }
+
+ if (npcNum != -1) {
+ // See if the VGS file called for is different than the main graphics which are already loaded
+ if (filename.compareToIgnoreCase(people[npcNum]._walkVGSName) != 0) {
+ // See if this is one of the more used Walk Graphics stored in WALK.LIB
+ for (int idx = 0; idx < NUM_IN_WALK_LIB; ++idx) {
+ if (!scumm_stricmp(filename.c_str(), WALK_LIB_NAMES[idx])) {
+ people._useWalkLib = true;
+ break;
+ }
+ }
+
+ _altImages = new ImageFile(filename);
+ people._useWalkLib = false;
+
+ _altSeq = _sequenceNumber + 1;
+ }
+ }
+ }
+
+ // If this is a different seqeunce from the current sequence, reset the appropriate variables
+ if (_sequences != &_walkSequences[_sequenceNumber]._sequences[0]) {
+ _seqTo = _seqCounter = _seqCounter2 = _seqStack = _startSeq = 0;
+ _sequences = &_walkSequences[_sequenceNumber]._sequences[0];
+ _seqSize = _walkSequences[_sequenceNumber]._sequences.size();
+
+ // WORKAROUND: Occassionally when switching to a new walk sequence the existing frame number may be outside
+ // the allowed range for the new sequence. In such cases, reset the frame number
+ if (_frameNumber < 0 || _frameNumber >= (int)_seqSize || _walkSequences[_sequenceNumber][_frameNumber] == 0)
+ _frameNumber = 0;
+ }
+
+ setImageFrame();
+}
+
+void TattooPerson::synchronize(Serializer &s) {
+ if (s.isSaving()) {
+ SpriteType type = (_type == INVALID && _walkLoaded) ? HIDDEN_CHARACTER : _type;
+ s.syncAsSint16LE(type);
+ } else {
+ if (_walkCount)
+ gotoStand();
+
+ s.syncAsSint16LE(_type);
+ }
+
+ s.syncAsSint32LE(_position.x);
+ s.syncAsSint32LE(_position.y);
+ s.syncString(_walkVGSName);
+ s.syncString(_description);
+ s.syncString(_examine);
+
+ // NPC specific properties
+ s.syncBytes(&_npcPath[0], MAX_NPC_PATH);
+ s.syncString(_npcName);
+ s.syncAsSint32LE(_npcPause);
+ s.syncAsByte(_lookHolmes);
+ s.syncAsByte(_updateNPCPath);
+ if (s.isLoading())
+ _npcIndex = 0;
+
+ // Verbs
+ for (int idx = 0; idx < 2; ++idx)
+ _use[idx].synchronize(s);
+}
+
+void TattooPerson::walkHolmesToNPC() {
+ Events &events = *_vm->_events;
+ TattooScene &scene = *(TattooScene *)_vm->_scene;
+ TattooPeople &people = *(TattooPeople *)_vm->_people;
+ Screen &screen = *_vm->_screen;
+ Talk &talk = *_vm->_talk;
+ TattooPerson &holmes = people[HOLMES];
+ int facing;
+
+ // Save the character's details
+ pushNPCPath();
+
+ // If the NPC is moving, stop him at his current position
+ if (_walkCount) {
+ // Reset the facing so the NPC will stop facing the direction he was going,
+ // rather than the direction he was supposed to when he finished wlaking
+ _npcFacing = -1;
+ gotoStand();
+ }
+
+ int scaleVal = scene.getScaleVal(_position);
+ ImageFrame &imgFrame = (*holmes._images)[0];
+
+ // Clear the path variables
+ memset(_npcPath, 0, 100);
+
+ // Set the NPC path so he pauses for 250 while looking at Holmes
+ _npcPath[0] = 6;
+ _npcPath[1] = 1;
+ _npcPath[2] = 251;
+ _npcIndex = 0;
+ _npcPause = 250;
+ _lookHolmes = true;
+
+ // See where Holmes is with respect to the NPC (x coords)
+ if (holmes._position.x < _position.x) {
+ 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);
+ }
+
+ // See where Holmes is with respect to the NPC (y coords)
+ if (holmes._position.y < (_position.y - imgFrame.sDrawXSize(scaleVal) * 500)) {
+ holmes._walkDest.y = MAX(_position.y / FIXED_INT_MULTIPLIER - imgFrame.sDrawXSize(scaleVal) / 2, 0);
+ } else {
+ if (holmes._position.y > (_position.y + imgFrame.sDrawXSize(scaleVal) * 500)) {
+ // Holmes is below the NPC
+ holmes._walkDest.y = MIN(_position.y / FIXED_INT_MULTIPLIER + imgFrame.sDrawXSize(scaleVal) / 2,
+ SHERLOCK_SCREEN_HEIGHT - 1);
+ } else {
+ // Holmes is roughly on the same Y as the NPC
+ holmes._walkDest.y = _position.y / FIXED_INT_MULTIPLIER;
+ }
+ }
+
+ events.setCursor(WAIT);
+
+ _walkDest.x += 10;
+ people._allowWalkAbort = true;
+ holmes.goAllTheWay();
+
+ // Do doBgAnim should be called over and over until walk is done
+ do {
+ events.wait(1);
+ scene.doBgAnim();
+ } while (holmes._walkCount);
+
+ if (!talk._talkToAbort) {
+ // Setup correct direction for Holmes to face
+
+ // See where Holmes is with respect to the NPC (x coords)
+ facing = (holmes._position.x < _position.x) ? STOP_RIGHT : STOP_LEFT;
+
+ // See where Holmes is with respect to the NPC (y coords)
+ if (holmes._position.y < (_position.y - (10 * FIXED_INT_MULTIPLIER))) {
+ // Holmes is above the NPC. Reset the facing to the diagonal downs
+ facing = (facing == STOP_RIGHT) ? STOP_DOWNRIGHT : STOP_DOWNLEFT;
+ } else {
+ if (holmes._position.y > (_position.y + 10 * FIXED_INT_MULTIPLIER)) {
+ // Holmes is below the NPC. Reset the facing to the diagonal ups
+ facing = (facing == STOP_RIGHT) ? STOP_UPRIGHT : STOP_UPLEFT;
+ }
+ }
+
+ holmes._sequenceNumber = facing;
+ holmes.gotoStand();
+
+ events.setCursor(ARROW);
+ }
+}
+
+void TattooPerson::walkBothToCoords(const PositionFacing &holmesDest, const PositionFacing &npcDest) {
+ Events &events = *_vm->_events;
+ TattooPeople &people = *(TattooPeople *)_vm->_people;
+ Scene &scene = *_vm->_scene;
+ Talk &talk = *_vm->_talk;
+ TattooPerson &holmes = people[HOLMES];
+ bool holmesStopped = false, npcStopped = false;
+
+ // Save the current cursor and change to the wait cursor
+ CursorId oldCursor = events.getCursor();
+ events.setCursor(WAIT);
+
+ holmes._centerWalk = false;
+ _centerWalk = false;
+
+ // Start Holmes walking to his dest
+ holmes._walkDest = Common::Point(holmesDest.x / FIXED_INT_MULTIPLIER + 10, holmesDest.y / FIXED_INT_MULTIPLIER);
+ people._allowWalkAbort = true;
+ holmes.goAllTheWay();
+
+ // Start the NPC walking to their dest
+ _walkDest = Common::Point(npcDest.x / FIXED_INT_MULTIPLIER + 10, npcDest.y / FIXED_INT_MULTIPLIER);
+ goAllTheWay();
+
+ // Clear the path variables
+ _npcIndex = _npcPause = 0;
+ Common::fill(&_npcPath[0], &_npcPath[100], 0);
+ _npcFacing = npcDest._facing;
+
+ // Now loop until both stop walking
+ do {
+ events.pollEvents();
+ scene.doBgAnim();
+
+ if (!holmes._walkCount && !holmesStopped) {
+ // Holmes finished walking
+ holmesStopped = true;
+
+ // Ensure Holmes is on the exact destination spot
+ holmes._position = holmesDest;
+ holmes._sequenceNumber = holmesDest._facing;
+ holmes.gotoStand();
+ }
+
+ if (!_walkCount && !npcStopped) {
+ // NPC finished walking
+ npcStopped = true;
+
+ // Ensure NPC is on the exact destination spot
+ _position = npcDest;
+ _sequenceNumber = npcDest._facing;
+ gotoStand();
+ }
+
+ } while (!_vm->shouldQuit() && (holmes._walkCount || _walkCount));
+
+ holmes._centerWalk = true;
+ _centerWalk = true;
+
+ // Do one last frame draw so that the lsat person to stop will be drawn in their final position
+ scene.doBgAnim();
+
+ _updateNPCPath = true;
+
+ if (!talk._talkToAbort)
+ // Restore original mouse cursor
+ events.setCursor(oldCursor);
+}
+
+void TattooPerson::centerScreenOnPerson() {
+ Screen &screen = *_vm->_screen;
+ 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);
+ screen._currentScroll = ui._targetScroll;
+
+ // Reset the default look position to the center of the screen
+ ui._lookPos = screen._currentScroll + Common::Point(SHERLOCK_SCREEN_WIDTH / 2, SHERLOCK_SCREEN_HEIGHT / 2);
+}
+
+/*----------------------------------------------------------------*/
+
+TattooPeople::TattooPeople(SherlockEngine *vm) : People(vm) {
+ for (int idx = 0; idx < 6; ++idx)
+ _data.push_back(new TattooPerson());
+}
+
+void TattooPeople::setListenSequence(int speaker, int sequenceNum) {
+ Scene &scene = *_vm->_scene;
+
+ // If no speaker is specified, then nothing needs to be done
+ if (speaker == -1)
+ return;
+
+ int objNum = findSpeaker(speaker);
+ if (objNum < CHARACTERS_INDEX && objNum != -1) {
+ // See if the Object has to wait for an Abort Talk Code
+ Object &obj = scene._bgShapes[objNum];
+ if (obj.hasAborts())
+ obj._gotoSeq = sequenceNum;
+ else
+ obj.setObjTalkSequence(sequenceNum);
+ } else if (objNum != -1) {
+ objNum -= CHARACTERS_INDEX;
+ TattooPerson &person = (*this)[objNum];
+
+ int newDir = person._sequenceNumber;
+ switch (person._sequenceNumber) {
+ case WALK_UP:
+ case STOP_UP:
+ case WALK_UPRIGHT:
+ case STOP_UPRIGHT:
+ case TALK_UPRIGHT:
+ case LISTEN_UPRIGHT:
+ newDir = LISTEN_UPRIGHT;
+ break;
+ case WALK_RIGHT:
+ case STOP_RIGHT:
+ case TALK_RIGHT:
+ case LISTEN_RIGHT:
+ newDir = LISTEN_RIGHT;
+ break;
+ case WALK_DOWNRIGHT:
+ case STOP_DOWNRIGHT:
+ case TALK_DOWNRIGHT:
+ case LISTEN_DOWNRIGHT:
+ newDir = LISTEN_DOWNRIGHT;
+ break;
+ case WALK_DOWN:
+ case STOP_DOWN:
+ case WALK_DOWNLEFT:
+ case STOP_DOWNLEFT:
+ case TALK_DOWNLEFT:
+ case LISTEN_DOWNLEFT:
+ newDir = LISTEN_DOWNLEFT;
+ break;
+ case WALK_LEFT:
+ case STOP_LEFT:
+ case TALK_LEFT:
+ case LISTEN_LEFT:
+ newDir = LISTEN_LEFT;
+ break;
+ case WALK_UPLEFT:
+ case STOP_UPLEFT:
+ case TALK_UPLEFT:
+ case LISTEN_UPLEFT:
+ newDir = LISTEN_UPLEFT;
+ break;
+
+ default:
+ break;
+ }
+
+ // See if the NPC's Seq has to wait for an Abort Talk Code
+ if (person.hasAborts()) {
+ person._gotoSeq = newDir;
+ } else {
+ if (person._seqTo) {
+ // Reset to previous value
+ person._walkSequences[person._sequenceNumber]._sequences[person._frameNumber] = person._seqTo;
+ person._seqTo = 0;
+ }
+
+ person._sequenceNumber = newDir;
+ person._frameNumber = 0;
+ person.checkWalkGraphics();
+ }
+ }
+}
+
+void TattooPeople::setTalkSequence(int speaker, int sequenceNum) {
+ TattooPeople &people = *(TattooPeople *)_vm->_people;
+ Scene &scene = *_vm->_scene;
+ TattooTalk &talk = *(TattooTalk *)_vm->_talk;
+
+ // If no speaker is specified, then nothing needs to be done
+ if (speaker == -1)
+ return;
+
+ int objNum = people.findSpeaker(speaker);
+ if (objNum != -1 && objNum < CHARACTERS_INDEX) {
+ Object &obj = scene._bgShapes[objNum];
+
+ // See if the Object has to wait for an Abort Talk Code
+ if (obj.hasAborts()) {
+ talk.pushSequenceEntry(&obj);
+ obj._gotoSeq = sequenceNum;
+ } else {
+ obj.setObjTalkSequence(sequenceNum);
+ }
+ } else if (objNum != -1) {
+ objNum -= CHARACTERS_INDEX;
+ TattooPerson &person = people[objNum];
+ int newDir = person._sequenceNumber;
+
+ switch (newDir) {
+ case WALK_UP:
+ case STOP_UP:
+ case WALK_UPRIGHT:
+ case STOP_UPRIGHT:
+ case TALK_UPRIGHT:
+ case LISTEN_UPRIGHT:
+ newDir = TALK_UPRIGHT;
+ break;
+ case WALK_RIGHT:
+ case STOP_RIGHT:
+ case TALK_RIGHT:
+ case LISTEN_RIGHT:
+ newDir = TALK_RIGHT;
+ break;
+ case WALK_DOWNRIGHT:
+ case STOP_DOWNRIGHT:
+ case TALK_DOWNRIGHT:
+ case LISTEN_DOWNRIGHT:
+ newDir = TALK_DOWNRIGHT;
+ break;
+ case WALK_DOWN:
+ case STOP_DOWN:
+ case WALK_DOWNLEFT:
+ case STOP_DOWNLEFT:
+ case TALK_DOWNLEFT:
+ case LISTEN_DOWNLEFT:
+ newDir = TALK_DOWNLEFT;
+ break;
+ case WALK_LEFT:
+ case STOP_LEFT:
+ case TALK_LEFT:
+ case LISTEN_LEFT:
+ newDir = TALK_LEFT;
+ break;
+ case WALK_UPLEFT:
+ case STOP_UPLEFT:
+ case TALK_UPLEFT:
+ case LISTEN_UPLEFT:
+ newDir = TALK_UPLEFT;
+ break;
+ default:
+ break;
+ }
+
+ // See if the NPC's sequence has to wait for an Abort Talk Code
+ if (person.hasAborts()) {
+ person._gotoSeq = newDir;
+ } else {
+ if (person._seqTo) {
+ // Reset to previous value
+ person._walkSequences[person._sequenceNumber]._sequences[person._frameNumber] = person._seqTo;
+ person._seqTo = 0;
+ }
+
+ person._sequenceNumber = newDir;
+ person._frameNumber = 0;
+ person.checkWalkGraphics();
+ }
+ }
+}
+
+
+int TattooPeople::findSpeaker(int speaker) {
+ int result = People::findSpeaker(speaker);
+ const char *portrait = _characters[speaker]._portrait;
+
+ // Fallback that Rose Tattoo uses if no speaker was found
+ if (result == -1) {
+ bool flag = _vm->readFlags(FLAG_PLAYER_IS_HOLMES);
+
+ if (_data[HOLMES]->_type == CHARACTER && ((speaker == HOLMES && flag) || (speaker == WATSON && !flag)))
+ // Return the offset index for the first character
+ return 0 + CHARACTERS_INDEX;
+
+ // Otherwise, scan through the list of the remaining characters to find a name match
+ for (uint idx = 1; idx < _data.size(); ++idx) {
+ TattooPerson &p = (*this)[idx];
+
+ if (p._type == CHARACTER) {
+ Common::String name(p._name.c_str(), p._name.c_str() + 4);
+
+ if (name.equalsIgnoreCase(portrait) && p._npcName[4] >= '0' && p._npcName[4] <= '9')
+ return idx + CHARACTERS_INDEX;
+ }
+ }
+ }
+
+ return result;
+}
+
+void TattooPeople::synchronize(Serializer &s) {
+ s.syncAsByte(_holmesOn);
+
+ for (uint idx = 0; idx < _data.size(); ++idx)
+ (*this)[idx].synchronize(s);
+
+ s.syncAsSint16LE(_holmesQuotient);
+
+ if (s.isLoading()) {
+ _savedPos.x = _data[HOLMES]->_position.x;
+ _savedPos.y = _data[HOLMES]->_position.y;
+ _savedPos._facing = _data[HOLMES]->_sequenceNumber;
+ }
+}
+
+bool TattooPeople::loadWalk() {
+ Resources &res = *_vm->_res;
+ bool result = false;
+
+ for (int idx = 0; idx < MAX_CHARACTERS; ++idx) {
+ Person &person = *_data[idx];
+
+ if (!person._walkLoaded && (person._type == CHARACTER || person._type == HIDDEN_CHARACTER)) {
+ if (person._type == HIDDEN_CHARACTER)
+ person._type = INVALID;
+
+ // See if this is one of the more used Walk Graphics stored in WALK.LIB
+ for (int libNum = 0; libNum < NUM_IN_WALK_LIB; ++libNum) {
+ if (!person._walkVGSName.compareToIgnoreCase(WALK_LIB_NAMES[libNum])) {
+ _useWalkLib = true;
+ break;
+ }
+ }
+
+ // Load the images for the character
+ person._images = new ImageFile(person._walkVGSName, false);
+ person._maxFrames = person._images->size();
+
+ // Load walk sequence data
+ Common::String fname = Common::String(person._walkVGSName.c_str(), strchr(person._walkVGSName.c_str(), '.'));
+ fname += ".SEQ";
+
+ // Load the walk sequence data
+ Common::SeekableReadStream *stream = res.load(fname, _useWalkLib ? "walk.lib" : "vgs.lib");
+
+ person._walkSequences.resize(stream->readByte());
+
+ for (uint seqNum = 0; seqNum < person._walkSequences.size(); ++seqNum)
+ person._walkSequences[seqNum].load(*stream);
+
+ // Close the sequences resource
+ delete stream;
+ _useWalkLib = false;
+
+ person._sequences = &person._walkSequences[person._sequenceNumber]._sequences[0];
+ person._seqSize = person._walkSequences[person._sequenceNumber]._sequences.size();
+ person._frameNumber = 0;
+ person.setImageFrame();
+
+ // Set the stop Frames pointers
+ for (int dirNum = 0; dirNum < 8; ++dirNum) {
+ int count = 0;
+ while (person._walkSequences[dirNum + 8][count] != 0)
+ ++count;
+ count += 2;
+ count = person._walkSequences[dirNum + 8][count] - 1;
+ person._stopFrames[dirNum] = &(*person._images)[count];
+ }
+
+ result = true;
+ person._walkLoaded = true;
+ } else if (person._type != CHARACTER) {
+ person._walkLoaded = false;
+ }
+ }
+
+ _forceWalkReload = false;
+ return result;
+}
+
+
+void TattooPeople::pullNPCPaths() {
+ for (int idx = 1; idx < MAX_CHARACTERS; ++idx) {
+ TattooPerson &p = (*this)[idx];
+ if (p._npcMoved) {
+ while (!p._pathStack.empty())
+ p.pullNPCPath();
+ }
+ }
+}
+
+const Common::Point TattooPeople::restrictToZone(int zoneId, const Common::Point &destPos) {
+ Scene &scene = *_vm->_scene;
+ Screen &screen = *_vm->_screen;
+ Common::Rect &r = scene._zones[zoneId];
+
+ if (destPos.x < 0 || destPos.x > screen._backBuffer1.w())
+ return destPos;
+ else if (destPos.y < r.top && r.left < destPos.x && destPos.x < r.right)
+ return Common::Point(destPos.x, r.top);
+ else if (destPos.y > r.bottom && r.left < destPos.x && destPos.x < r.right)
+ return Common::Point(destPos.x, r.bottom);
+ else if (destPos.x < r.left && r.top < destPos.y && destPos.y < r.bottom)
+ return Common::Point(r.left, destPos.y);
+ else if (destPos.x > r.right && r.top < destPos.y && destPos.y < r.bottom)
+ return Common::Point(r.right, destPos.y);
+
+ // Find which corner of the zone the point is closet to
+ if (destPos.x <= r.left) {
+ return Common::Point(r.left, (destPos.y <= r.top) ? r.top : r.bottom);
+ } else {
+ return Common::Point(r.right, (destPos.y <= r.top) ? r.top : r.bottom);
+ }
+}
+
+
+} // End of namespace Tattoo
+
+} // End of namespace Sherlock
diff --git a/engines/sherlock/tattoo/tattoo_people.h b/engines/sherlock/tattoo/tattoo_people.h
new file mode 100644
index 0000000000..722c4a9aaa
--- /dev/null
+++ b/engines/sherlock/tattoo/tattoo_people.h
@@ -0,0 +1,281 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public 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_PEOPLE_H
+#define SHERLOCK_TATTOO_PEOPLE_H
+
+#include "common/scummsys.h"
+#include "common/stack.h"
+#include "sherlock/people.h"
+
+namespace Sherlock {
+
+class SherlockEngine;
+
+namespace Tattoo {
+
+// Animation sequence identifiers for characters
+enum TattooSequences {
+ // Walk Sequences Numbers for NPCs
+ WALK_UP = 0,
+ WALK_UPRIGHT = 1,
+ WALK_RIGHT = 2,
+ WALK_DOWNRIGHT = 3,
+ WALK_DOWN = 4,
+ WALK_DOWNLEFT = 5,
+ WALK_LEFT = 6,
+ WALK_UPLEFT = 7,
+
+ // Stop Sequences Numbers for NPCs
+ STOP_UP = 8,
+ STOP_UPRIGHT = 9,
+ STOP_RIGHT = 10,
+ STOP_DOWNRIGHT = 11,
+ STOP_DOWN = 12,
+ STOP_DOWNLEFT = 13,
+ STOP_LEFT = 14,
+ STOP_UPLEFT = 15,
+
+ // NPC Talk Sequence Numbers
+ TALK_UPRIGHT = 16,
+ TALK_RIGHT = 17,
+ TALK_DOWNRIGHT = 18,
+ TALK_DOWNLEFT = 19,
+ TALK_LEFT = 20,
+ TALK_UPLEFT = 21,
+
+ // NPC Listen Sequence Numbers
+ LISTEN_UPRIGHT = 22,
+ LISTEN_RIGHT = 23,
+ LISTEN_DOWNRIGHT = 24,
+ LISTEN_DOWNLEFT = 25,
+ LISTEN_LEFT = 26,
+ LISTEN_UPLEFT = 27
+};
+
+enum NpcPath {
+ NPCPATH_SET_DEST = 1,
+ NPCPATH_PAUSE = 2,
+ NPCPATH_SET_TALK_FILE = 3,
+ NPCPATH_CALL_TALK_FILE = 4,
+ NPCPATH_TAKE_NOTES = 5,
+ NPCPATH_FACE_HOLMES = 6,
+ NPCPATH_PATH_LABEL = 7,
+ NPCPATH_GOTO_LABEL = 8,
+ NPCPATH_IFFLAG_GOTO_LABEL = 9
+};
+
+struct SavedNPCPath {
+ byte _path[MAX_NPC_PATH];
+ int _npcIndex;
+ int _npcPause;
+ Point32 _position;
+ int _npcFacing;
+ bool _lookHolmes;
+
+ SavedNPCPath();
+ SavedNPCPath(byte path[MAX_NPC_PATH], int npcIndex, int npcPause, const Point32 &position,
+ int npcFacing, bool lookHolmes);
+};
+
+class TattooPerson: public Person {
+private:
+ Point32 _nextDest;
+private:
+ bool checkCollision() const;
+
+ /**
+ * Free the alternate graphics used by NPCs
+ */
+ void freeAltGraphics();
+protected:
+ /**
+ * Get the source position for a character potentially affected by scaling
+ */
+ virtual Common::Point getSourcePoint() const;
+public:
+ Common::Stack<SavedNPCPath> _pathStack;
+ int _npcIndex;
+ int _npcPause;
+ byte _npcPath[MAX_NPC_PATH];
+ bool _npcMoved;
+ int _npcFacing;
+ bool _resetNPCPath;
+ int _savedNpcSequence;
+ int _savedNpcFrame;
+ int _tempX;
+ int _tempScaleVal;
+ bool _updateNPCPath;
+ bool _lookHolmes;
+public:
+ TattooPerson();
+ virtual ~TattooPerson() {}
+
+ /**
+ * Clear the NPC related data
+ */
+ void clearNPC();
+
+ /**
+ * Called from doBgAnim to move NPCs along any set paths. If an NPC is paused in his path,
+ * he will remain paused until his pause timer runs out. If he is walking somewhere,
+ * he will continue walking there until he reaches the dest position. When an NPC stops moving,
+ * the next element of his path is processed.
+ *
+ * The path is an array of bytes with control codes followed by their parameters as needed.
+ */
+ void updateNPC();
+
+ /**
+ * Push the NPC's path data onto the path stack for when a talk file moves the NPC that
+ * has some control codes.
+ */
+ void pushNPCPath();
+
+ /**
+ * Pull an NPC's path data that has been previously saved on the path stack for that character.
+ * There are two possibilities for when the NPC was interrupted, and both are handled differently:
+ * 1) The NPC was paused at a position
+ * If the NPC didn't move, we can just restore his pause counter and exit. But if he did move,
+ * he must return to that position, and the path index must be reset to the pause he was executing.
+ * This means that the index must be decremented by 3
+ * 2) The NPC was in route to a position
+ * He must be set to walk to that position again. This is done by moving the path index
+ * so that it points to the code that set the NPC walking there in the first place.
+ * The regular calls to updateNPC will handle the rest
+ */
+ void pullNPCPath();
+
+ /**
+ * Checks a sprite associated with an NPC to see if the frame sequence specified
+ * in the sequence number uses alternate graphics, and if so if they need to be loaded
+ */
+ void checkWalkGraphics();
+
+ /**
+ * Synchronize the data for a savegame
+ */
+ void synchronize(Serializer &s);
+
+
+ /**
+ * Walk Holmes to the NPC
+ */
+ void walkHolmesToNPC();
+
+ /**
+ * Walk both the specified character and Holmes to specified destination positions
+ */
+ void walkBothToCoords(const PositionFacing &holmesDest, const PositionFacing &npcDest);
+
+ /**
+ * This adjusts the sprites position, as well as its animation sequence:
+ */
+ virtual void adjustSprite();
+
+ /**
+ * Bring a moving character to a standing position
+ */
+ virtual void gotoStand();
+
+ /**
+ * Set the variables for moving a character from one poisition to another
+ * in a straight line
+ */
+ virtual void setWalking();
+
+ /**
+ * Walk to the co-ordinates passed, and then face the given direction
+ */
+ virtual void walkToCoords(const Point32 &destPos, int destDir);
+
+ /**
+ * Adjusts the frame and sequence variables of a sprite that corresponds to the current speaker
+ * so that it points to the beginning of the sequence number's talk sequence in the object's
+ * sequence buffer
+ * @param seq Which sequence to use (if there's more than 1)
+ * @remarks 1: First talk seq, 2: second talk seq, etc.
+ */
+ virtual void setObjTalkSequence(int seq);
+
+ /**
+ * Center the visible screen so that the person is in the center of the screen
+ */
+ virtual void centerScreenOnPerson();
+};
+
+class TattooPeople : public People {
+public:
+ TattooPeople(SherlockEngine *vm);
+ virtual ~TattooPeople() {}
+
+ TattooPerson &operator[](PeopleId id) { return *(TattooPerson *)_data[id]; }
+ TattooPerson &operator[](int idx) { return *(TattooPerson *)_data[idx]; }
+
+ /**
+ * Restore any saved NPC walk path data from any of the NPCs
+ */
+ void pullNPCPaths();
+
+ /**
+ * Finds the scene background object corresponding to a specified speaker
+ */
+ virtual int findSpeaker(int speaker);
+
+ /**
+ * Synchronize the data for a savegame
+ */
+ virtual void synchronize(Serializer &s);
+
+ /**
+ * Change the sequence of the scene background object associated with the specified speaker.
+ */
+ virtual void setTalkSequence(int speaker, int sequenceNum = 1);
+
+ /**
+ * Load the walking images for Sherlock
+ */
+ virtual bool loadWalk();
+
+ /**
+ * Restrict passed point to zone using Sherlock's positioning rules
+ */
+ virtual const Common::Point restrictToZone(int zoneId, const Common::Point &destPos);
+
+ /**
+ * If the specified speaker is a background object, it will set it so that it uses
+ * the Listen Sequence (specified by the sequence number). If the current sequence
+ * has an Allow Talk Code in it, the _gotoSeq field will be set so that the object
+ * begins listening as soon as it hits the Allow Talk Code. If there is no Abort Code,
+ * the Listen Sequence will begin immediately.
+ * @param speaker Who is speaking
+ * @param sequenceNum Which listen sequence to use
+ */
+ virtual void setListenSequence(int speaker, int sequenceNum = 1);
+};
+
+} // End of namespace Scalpel
+
+} // End of namespace Sherlock
+
+
+#endif
diff --git a/engines/sherlock/tattoo/tattoo_resources.cpp b/engines/sherlock/tattoo/tattoo_resources.cpp
new file mode 100644
index 0000000000..3be41e2650
--- /dev/null
+++ b/engines/sherlock/tattoo/tattoo_resources.cpp
@@ -0,0 +1,329 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public 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_resources.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 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
new file mode 100644
index 0000000000..b706d90f2d
--- /dev/null
+++ b/engines/sherlock/tattoo/tattoo_resources.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 SHERLOCK_TATTOO_RESOURCES_H
+#define SHERLOCK_TATTOO_RESOURCES_H
+
+#include "common/scummsys.h"
+
+namespace Sherlock {
+
+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];
+
+} // End of namespace Tattoo
+
+} // End of namespace Sherlock
+
+#endif
diff --git a/engines/sherlock/tattoo/tattoo_scene.cpp b/engines/sherlock/tattoo/tattoo_scene.cpp
index 2a13b2a450..f13d0588df 100644
--- a/engines/sherlock/tattoo/tattoo_scene.cpp
+++ b/engines/sherlock/tattoo/tattoo_scene.cpp
@@ -21,8 +21,10 @@
*/
#include "sherlock/tattoo/tattoo_scene.h"
-#include "sherlock/tattoo/tattoo.h"
+#include "sherlock/tattoo/tattoo_people.h"
+#include "sherlock/tattoo/tattoo_talk.h"
#include "sherlock/tattoo/tattoo_user_interface.h"
+#include "sherlock/tattoo/tattoo.h"
#include "sherlock/events.h"
#include "sherlock/people.h"
@@ -30,28 +32,262 @@ namespace Sherlock {
namespace Tattoo {
-TattooScene::TattooScene(SherlockEngine *vm) : Scene(vm) {
- _arrowZone = -1;
- _mask = _mask1 = nullptr;
- _maskCounter = 0;
+const int FS_TRANS[8] = {
+ STOP_UP, STOP_UPRIGHT, STOP_RIGHT, STOP_DOWNRIGHT, STOP_DOWN, STOP_DOWNLEFT, STOP_LEFT, STOP_UPLEFT
+};
+
+/*----------------------------------------------------------------*/
+
+struct ShapeEntry {
+ Object *_shape;
+ TattooPerson *_person;
+ bool _isAnimation;
+ int _yp;
+ int _ordering;
+
+ ShapeEntry(TattooPerson *person, int yp, int ordering) :
+ _shape(nullptr), _person(person), _yp(yp), _isAnimation(false), _ordering(ordering) {}
+ ShapeEntry(Object *shape, int yp, int ordering) :
+ _shape(shape), _person(nullptr), _yp(yp), _isAnimation(false), _ordering(ordering) {}
+ ShapeEntry(int yp, int ordering) :
+ _shape(nullptr), _person(nullptr), _yp(yp), _isAnimation(true), _ordering(ordering) {}
+};
+typedef Common::List<ShapeEntry> ShapeList;
+
+static bool sortImagesY(const ShapeEntry &s1, const ShapeEntry &s2) {
+ // Objects are order by the calculated Y position first and then, when both are equal,
+ // by the order in which the entries were added
+ return s1._yp < s2._yp || (s1._yp == s2._yp && s1._ordering < s2._ordering);
}
-void TattooScene::checkBgShapes() {
- People &people = *_vm->_people;
- Person &holmes = people._player;
- Common::Point pt(holmes._position.x / FIXED_INT_MULTIPLIER, holmes._position.y / FIXED_INT_MULTIPLIER);
+/*----------------------------------------------------------------*/
+
+TattooScene::TattooScene(SherlockEngine *vm) : Scene(vm), _labWidget(vm) {
+ _labTableScene = false;
+}
+
+bool TattooScene::loadScene(const Common::String &filename) {
+ TattooEngine &vm = *(TattooEngine *)_vm;
+ Events &events = *_vm->_events;
+ Music &music = *_vm->_music;
+ Talk &talk = *_vm->_talk;
+ TattooUserInterface &ui = *(TattooUserInterface *)_vm->_ui;
+
+ // If we're going to the first game scene after the intro sequence, flag it as finished
+ if (vm._runningProlog && _currentScene == STARTING_GAME_SCENE) {
+ vm._runningProlog = false;
+ events.showCursor();
+ talk._talkToAbort = false;
+ }
+
+ // Check if it's a scene we need to keep trakc track of how many times we've visited
+ for (int idx = (int)_sceneTripCounters.size() - 1; idx >= 0; --idx) {
+ if (_sceneTripCounters[idx]._sceneNumber == _currentScene) {
+ if (--_sceneTripCounters[idx]._numTimes == 0) {
+ _vm->setFlags(_sceneTripCounters[idx]._flag);
+ _sceneTripCounters.remove_at(idx);
+ }
+ }
+ }
+
+ // 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();
+ }
+ }
+ }
+
+ bool result = Scene::loadScene(filename);
+
+ if (_currentScene != STARTING_INTRO_SCENE) {
+ // Set the menu/ui mode and whether we're in a lab table close-up scene
+ _labTableScene = _currentScene > 91 && _currentScene < 100;
+ ui._menuMode = _labTableScene ? LAB_MODE : STD_MODE;
+
+ if (_labTableScene)
+ ui.addFixedWidget(&_labWidget);
+ }
+
+ return result;
+}
+
+void TattooScene::drawAllShapes() {
+ TattooPeople &people = *(TattooPeople *)_vm->_people;
+ Screen &screen = *_vm->_screen;
+ ShapeList shapeList;
+ int ordering = 0;
+
+ // Draw all objects and animations that are set to behind
+ screen.setDisplayBounds(Common::Rect(0, 0, SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT));
+
+ // Draw all active shapes which are behind the person
+ for (uint idx = 0; idx < _bgShapes.size(); ++idx) {
+ Object &obj = _bgShapes[idx];
+
+ if (obj._type == ACTIVE_BG_SHAPE && obj._misc == BEHIND) {
+ if (obj._quickDraw && obj._scaleVal == SCALE_THRESHOLD)
+ screen._backBuffer1.blitFrom(*obj._imageFrame, obj._position);
+ else
+ screen._backBuffer1.transBlitFrom(*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,
+ (_activeCAnim._flags & 4) >> 1, 0, _activeCAnim._scaleVal);
+
+ screen.resetDisplayBounds();
+
+ // Queue drawing of all objects that are set to NORMAL.
+ for (uint idx = 0; idx < _bgShapes.size(); ++idx) {
+ Object &obj = _bgShapes[idx];
+
+ if (obj._type == ACTIVE_BG_SHAPE && (obj._misc == NORMAL_BEHIND || obj._misc == NORMAL_FORWARD)) {
+ if (obj._scaleVal == SCALE_THRESHOLD)
+ shapeList.push_back(ShapeEntry(&obj, obj._position.y + obj._imageFrame->_offset.y +
+ obj._imageFrame->_height, ordering++));
+ else
+ shapeList.push_back(ShapeEntry(&obj, obj._position.y + obj._imageFrame->sDrawYOffset(obj._scaleVal) +
+ obj._imageFrame->sDrawYSize(obj._scaleVal), ordering++));
+ }
+ }
+
+ // Queue drawing the animation if it is NORMAL and can fall in front of, or behind the people
+ if (_activeCAnim.active() && (_activeCAnim._zPlacement == NORMAL_BEHIND || _activeCAnim._zPlacement == NORMAL_FORWARD)) {
+ if (_activeCAnim._scaleVal == SCALE_THRESHOLD)
+ shapeList.push_back(ShapeEntry(_activeCAnim._position.y + _activeCAnim._imageFrame._offset.y +
+ _activeCAnim._imageFrame._height, ordering++));
+ else
+ shapeList.push_back(ShapeEntry(_activeCAnim._position.y + _activeCAnim._imageFrame.sDrawYOffset(_activeCAnim._scaleVal) +
+ _activeCAnim._imageFrame.sDrawYSize(_activeCAnim._scaleVal), ordering++));
+ }
+
+ // Queue all active characters for drawing
+ for (int idx = 0; idx < MAX_CHARACTERS; ++idx) {
+ if (people[idx]._type == CHARACTER && people[idx]._walkLoaded)
+ shapeList.push_back(ShapeEntry(&people[idx], people[idx]._position.y / FIXED_INT_MULTIPLIER, ordering++));
+ }
+
+ // Sort the list
+ Common::sort(shapeList.begin(), shapeList.end(), sortImagesY);
+
+ // Draw the list of shapes in order
+ for (ShapeList::iterator i = shapeList.begin(); i != shapeList.end(); ++i) {
+ ShapeEntry &se = *i;
+
+ 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);
+ else
+ screen._backBuffer1.transBlitFrom(*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,
+ (_activeCAnim._flags & 4) >> 1, 0, _activeCAnim._scaleVal);
+ } else {
+ // Drawing person
+ TattooPerson &p = *se._person;
+
+ p._tempX = p._position.x / FIXED_INT_MULTIPLIER;
+ p._tempScaleVal = getScaleVal(p._position);
+ Common::Point adjust = p._adjust;
+
+ if (p._tempScaleVal == SCALE_THRESHOLD) {
+ p._tempX += adjust.x;
+ screen._backBuffer1.transBlitFrom(*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) {
+ if (!p._tempScaleVal)
+ ++p._tempScaleVal;
+
+ if (p._tempScaleVal >= SCALE_THRESHOLD && adjust.x)
+ --adjust.x;
+
+ adjust.x = adjust.x * SCALE_THRESHOLD / p._tempScaleVal;
+
+ if (p._tempScaleVal >= SCALE_THRESHOLD)
+ ++adjust.x;
+ p._tempX += adjust.x;
+ }
+
+ if (adjust.y) {
+ if (!p._tempScaleVal)
+ p._tempScaleVal++;
+
+ if (p._tempScaleVal >= SCALE_THRESHOLD && adjust.y)
+ --adjust.y;
+
+ adjust.y = adjust.y * SCALE_THRESHOLD / p._tempScaleVal;
+
+ if (p._tempScaleVal >= SCALE_THRESHOLD)
+ ++adjust.y;
+ }
+
+ screen._backBuffer1.transBlitFrom(*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);
+ }
+ }
+ }
+
+ // Draw all objects & canimations that are set to FORWARD.
+ // Draw all static and active shapes that are FORWARD
+ for (uint idx = 0; idx < _bgShapes.size(); ++idx) {
+ Object &obj = _bgShapes[idx];
+
+ if (obj._type == ACTIVE_BG_SHAPE && obj._misc == FORWARD) {
+ if (obj._quickDraw && obj._scaleVal == SCALE_THRESHOLD)
+ screen._backBuffer1.blitFrom(*obj._imageFrame, obj._position);
+ else
+ screen._backBuffer1.transBlitFrom(*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);
+
+ // Draw all NO_SHAPE shapes which have their flag bits clear
+ for (uint idx = 0; idx < _bgShapes.size(); ++idx) {
+ Object &obj = _bgShapes[idx];
+ if (obj._type == NO_SHAPE && (obj._flags & 1) == 0)
+ screen._backBuffer1.fillRect(obj.getNoShapeBounds(), 15);
+ }
+}
+
+void TattooScene::paletteLoaded() {
+ Screen &screen = *_vm->_screen;
+ TattooUserInterface &ui = *(TattooUserInterface *)_vm->_ui;
+ ui.setupBGArea(screen._cMap);
+ ui.initScrollVars();
+}
+
+void TattooScene::checkBgShapes() {
// Call the base scene method to handle bg shapes
Scene::checkBgShapes();
// Check for any active playing animation
- if (_activeCAnim._images && _activeCAnim._zPlacement != REMOVE) {
+ if (_activeCAnim.active() && _activeCAnim._zPlacement != REMOVE) {
switch (_activeCAnim._flags & 3) {
case 0:
_activeCAnim._zPlacement = BEHIND;
break;
case 1:
- _activeCAnim._zPlacement = ((_activeCAnim._position.y + _activeCAnim._imageFrame->_frame.h - 1)) ?
+ _activeCAnim._zPlacement = ((_activeCAnim._position.y + _activeCAnim._imageFrame._frame.h - 1)) ?
NORMAL_FORWARD : NORMAL_BEHIND;
break;
case 2:
@@ -63,9 +299,19 @@ void TattooScene::checkBgShapes() {
}
}
+void TattooScene::freeScene() {
+ TattooUserInterface &ui = *(TattooUserInterface *)_vm->_ui;
+ Scene::freeScene();
+
+ // Delete any scene overlays that were used by the scene
+ delete ui._mask;
+ delete ui._mask1;
+ ui._mask = ui._mask1 = nullptr;
+}
+
void TattooScene::doBgAnimCheckCursor() {
Events &events = *_vm->_events;
- UserInterface &ui = *_vm->_ui;
+ TattooUserInterface &ui = *(TattooUserInterface *)_vm->_ui;
Common::Point mousePos = events.mousePos();
// If we're in Look Mode, make sure the cursor is the magnifying glass
@@ -77,7 +323,7 @@ void TattooScene::doBgAnimCheckCursor() {
if (events.getCursor() == ARROW || events.getCursor() >= EXIT_ZONES_START) {
CursorId cursorId = ARROW;
- if (ui._menuMode == STD_MODE && _arrowZone != -1 && _currentScene != 90) {
+ if (ui._menuMode == STD_MODE && ui._arrowZone != -1 && _currentScene != 90) {
for (uint idx = 0; idx < _exits.size(); ++idx) {
Exit &exit = _exits[idx];
if (exit.contains(mousePos))
@@ -86,151 +332,80 @@ void TattooScene::doBgAnimCheckCursor() {
}
events.setCursor(cursorId);
- }
-}
-
-void TattooScene::doBgAnimEraseBackground() {
- TattooEngine &vm = *((TattooEngine *)_vm);
- People &people = *_vm->_people;
- Screen &screen = *_vm->_screen;
- TattooUserInterface &ui = *((TattooUserInterface *)_vm->_ui);
-
- static const int16 OFFSETS[16] = { -1, -2, -3, -3, -2, -1, -1, 0, 1, 2, 3, 3, 2, 1, 0, 0 };
-
- if (_mask != nullptr) {
- if (screen._backBuffer1.w() > screen.w())
- screen.blitFrom(screen._backBuffer1, Common::Point(0, 0), Common::Rect(screen._currentScroll, 0,
- screen._currentScroll + screen.w(), screen.h()));
- else
- screen.blitFrom(screen._backBuffer1);
-
- switch (_currentScene) {
- case 7:
- if (++_maskCounter == 2) {
- _maskCounter = 0;
- if (--_maskOffset.x < 0)
- _maskOffset.x = SHERLOCK_SCREEN_WIDTH - 1;
- }
- break;
-
- case 8:
- _maskOffset.x += 2;
- if (_maskOffset.x >= SHERLOCK_SCREEN_WIDTH)
- _maskOffset.x = 0;
- break;
-
- case 18:
- case 68:
- ++_maskCounter;
- if (_maskCounter / 4 >= 16)
- _maskCounter = 0;
-
- _maskOffset.x = OFFSETS[_maskCounter / 4];
- break;
-
- case 53:
- if (++_maskCounter == 2) {
- _maskCounter = 0;
- if (++_maskOffset.x == screen._backBuffer1.w())
- _maskOffset.x = 0;
- }
- break;
-
- default:
- break;
- }
} else {
- // Standard scene without mask, so call user interface to erase any UI elements as necessary
- ui.doBgAnimRestoreUI();
-
- // Restore background for any areas covered by characters and shapes
- for (uint idx = 0; idx < MAX_CHARACTERS; ++idx)
- screen.restoreBackground(Common::Rect(people[idx]._oldPosition.x, people[idx]._oldPosition.y,
- people[idx]._oldPosition.x + people[idx]._oldSize.x, people[idx]._oldPosition.y + people[idx]._oldSize.y));
-
- for (uint idx = 0; idx < _bgShapes.size(); ++idx) {
- Object &obj = _bgShapes[idx];
-
- 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(*obj._imageFrame, obj._oldPosition,
- Common::Rect(obj._oldPosition.x, obj._oldPosition.y, obj._oldPosition.x + obj._oldSize.x,
- obj._oldPosition.y + obj._oldSize.y));
- }
-
- // If credits are active, erase the area they cover
- if (vm._creditsActive)
- vm.eraseCredits();
+ events.animateCursorIfNeeded();
}
-
- for (uint idx = 0; idx < _bgShapes.size(); ++idx) {
- Object &obj = _bgShapes[idx];
-
- if (obj._type == NO_SHAPE && (obj._flags & 1) == 0) {
- screen._backBuffer1.blitFrom(screen._backBuffer2, obj._position, obj.getNoShapeBounds());
-
- obj._oldPosition = obj._position;
- obj._oldSize = obj._noShapeSize;
- }
- }
-
- // Adjust the Target Scroll if needed
- if ((people[people._walkControl]._position.x / FIXED_INT_MULTIPLIER - screen._currentScroll) <
- (SHERLOCK_SCREEN_WIDTH / 8) && people[people._walkControl]._delta.x < 0) {
-
- screen._targetScroll = (short)(people[people._walkControl]._position.x / FIXED_INT_MULTIPLIER -
- SHERLOCK_SCREEN_WIDTH / 8 - 250);
- if (screen._targetScroll < 0)
- screen._targetScroll = 0;
- }
-
- if ((people[people._walkControl]._position.x / FIXED_INT_MULTIPLIER - screen._currentScroll) > (SHERLOCK_SCREEN_WIDTH / 4 * 3)
- && people[people._walkControl]._delta.x > 0)
- screen._targetScroll = (short)(people[people._walkControl]._position.x / FIXED_INT_MULTIPLIER -
- SHERLOCK_SCREEN_WIDTH / 4 * 3 + 250);
-
- if (screen._targetScroll > screen._scrollSize)
- screen._targetScroll = screen._scrollSize;
-
- ui.doScroll();
}
void TattooScene::doBgAnim() {
+ TattooEngine &vm = *(TattooEngine *)_vm;
+ Events &events = *_vm->_events;
+ TattooPeople &people = *(TattooPeople *)_vm->_people;
+ Screen &screen = *_vm->_screen;
+ Talk &talk = *_vm->_talk;
TattooUserInterface &ui = *((TattooUserInterface *)_vm->_ui);
doBgAnimCheckCursor();
-// Events &events = *_vm->_events;
- People &people = *_vm->_people;
-// Scene &scene = *_vm->_scene;
- Screen &screen = *_vm->_screen;
- Talk &talk = *_vm->_talk;
-
- screen.setDisplayBounds(Common::Rect(0, 0, SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCENE_HEIGHT));
talk._talkToAbort = false;
// Check the characters and sprites for updates
- for (uint idx = 0; idx < MAX_CHARACTERS; ++idx) {
+ for (int idx = 0; idx < MAX_CHARACTERS; ++idx) {
if (people[idx]._type == CHARACTER)
people[idx].checkSprite();
}
-
+
for (uint idx = 0; idx < _bgShapes.size(); ++idx) {
if (_bgShapes[idx]._type == ACTIVE_BG_SHAPE)
_bgShapes[idx].checkObject();
}
+ // If one of the objects has signalled a call to a talk file, to go to another scene, exit immediately
+ if (_goToScene != -1)
+ return;
+
// Erase any affected background areas
- doBgAnimEraseBackground();
+ ui.doBgAnimEraseBackground();
doBgAnimUpdateBgObjectsAndAnim();
+ doBgAnimDrawSprites();
+
ui.drawInterface();
+
+ if (ui._creditsWidget.active())
+ ui._creditsWidget.blitCredits();
+
+ if (screen._flushScreen) {
+ screen.slamArea(screen._currentScroll.x, screen._currentScroll.y, SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT);
+ screen._flushScreen = false;
+ }
+
+ screen._flushScreen = false;
+ _doBgAnimDone = true;
+ ui._drawMenu = false;
+
+ // Handle drawing tooltips
+ if (ui._menuMode == STD_MODE || ui._menuMode == LAB_MODE)
+ ui._tooltipWidget.draw();
+ if (!ui._postRenderWidgets.empty()) {
+ for (WidgetList::iterator i = ui._postRenderWidgets.begin(); i != ui._postRenderWidgets.end(); ++i)
+ (*i)->draw();
+ ui._postRenderWidgets.clear();
+ }
+
+ if (!vm._fastMode)
+ events.wait(3);
+
+ for (int idx = 1; idx < MAX_CHARACTERS; ++idx) {
+ if (people[idx]._updateNPCPath)
+ people[idx].updateNPC();
+ }
}
void TattooScene::doBgAnimUpdateBgObjectsAndAnim() {
People &people = *_vm->_people;
- Screen &screen = *_vm->_screen;
+ TattooUserInterface &ui = *(TattooUserInterface *)_vm->_ui;
for (uint idx = 0; idx < _bgShapes.size(); ++idx) {
Object &obj = _bgShapes[idx];
@@ -238,102 +413,31 @@ void TattooScene::doBgAnimUpdateBgObjectsAndAnim() {
obj.adjustObject();
}
- for (uint idx = 0; idx < MAX_CHARACTERS; ++idx) {
+ for (int idx = 0; idx < MAX_CHARACTERS; ++idx) {
if (people[idx]._type == CHARACTER)
people[idx].adjustSprite();
}
- if ((_activeCAnim._images != nullptr) && (_activeCAnim._zPlacement != REMOVE)) {
- _activeCAnim.getNextFrame();
- }
-
// Flag the bg shapes which need to be redrawn
checkBgShapes();
drawAllShapes();
-
- if (_mask != nullptr) {
- switch (_currentScene) {
- case 7:
- screen._backBuffer1.maskArea((*_mask)[0], Common::Point(_maskOffset.x - SHERLOCK_SCREEN_WIDTH, 110), screen._currentScroll);
- screen._backBuffer1.maskArea((*_mask)[0], Common::Point(_maskOffset.x, 110), screen._currentScroll);
- screen._backBuffer1.maskArea((*_mask)[0], Common::Point(_maskOffset.x + SHERLOCK_SCREEN_WIDTH, 110), screen._currentScroll);
- break;
-
- case 8:
- screen._backBuffer1.maskArea((*_mask)[0], Common::Point(_maskOffset.x - SHERLOCK_SCREEN_WIDTH, 180), screen._currentScroll);
- screen._backBuffer1.maskArea((*_mask)[0], Common::Point(_maskOffset.x, 180), screen._currentScroll);
- screen._backBuffer1.maskArea((*_mask)[0], Common::Point(_maskOffset.x + SHERLOCK_SCREEN_WIDTH, 180), screen._currentScroll);
- if (!_vm->readFlags(880))
- screen._backBuffer1.maskArea((*_mask1)[0], Common::Point(940, 300), screen._currentScroll);
- break;
-
- case 18:
- screen._backBuffer1.maskArea((*_mask)[0], Common::Point(_maskOffset.x, 203), screen._currentScroll);
- if (!_vm->readFlags(189))
- screen._backBuffer1.maskArea((*_mask1)[0], Common::Point(124 + _maskOffset.x, 239), screen._currentScroll);
- break;
-
- case 53:
- screen._backBuffer1.maskArea((*_mask)[0], Common::Point(_maskOffset.x, 110), screen._currentScroll);
- screen._backBuffer1.maskArea((*_mask)[0], Common::Point(_maskOffset.x - SHERLOCK_SCREEN_WIDTH, 110), screen._currentScroll);
- break;
-
- case 68:
- screen._backBuffer1.maskArea((*_mask)[0], Common::Point(_maskOffset.x, 203), screen._currentScroll);
- screen._backBuffer1.maskArea((*_mask1)[0], Common::Point(124 + _maskOffset.x, 239), screen._currentScroll);
- break;
- }
- }
+ ui.drawMaskArea(true);
}
-
void TattooScene::updateBackground() {
- People &people = *_vm->_people;
+ TattooPeople &people = *(TattooPeople *)_vm->_people;
Screen &screen = *_vm->_screen;
+ TattooUserInterface &ui = *(TattooUserInterface *)_vm->_ui;
Scene::updateBackground();
- if (_mask != nullptr) {
- switch (_currentScene) {
- case 7:
- screen._backBuffer1.maskArea((*_mask)[0], Common::Point(_maskOffset.x - SHERLOCK_SCREEN_WIDTH, 110), screen._currentScroll);
- screen._backBuffer1.maskArea((*_mask)[0], Common::Point(_maskOffset.x, 110), screen._currentScroll);
- screen._backBuffer1.maskArea((*_mask)[0], Common::Point(_maskOffset.x + SHERLOCK_SCREEN_WIDTH, 110), screen._currentScroll);
- break;
-
- case 8:
- screen._backBuffer1.maskArea((*_mask)[0], Common::Point(_maskOffset.x - SHERLOCK_SCREEN_WIDTH, 180), screen._currentScroll);
- screen._backBuffer1.maskArea((*_mask)[0], Common::Point(_maskOffset.x, 180), screen._currentScroll);
- screen._backBuffer1.maskArea((*_mask)[0], Common::Point(_maskOffset.x + SHERLOCK_SCREEN_WIDTH, 180), screen._currentScroll);
- if (!_vm->readFlags(880))
- screen._backBuffer1.maskArea((*_mask1)[0], Common::Point(940, 300), screen._currentScroll);
- break;
-
- case 18:
- screen._backBuffer1.maskArea((*_mask)[0], Common::Point(0, 203), screen._currentScroll);
- if (!_vm->readFlags(189))
- screen._backBuffer1.maskArea((*_mask1)[0], Common::Point(124, 239), screen._currentScroll);
- break;
-
- case 53:
- screen._backBuffer1.maskArea((*_mask)[0], Common::Point(_maskOffset.x, 110), screen._currentScroll);
- break;
-
- case 68:
- screen._backBuffer1.maskArea((*_mask)[0], Common::Point(0, 203), screen._currentScroll);
- screen._backBuffer1.maskArea((*_mask1)[0], Common::Point(124, 239), screen._currentScroll);
- break;
-
- default:
- break;
- }
- }
+ ui.drawMaskArea(false);
screen._flushScreen = true;
for (int idx = 0; idx < MAX_CHARACTERS; ++idx) {
- Person &p = people[idx];
+ TattooPerson &p = people[idx];
if (p._type != INVALID) {
if (_goToScene == -1 || _cAnim.size() == 0) {
@@ -341,7 +445,7 @@ void TattooScene::updateBackground() {
screen.slamArea(p._oldPosition.x, p._oldPosition.y, p._oldSize.x, p._oldSize.y);
p._type = INVALID;
} else {
- if (p._tempScaleVal == 256) {
+ if (p._tempScaleVal == SCALE_THRESHOLD) {
screen.flushImage(p._imageFrame, Common::Point(p._tempX, p._position.y / FIXED_INT_MULTIPLIER
- p._imageFrame->_width), &p._oldPosition.x, &p._oldPosition.y, &p._oldSize.x, &p._oldSize.y);
} else {
@@ -360,7 +464,7 @@ void TattooScene::updateBackground() {
if (obj._type == ACTIVE_BG_SHAPE || obj._type == REMOVE) {
if (_goToScene == -1) {
- if (obj._scaleVal == 256)
+ if (obj._scaleVal == SCALE_THRESHOLD)
screen.flushImage(obj._imageFrame, obj._position, &obj._oldPosition.x, &obj._oldPosition.y,
&obj._oldSize.x, &obj._oldSize.y);
else
@@ -381,7 +485,7 @@ void TattooScene::updateBackground() {
screen.slamRect(obj.getNoShapeBounds());
screen.slamRect(obj.getOldBounds());
} else if (obj._type == HIDE_SHAPE) {
- if (obj._scaleVal == 256)
+ if (obj._scaleVal == SCALE_THRESHOLD)
screen.flushImage(obj._imageFrame, obj._position, &obj._oldPosition.x, &obj._oldPosition.y,
&obj._oldSize.x, &obj._oldSize.y);
else
@@ -395,6 +499,360 @@ void TattooScene::updateBackground() {
screen._flushScreen = false;
}
+void TattooScene::doBgAnimDrawSprites() {
+ TattooPeople &people = *(TattooPeople *)_vm->_people;
+ Screen &screen = *_vm->_screen;
+
+ for (int idx = 0; idx < MAX_CHARACTERS; ++idx) {
+ TattooPerson &person = people[idx];
+
+ if (person._type != INVALID) {
+ if (_goToScene == -1 || _cAnim.size() == 0) {
+ if (person._type == REMOVE) {
+ screen.slamRect(person.getOldBounds());
+ person._type = INVALID;
+ } else {
+ if (person._tempScaleVal == SCALE_THRESHOLD) {
+ screen.flushImage(person._imageFrame, Common::Point(person._tempX, person._position.y / FIXED_INT_MULTIPLIER
+ - person.frameHeight()), &person._oldPosition.x, &person._oldPosition.y, &person._oldSize.x, &person._oldSize.y);
+ } else {
+ int ts = person._imageFrame->sDrawYSize(person._tempScaleVal);
+ int ty = person._position.y / FIXED_INT_MULTIPLIER - ts;
+ screen.flushScaleImage(person._imageFrame, Common::Point(person._tempX, ty),
+ &person._oldPosition.x, &person._oldPosition.y, &person._oldSize.x, &person._oldSize.y, person._tempScaleVal);
+ }
+ }
+ }
+ }
+ }
+
+ for (uint idx = 0; idx < _bgShapes.size(); ++idx) {
+ Object &obj = _bgShapes[idx];
+
+ if (obj._type == ACTIVE_BG_SHAPE || obj._type == REMOVE) {
+ if (_goToScene == -1) {
+ if (obj._scaleVal == SCALE_THRESHOLD)
+ screen.flushImage(obj._imageFrame, obj._position, &obj._oldPosition.x, &obj._oldPosition.y,
+ &obj._oldSize.x, &obj._oldSize.y);
+ else
+ screen.flushScaleImage(obj._imageFrame, obj._position, &obj._oldPosition.x, &obj._oldPosition.y,
+ &obj._oldSize.x, &obj._oldSize.y, obj._scaleVal);
+
+ if (obj._type == REMOVE)
+ obj._type = INVALID;
+ }
+ }
+ }
+
+ for (uint idx = 0; idx < _bgShapes.size(); ++idx) {
+ Object &obj = _bgShapes[idx];
+
+ if (_goToScene == -1) {
+ if (obj._type == NO_SHAPE && (obj._flags & 1) == 0) {
+ screen.slamRect(obj.getNoShapeBounds());
+ screen.slamRect(obj.getOldBounds());
+ } else if (obj._type == HIDE_SHAPE) {
+ if (obj._scaleVal == SCALE_THRESHOLD)
+ screen.flushImage(obj._imageFrame, obj._position, &obj._oldPosition.x, &obj._oldPosition.y,
+ &obj._oldSize.x, &obj._oldSize.y);
+ else
+ screen.flushScaleImage(obj._imageFrame, obj._position, &obj._oldPosition.x, &obj._oldPosition.y,
+ &obj._oldSize.x, &obj._oldSize.y, obj._scaleVal);
+ obj._type = HIDDEN;
+ }
+ }
+ }
+
+ if (_activeCAnim.active() || _activeCAnim._zPlacement == REMOVE) {
+ if (_activeCAnim._zPlacement != REMOVE) {
+ screen.flushImage(&_activeCAnim._imageFrame, _activeCAnim._position, _activeCAnim._oldBounds, _activeCAnim._scaleVal);
+ } else {
+ screen.slamRect(_activeCAnim._removeBounds);
+ _activeCAnim._removeBounds = Common::Rect(0, 0, 0, 0);
+ _activeCAnim._zPlacement = -1; // Reset _zPlacement so we don't REMOVE again
+ }
+ }
+}
+
+int TattooScene::getScaleVal(const Point32 &pt) {
+ bool found = false;
+ int result = SCALE_THRESHOLD;
+ Common::Point pos(pt.x / FIXED_INT_MULTIPLIER, pt.y / FIXED_INT_MULTIPLIER);
+
+ for (uint idx = 0; idx < _scaleZones.size() && !found; ++idx) {
+ ScaleZone &sz = _scaleZones[idx];
+ if (sz.contains(pos)) {
+ int n = (sz._bottomNumber - sz._topNumber) * 100 / sz.height() * (pos.y - sz.top) / 100 + sz._topNumber;
+ result = 25600L / n;
+ // CHECKME: Shouldn't we set 'found' at this place?
+ }
+ }
+
+ // If it wasn't found, we may be off screen to the left or right, so find the scale zone
+ // that would apply to the y val passed in disregarding the x
+ if (!found) {
+ for (uint idx = 0; idx < _scaleZones.size() && !found; ++idx) {
+ ScaleZone &sz = _scaleZones[idx];
+ if (pos.y >= sz.top && pos.y < sz.bottom) {
+ int n = (sz._bottomNumber - sz._topNumber) * 100 / sz.height() * (pos.y - sz.top) / 100 + sz._topNumber;
+ result = 25600L / n;
+ }
+ }
+ }
+
+ return result;
+}
+
+int TattooScene::startCAnim(int cAnimNum, int playRate) {
+ TattooEngine &vm = *(TattooEngine *)_vm;
+ Events &events = *_vm->_events;
+ TattooPeople &people = *(TattooPeople *)_vm->_people;
+ Resources &res = *_vm->_res;
+ Talk &talk = *_vm->_talk;
+ UserInterface &ui = *_vm->_ui;
+
+ // Exit immediately if the anim number is out of range, or the anim doesn't have a position specified
+ if (cAnimNum < 0 || cAnimNum >= (int)_cAnim.size() || _cAnim[cAnimNum]._position.x == -1)
+ // Return out of range error
+ return -1;
+
+ // Get the co-ordinates that the Player & NPC #1 must walk to and end on
+ CAnim &cAnim = _cAnim[cAnimNum];
+ PositionFacing goto1 = cAnim._goto[0];
+ PositionFacing goto2 = cAnim._goto[1];
+ PositionFacing teleport1 = cAnim._teleport[0];
+ PositionFacing teleport2 = cAnim._teleport[1];
+
+ // See if the Player must walk to a position before the animation starts
+ SpriteType savedPlayerType = people[HOLMES]._type;
+ if (goto1.x != -1 && people[HOLMES]._type == CHARACTER) {
+ if (people[HOLMES]._position != goto1)
+ people[HOLMES].walkToCoords(goto1, goto1._facing);
+ }
+
+ if (talk._talkToAbort)
+ return 1;
+
+ // See if NPC #1 must walk to a position before the animation starts
+ SpriteType savedNPCType = people[WATSON]._type;
+ if (goto2.x != -1 && people[WATSON]._type == CHARACTER) {
+ if (people[WATSON]._position != goto2)
+ people[WATSON].walkToCoords(goto2, goto2._facing);
+ }
+
+ if (talk._talkToAbort)
+ return 1;
+
+ // Turn the player (and NPC #1 if neccessary) off before running the canimation
+ if (teleport1.x != -1 && savedPlayerType == CHARACTER)
+ people[HOLMES]._type = REMOVE;
+
+ if (teleport2.x != -1 && savedNPCType == CHARACTER)
+ people[WATSON]._type = REMOVE;
+
+ 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);
+ stream->seek(stream->readUint32LE());
+ Common::SeekableReadStream *animStream = stream->readStream(cAnim._dataSize);
+ delete stream;
+
+ // Set up the active animation
+ _activeCAnim._position = cAnim._position;
+ _activeCAnim._oldBounds = Common::Rect(0, 0, 0, 0);
+ _activeCAnim._flags = cAnim._flags;
+ _activeCAnim._scaleVal = cAnim._scaleVal;
+ _activeCAnim._zPlacement = 0;
+
+ _activeCAnim.load(animStream, _compressed);
+
+ while (!_vm->shouldQuit()) {
+ // Get the next frame
+ if (!_activeCAnim.getNextFrame())
+ break;
+
+ // Draw the frame
+ doBgAnim();
+
+ // Check for Escape key being pressed to abort animation
+ events.pollEvents();
+ if (events.kbHit()) {
+ Common::KeyState keyState = events.getKey();
+
+ if (keyState.keycode == Common::KEYCODE_ESCAPE && vm._runningProlog) {
+ _vm->setFlags(-76);
+ _vm->setFlags(396);
+ _goToScene = STARTING_GAME_SCENE;
+ talk._talkToAbort = true;
+ _activeCAnim.close();
+ }
+ }
+ }
+
+ // Turn the people back on
+ people[HOLMES]._type = savedPlayerType;
+ if (teleport2.x != -1)
+ people[WATSON]._type = savedNPCType;
+
+ // Teleport the Player to the ending coordinates if necessary
+ if (teleport1.x != -1 && savedPlayerType == CHARACTER) {
+ people[HOLMES]._position = teleport1;
+ people[HOLMES]._sequenceNumber = teleport1._facing;
+ people[HOLMES].gotoStand();
+ }
+
+ // Teleport Watson to the ending coordinates if necessary
+ if (teleport2.x != -1 && savedNPCType == CHARACTER) {
+ people[WATSON]._position = teleport2;
+ people[WATSON]._sequenceNumber = teleport2._facing;
+ people[WATSON].gotoStand();
+ }
+
+ // Flag the Canimation to be cleared
+ _activeCAnim._zPlacement = REMOVE;
+ _activeCAnim._removeBounds = _activeCAnim._oldBounds;
+
+ // Free up the animation
+ _activeCAnim.close();
+
+ return 1;
+}
+
+void TattooScene::setNPCPath(int npc) {
+ TattooPeople &people = *(TattooPeople *)_vm->_people;
+ SaveManager &saves = *_vm->_saves;
+ Talk &talk = *_vm->_talk;
+
+ // Don't do initial scene setup if a savegame has just been loaded
+ if (saves._justLoaded)
+ return;
+
+ people[npc].clearNPC();
+ people[npc]._npcName = Common::String::format("WATS%.2dA", _currentScene);
+
+ // If we're in the middle of a script that will continue once the scene is loaded,
+ // return without calling the path script
+ if (talk._scriptMoreFlag == 1 || talk._scriptMoreFlag == 3)
+ return;
+
+ // Turn off all the NPCs, since the talk script will turn them back on as needed
+ for (int idx = 1; idx < MAX_CHARACTERS; ++idx)
+ people[idx]._type = INVALID;
+
+ // Call the path script for the scene
+ Common::String pathFile = Common::String::format("PATH%.2dA", _currentScene);
+ talk.talkTo(pathFile);
+}
+
+int TattooScene::findBgShape(const Common::Point &pt) {
+ People &people = *_vm->_people;
+ UserInterface &ui = *_vm->_ui;
+
+ if (!_doBgAnimDone)
+ // New frame hasn't been drawn yet
+ return -1;
+
+ int result = -1;
+ for (int idx = (int)_bgShapes.size() - 1; idx >= 0 && result == -1; --idx) {
+ Object &o = _bgShapes[idx];
+
+ if (o._type != INVALID && o._type != NO_SHAPE && o._type != HIDDEN &&
+ (o._aType <= PERSON || (ui._menuMode == LAB_MODE && o._aType == SOLID))) {
+ if (o.getNewBounds().contains(pt))
+ result = idx;
+ } else if (o._type == NO_SHAPE) {
+ if (o.getNoShapeBounds().contains(pt))
+ result = idx;
+ }
+ }
+
+ // Now check for the mouse being over an NPC. If so, it overrides any found bg object
+ for (int idx = 1; idx < MAX_CHARACTERS; ++idx) {
+ Person &person = people[idx];
+
+ if (person._type == CHARACTER) {
+ int scaleVal = getScaleVal(person._position);
+ Common::Rect charRect;
+
+ if (scaleVal == SCALE_THRESHOLD)
+ charRect = Common::Rect(person.frameWidth(), person.frameHeight());
+ else
+ charRect = Common::Rect(person._imageFrame->sDrawXSize(scaleVal), person._imageFrame->sDrawYSize(scaleVal));
+ charRect.moveTo(person._position.x / FIXED_INT_MULTIPLIER, person._position.y / FIXED_INT_MULTIPLIER
+ - charRect.height());
+
+ if (charRect.contains(pt))
+ result = 1000 + idx;
+ }
+ }
+
+ return result;
+}
+
+void TattooScene::synchronize(Serializer &s) {
+ TattooEngine &vm = *(TattooEngine *)_vm;
+ TattooUserInterface &ui = *(TattooUserInterface *)_vm->_ui;
+ Scene::synchronize(s);
+
+ if (s.isLoading()) {
+ // In case we were showing the intro prologue or the ending credits, stop them
+ vm._runningProlog = false;
+ ui._creditsWidget.close();
+ }
+}
+
+int TattooScene::closestZone(const Common::Point &pt) {
+ int zone = -1;
+ int dist = 9999;
+ int d;
+
+ for (uint idx = 0; idx < _zones.size(); ++idx) {
+ Common::Rect &r = _zones[idx];
+
+ // Check the distance from the point to the center of the zone
+ d = ABS(r.left + (r.width() / 2) - pt.x) + ABS(r.top + (r.height() / 2) - pt.y);
+ if (d < dist) {
+ dist = d;
+ zone = idx;
+ }
+
+ // Check the distance from the point to the upper left of the zone
+ d = ABS((int)(r.left - pt.x)) + ABS((int)(r.top - pt.y));
+ if (d < dist)
+ {
+ dist = d;
+ zone = idx;
+ }
+
+ // Check the distance from the point to the upper right of the zone
+ d = ABS(r.left + r.width() - pt.x) + ABS(r.top - pt.y);
+ if (d < dist) {
+ dist = d;
+ zone = idx;
+ }
+
+ // Check the distance from the point to the lower left of the zone
+ d = ABS(r.left - pt.x) + ABS(r.top + r.height() - pt.y);
+ if (d < dist) {
+ dist = d;
+ zone = idx;
+ }
+
+ // Check the distance from the point to the lower right of the zone
+ d = ABS(r.left + r.width() - pt.x) + ABS(r.top + r.height() - pt.y);
+ if (d < dist) {
+ dist = d;
+ zone = idx;
+ }
+ }
+
+ return zone;
+}
} // End of namespace Tattoo
diff --git a/engines/sherlock/tattoo/tattoo_scene.h b/engines/sherlock/tattoo/tattoo_scene.h
index de28306c1b..678330077c 100644
--- a/engines/sherlock/tattoo/tattoo_scene.h
+++ b/engines/sherlock/tattoo/tattoo_scene.h
@@ -25,39 +25,104 @@
#include "common/scummsys.h"
#include "sherlock/scene.h"
+#include "sherlock/tattoo/widget_lab.h"
namespace Sherlock {
namespace Tattoo {
+extern const int FS_TRANS[8];
+
+enum {
+ STARTING_GAME_SCENE = 1, WEARY_PUNT = 52, TRAIN_RIDE = 69, STARTING_INTRO_SCENE = 91, OVERHEAD_MAP2 = 90, OVERHEAD_MAP = 100
+};
+
+struct SceneTripEntry {
+ int _flag;
+ int _sceneNumber;
+ int _numTimes;
+
+ SceneTripEntry() : _flag(0), _sceneNumber(0), _numTimes(0) {}
+ SceneTripEntry(int flag, int sceneNumber, int numTimes) : _flag(flag),
+ _sceneNumber(sceneNumber), _numTimes(numTimes) {}
+};
+
class TattooScene : public Scene {
private:
- int _arrowZone;
- int _maskCounter;
- Common::Point _maskOffset;
-private:
- void doBgAnimCheckCursor();
+ WidgetLab _labWidget;
- void doBgAnimEraseBackground();
+ void doBgAnimCheckCursor();
/**
* Update the background objects and canimations as part of doBgAnim
*/
void doBgAnimUpdateBgObjectsAndAnim();
+
+ void doBgAnimDrawSprites();
+
+ /**
+ * Resets the NPC path information when entering a new scene.
+ * @remarks The default talk file for the given NPC is set to WATS##A, where ## is
+ * the scene number being entered
+ */
+ void setNPCPath(int npc);
protected:
/**
+ * Loads the data associated for a given scene. The room resource file's format is:
+ * BGHEADER: Holds an index for the rest of the file
+ * STRUCTS: The objects for the scene
+ * IMAGES: The graphic information for the structures
+ *
+ * The _misc field of the structures contains the number of the graphic image
+ * that it should point to after loading; _misc is then set to 0.
+ */
+ virtual bool loadScene(const Common::String &filename);
+
+ /**
* Checks all the background shapes. If a background shape is animating,
* it will flag it as needing to be drawn. If a non-animating shape is
* colliding with another shape, it will also flag it as needing drawing
*/
virtual void checkBgShapes();
+
+ /**
+ * Draw all the shapes, people and NPCs in the correct order
+ */
+ virtual void drawAllShapes();
+
+ /**
+ * Called by loadScene when the palette is loaded for Rose Tattoo
+ */
+ virtual void paletteLoaded();
+
+ /**
+ * Synchronize the data for a savegame
+ */
+ virtual void synchronize(Serializer &s);
+
+ /**
+ * Returns the index of the closest zone to a given point.
+ */
+ virtual int closestZone(const Common::Point &pt);
public:
- ImageFile *_mask, *_mask1;
- CAnimStream _activeCAnim;
+ StreamingImageFile _activeCAnim;
+ Common::Array<SceneTripEntry> _sceneTripCounters;
+ bool _labTableScene;
public:
TattooScene(SherlockEngine *vm);
/**
+ * Returns the scale value for the passed co-ordinates. This is taken from the scene's
+ * scale zones, interpolating inbetween the top and bottom values of the zones as needed
+ */
+ int getScaleVal(const Point32 &pt);
+
+ /**
+ * Fres all the graphics and other dynamically allocated data for the scene
+ */
+ virtual void freeScene();
+
+ /**
* Draw all objects and characters.
*/
virtual void doBgAnim();
@@ -68,6 +133,21 @@ public:
*/
virtual void updateBackground();
+ /**
+ * Attempt to start a canimation sequence. It will load the requisite graphics, and
+ * then copy the canim object into the _canimShapes array to start the animation.
+ *
+ * @param cAnimNum The canim object within the current scene
+ * @param playRate Play rate. 0 is invalid; 1=normal speed, 2=1/2 speed, etc.
+ * A negative playRate can also be specified to play the animation in reverse
+ */
+ virtual int startCAnim(int cAnimNum, int playRate = 1);
+
+ /**
+ * Attempts to find a background shape within the passed bounds. If found,
+ * it will return the shape number, or -1 on failure.
+ */
+ virtual int findBgShape(const Common::Point &pt);
};
} // End of namespace Tattoo
diff --git a/engines/sherlock/tattoo/tattoo_talk.cpp b/engines/sherlock/tattoo/tattoo_talk.cpp
new file mode 100644
index 0000000000..a4ceca042b
--- /dev/null
+++ b/engines/sherlock/tattoo/tattoo_talk.cpp
@@ -0,0 +1,1013 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public 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_talk.h"
+#include "sherlock/tattoo/tattoo_fixed_text.h"
+#include "sherlock/tattoo/tattoo_people.h"
+#include "sherlock/tattoo/tattoo_scene.h"
+#include "sherlock/tattoo/tattoo_user_interface.h"
+#include "sherlock/tattoo/tattoo.h"
+#include "sherlock/screen.h"
+
+namespace Sherlock {
+
+namespace Tattoo {
+
+static const uint8 DIRECTION_CONVERSION[] = {
+ WALK_RIGHT, WALK_DOWN, WALK_LEFT, WALK_UP, STOP_RIGHT, STOP_DOWN, STOP_LEFT, STOP_UP,
+ WALK_UPRIGHT, WALK_DOWNRIGHT, WALK_UPLEFT, WALK_DOWNLEFT, STOP_UPRIGHT, STOP_UPLEFT,
+ STOP_DOWNRIGHT, STOP_DOWNLEFT
+};
+
+const byte TATTOO_OPCODES[] = {
+ 170, // OP_SWITCH_SPEAKER
+ 171, // OP_RUN_CANIMATION
+ 0, // OP_ASSIGN_PORTRAIT_LOCATION
+ 173, // OP_PAUSE
+ 0, // OP_REMOVE_PORTRAIT
+ 0, // OP_CLEAR_WINDOW
+ 176, // OP_ADJUST_OBJ_SEQUENCE
+ 177, // OP_WALK_HOlMES_TO_COORDS
+ 178, // OP_PAUSE_WITHOUT_CONTROL
+ 179, // OP_BANISH_WINDOW
+ 0, // OP_SUMMON_WINDOW
+ 181, // OP_SET_FLAG
+ 0, // OP_SFX_COMMAND
+ 183, // OP_TOGGLE_OBJECT
+ 184, // OP_STEALTH_MODE_ACTIVE
+ 0, // OP_IF_STATEMENT
+ 0, // OP_ELSE_STATEMENT
+ 0, // OP_END_IF_STATEMENT
+ 188, // OP_STEALTH_MODE_DEACTIVATE
+ 189, // OP_TURN_HOLMES_OFF
+ 190, // OP_TURN_HOLMES_ON
+ 191, // OP_GOTO_SCENE
+ 0, // OP_PLAY_PROLOGUE
+ 193, // OP_ADD_ITEM_TO_INVENTORY
+ 194, // OP_SET_OBJECT
+ 172, // OP_CALL_TALK_FILE
+ 0, // OP_MOVE_MOUSE
+ 0, // OP_DISPLAY_INFO_LINE
+ 0, // OP_CLEAR_INFO_LINE
+ 199, // OP_WALK_TO_CANIMATION
+ 200, // OP_REMOVE_ITEM_FROM_INVENTORY
+ 201, // OP_ENABLE_END_KEY
+ 202, // OP_DISABLE_END_KEY
+ 203, // OP_END_TEXT_WINDOW
+ 174, // OP_MOUSE_ON_OFF
+ 175, // OP_SET_WALK_CONTROL
+ 180, // OP_SET_TALK_SEQUENCE
+ 182, // OP_PLAY_SONG
+ 187, // OP_WALK_HOLMES_AND_NPC_TO_CANIM
+ 192, // OP_SET_NPC_PATH_DEST
+ 195, // OP_NEXT_SONG
+ 196, // OP_SET_NPC_PATH_PAUSE
+ 197, // OP_PASSWORD
+ 198, // OP_SET_SCENE_ENTRY_FLAG
+ 185, // OP_WALK_NPC_TO_CANIM
+ 186, // OP_WALK_NPC_TO_COORDS
+ 204, // OP_WALK_HOLMES_AND_NPC_TO_COORDS
+ 205, // OP_SET_NPC_TALK_FILE
+ 206, // OP_TURN_NPC_OFF
+ 207, // OP_TURN_NPC_ON
+ 208, // OP_NPC_DESC_ON_OFF
+ 209, // OP_NPC_PATH_PAUSE_TAKING_NOTES
+ 210, // OP_NPC_PATH_PAUSE_LOOKING_HOLMES
+ 211, // OP_ENABLE_TALK_INTERRUPTS
+ 212, // OP_DISABLE_TALK_INTERRUPTS
+ 213, // OP_SET_NPC_INFO_LINE
+ 214, // OP_SET_NPC_POSITION
+ 215, // OP_NPC_PATH_LABEL
+ 216, // OP_PATH_GOTO_LABEL
+ 217, // OP_PATH_IF_FLAG_GOTO_LABEL
+ 218, // OP_NPC_WALK_GRAPHICS
+ 220, // OP_NPC_VERB
+ 221, // OP_NPC_VERB_CANIM
+ 222, // OP_NPC_VERB_SCRIPT
+ 224, // OP_RESTORE_PEOPLE_SEQUENCE
+ 226, // OP_NPC_VERB_TARGET
+ 227, // OP_TURN_SOUNDS_OFF
+ 225 // OP_NULL
+};
+
+/*----------------------------------------------------------------*/
+
+TattooTalk::TattooTalk(SherlockEngine *vm) : Talk(vm), _talkWidget(vm), _passwordWidget(vm) {
+ static OpcodeMethod OPCODE_METHODS[] = {
+ (OpcodeMethod)&TattooTalk::cmdSwitchSpeaker,
+
+ (OpcodeMethod)&TattooTalk::cmdRunCAnimation,
+ (OpcodeMethod)&TattooTalk::cmdCallTalkFile,
+ (OpcodeMethod)&TattooTalk::cmdPause,
+ (OpcodeMethod)&TattooTalk::cmdMouseOnOff,
+ (OpcodeMethod)&TattooTalk::cmdSetWalkControl,
+ (OpcodeMethod)&TattooTalk::cmdAdjustObjectSequence,
+ (OpcodeMethod)&TattooTalk::cmdWalkHolmesToCoords,
+ (OpcodeMethod)&TattooTalk::cmdPauseWithoutControl,
+ (OpcodeMethod)&TattooTalk::cmdBanishWindow,
+ (OpcodeMethod)&TattooTalk::cmdSetTalkSequence,
+
+ (OpcodeMethod)&TattooTalk::cmdSetFlag,
+ (OpcodeMethod)&TattooTalk::cmdPlaySong,
+ (OpcodeMethod)&TattooTalk::cmdToggleObject,
+ (OpcodeMethod)&TattooTalk::cmdStealthModeActivate,
+ (OpcodeMethod)&TattooTalk::cmdWalkNPCToCAnimation,
+ (OpcodeMethod)&TattooTalk::cmdWalkNPCToCoords,
+ (OpcodeMethod)&TattooTalk::cmdWalkHomesAndNPCToCoords,
+ (OpcodeMethod)&TattooTalk::cmdStealthModeDeactivate,
+ (OpcodeMethod)&TattooTalk::cmdHolmesOff,
+ (OpcodeMethod)&TattooTalk::cmdHolmesOn,
+
+ (OpcodeMethod)&TattooTalk::cmdGotoScene,
+ (OpcodeMethod)&TattooTalk::cmdSetNPCPathDest,
+ (OpcodeMethod)&TattooTalk::cmdAddItemToInventory,
+ (OpcodeMethod)&TattooTalk::cmdSetObject,
+ (OpcodeMethod)&TattooTalk::cmdNextSong,
+ (OpcodeMethod)&TattooTalk::cmdSetNPCPathPause,
+ (OpcodeMethod)&TattooTalk::cmdPassword,
+ (OpcodeMethod)&TattooTalk::cmdSetSceneEntryFlag,
+ (OpcodeMethod)&TattooTalk::cmdWalkToCAnimation,
+ (OpcodeMethod)&TattooTalk::cmdRemoveItemFromInventory,
+
+ (OpcodeMethod)&TattooTalk::cmdEnableEndKey,
+ (OpcodeMethod)&TattooTalk::cmdDisableEndKey,
+ (OpcodeMethod)&TattooTalk::cmdEndTextWindow,
+ (OpcodeMethod)&TattooTalk::cmdWalkHomesAndNPCToCoords,
+ (OpcodeMethod)&TattooTalk::cmdSetNPCTalkFile,
+ (OpcodeMethod)&TattooTalk::cmdSetNPCOff,
+ (OpcodeMethod)&TattooTalk::cmdSetNPCOn,
+ (OpcodeMethod)&TattooTalk::cmdSetNPCDescOnOff,
+ (OpcodeMethod)&TattooTalk::cmdSetNPCPathPauseTakingNotes,
+ (OpcodeMethod)&TattooTalk::cmdSetNPCPathPauseLookingHolmes,
+
+ (OpcodeMethod)&TattooTalk::cmdTalkInterruptsEnable,
+ (OpcodeMethod)&TattooTalk::cmdTalkInterruptsDisable,
+ (OpcodeMethod)&TattooTalk::cmdSetNPCInfoLine,
+ (OpcodeMethod)&TattooTalk::cmdSetNPCPosition,
+ (OpcodeMethod)&TattooTalk::cmdNPCLabelSet,
+ (OpcodeMethod)&TattooTalk::cmdNPCLabelGoto,
+ (OpcodeMethod)&TattooTalk::cmdNPCLabelIfFlagGoto,
+ (OpcodeMethod)&TattooTalk::cmdSetNPCWalkGraphics,
+ nullptr,
+ (OpcodeMethod)&TattooTalk::cmdSetNPCVerb,
+
+ (OpcodeMethod)&TattooTalk::cmdSetNPCVerbCAnimation,
+ (OpcodeMethod)&TattooTalk::cmdSetNPCVerbScript,
+ nullptr,
+ (OpcodeMethod)&TattooTalk::cmdRestorePeopleSequence,
+ nullptr,
+ (OpcodeMethod)&TattooTalk::cmdSetNPCVerbTarget,
+ (OpcodeMethod)&TattooTalk::cmdTurnSoundsOff
+ };
+
+ _opcodes = TATTOO_OPCODES;
+ _opcodeTable = OPCODE_METHODS;
+}
+
+void TattooTalk::talkTo(const Common::String filename) {
+ Events &events = *_vm->_events;
+ TattooUserInterface &ui = *(TattooUserInterface *)_vm->_ui;
+
+ // WORKAROUND: Keep wait cursor active until very end of the cutscene of the monkey
+ // stealing the cap, which is finished by calling the 30cuend script
+ if (filename == "wilb29a")
+ events.incWaitCounter();
+
+ Talk::talkTo(filename);
+
+ if (filename == "wilb29a")
+ ui._menuMode = TALK_MODE;
+ if (filename == "30cuend") {
+ events.decWaitCounter();
+ events.setCursor(ARROW);
+ }
+}
+
+void TattooTalk::talkInterface(const byte *&str) {
+ TattooEngine &vm = *(TattooEngine *)_vm;
+ Sound &sound = *_vm->_sound;
+ TattooUserInterface &ui = *(TattooUserInterface *)_vm->_ui;
+ const byte *s = str;
+
+ // Move to past the end of the text string
+ _wait = 1;
+ _charCount = 0;
+ while ((*str < TATTOO_OPCODES[0] || *str == TATTOO_OPCODES[OP_NULL]) && *str) {
+ ++_charCount;
+ ++str;
+ }
+
+ // If speech is on, and text windows (subtitles) are off, then don't show the text window
+ if (!vm._textWindowsOn && sound._speechOn && _speaker != -1)
+ return;
+
+ // Display the text window
+ ui.banishWindow();
+ ui._textWidget.load(Common::String((const char *)s, (const char *)str), _speaker);
+ ui._textWidget.summonWindow();
+}
+
+void TattooTalk::nothingToSay() {
+ TattooUserInterface &ui = *(TattooUserInterface *)_vm->_ui;
+ ui.putMessage("%s", FIXED(NothingToSay));
+}
+
+void TattooTalk::showTalk() {
+ TattooPeople &people = *(TattooPeople *)_vm->_people;
+ TattooUserInterface &ui = *(TattooUserInterface *)_vm->_ui;
+
+ people.setListenSequence(_talkTo, 129);
+
+ _talkWidget.load();
+ _talkWidget.summonWindow();
+ _talkWidget.refresh();
+
+ if (ui._menuMode != MESSAGE_MODE)
+ ui._menuMode = TALK_MODE;
+}
+
+OpcodeReturn TattooTalk::cmdSwitchSpeaker(const byte *&str) {
+ TattooPeople &people = *(TattooPeople *)_vm->_people;
+ Screen &screen = *_vm->_screen;
+ UserInterface &ui = *_vm->_ui;
+
+ if (_talkToAbort)
+ return RET_EXIT;
+
+ ui.clearWindow();
+
+ _yp = screen.fontHeight() + 11;
+ _charCount = _line = 0;
+
+ people.setListenSequence(_speaker, 129);
+ _speaker = *++str - 1;
+ ++str;
+
+ people.setTalkSequence(_speaker, 1);
+
+ return RET_SUCCESS;
+}
+
+OpcodeReturn TattooTalk::cmdMouseOnOff(const byte *&str) {
+ Events &events = *_vm->_events;
+ bool mouseOn = *++str == 2;
+ if (mouseOn)
+ events.showCursor();
+ else
+ events.hideCursor();
+ return RET_SUCCESS;
+}
+
+OpcodeReturn TattooTalk::cmdWalkHolmesToCoords(const byte *&str) {
+ People &people = *_vm->_people;
+ ++str;
+
+ int xp = (str[0] - 1) * 256 + str[1] - 1;
+ if (xp > 16384)
+ // Negative X
+ xp = -1 * (xp - 16384);
+ int yp = (str[2] - 1) * 256 + str[3] - 1;
+
+ people[HOLMES].walkToCoords(Point32(xp * FIXED_INT_MULTIPLIER, yp * FIXED_INT_MULTIPLIER),
+ DIRECTION_CONVERSION[str[4] - 1]);
+
+ if (_talkToAbort)
+ return RET_EXIT;
+
+ str += 4;
+ return RET_SUCCESS;
+}
+
+OpcodeReturn TattooTalk::cmdGotoScene(const byte *&str) {
+ Map &map = *_vm->_map;
+ TattooPeople &people = *(TattooPeople *)_vm->_people;
+ Scene &scene = *_vm->_scene;
+ scene._goToScene = str[1] - 1;
+
+ if (scene._goToScene != OVERHEAD_MAP) {
+ // Not going to the map overview
+ map._oldCharPoint = scene._goToScene;
+
+ // Run a canimation?
+ if (str[2] > 100) {
+ people._savedPos = PositionFacing(160, 100, str[2]);
+ } else {
+ int posX = (str[3] - 1) * 256 + str[4] - 1;
+ if (posX > 16384)
+ posX = -1 * (posX - 16384);
+ int posY = (str[5] - 1) * 256 + str[6] - 1;
+ people._savedPos = PositionFacing(posX, posY, str[2] - 1);
+ }
+
+ _scriptMoreFlag = 1;
+ }
+
+ str += 7;
+ if (scene._goToScene != OVERHEAD_MAP)
+ _scriptSaveIndex = str - _scriptStart;
+
+ _endStr = true;
+ _wait = 0;
+
+ return RET_SUCCESS;
+}
+
+OpcodeReturn TattooTalk::cmdNextSong(const byte *&str) {
+ Music &music = *_vm->_music;
+
+ // Get the name of the next song to play
+ ++str;
+ music._nextSongName = "";
+ for (int idx = 0; idx < 8 && str[idx] != '~'; ++idx)
+ music._nextSongName += str[idx];
+ str += 7;
+
+ return RET_SUCCESS;
+}
+
+OpcodeReturn TattooTalk::cmdNPCLabelGoto(const byte *&str) {
+ int npcNum = *++str;
+ TattooPeople &people = *(TattooPeople *)_vm->_people;
+ TattooPerson &person = people[npcNum];
+
+ if (person._resetNPCPath) {
+ person._npcIndex = person._npcPause = 0;
+ person._resetNPCPath = false;
+ memset(person._npcPath, 0, 100);
+ }
+
+ person._npcPath[person._npcIndex] = 8;
+ person._npcPath[person._npcIndex + 1] = str[1];
+ person._npcIndex += 2;
+ str++;
+
+ return RET_SUCCESS;
+}
+
+OpcodeReturn TattooTalk::cmdNPCLabelIfFlagGoto(const byte *&str) {
+ int npcNum = *++str;
+ TattooPeople &people = *(TattooPeople *)_vm->_people;
+ TattooPerson &person = people[npcNum];
+
+ if (person._resetNPCPath) {
+ person._npcIndex = person._npcPause = 0;
+ person._resetNPCPath = false;
+ memset(person._npcPath, 0, 100);
+ }
+
+ person._npcPath[person._npcIndex] = 9;
+ for (int i = 1; i <= 3; i++)
+ person._npcPath[person._npcIndex + i] = str[i];
+
+ person._npcIndex += 4;
+ str += 3;
+
+ return RET_SUCCESS;
+}
+
+OpcodeReturn TattooTalk::cmdNPCLabelSet(const byte *&str) {
+ int npcNum = *++str;
+ TattooPeople &people = *(TattooPeople *)_vm->_people;
+ TattooPerson &person = people[npcNum];
+
+ if (person._resetNPCPath) {
+ person._npcIndex = person._npcPause = 0;
+ person._resetNPCPath = false;
+ memset(person._npcPath, 0, 100);
+ }
+
+ person._npcPath[person._npcIndex] = 7;
+ person._npcPath[person._npcIndex + 1] = str[1];
+ person._npcIndex += 2;
+ str++;
+
+ return RET_SUCCESS;
+}
+
+OpcodeReturn TattooTalk::cmdPassword(const byte *&str) {
+ _vm->_ui->clearWindow();
+ _passwordWidget.show();
+ return RET_EXIT;
+}
+
+OpcodeReturn TattooTalk::cmdPlaySong(const byte *&str) {
+ Music &music = *_vm->_music;
+ Common::String currentSong = music._currentSongName;
+
+ // Get the name of the song to play
+ music._currentSongName = "";
+ str++;
+ for (int idx = 0; idx < 8 && str[idx] != '~'; ++idx)
+ music._currentSongName += str[idx];
+ str += 7;
+
+ // Play the song
+ music.loadSong(music._currentSongName);
+
+ // Copy the old song name to _nextSongName so that when the new song is finished, the old song will restart
+ music._nextSongName = currentSong;
+
+ return RET_SUCCESS;
+}
+
+OpcodeReturn TattooTalk::cmdRestorePeopleSequence(const byte *&str) {
+ int npcNum = *++str - 1;
+ TattooPeople &people = *(TattooPeople *)_vm->_people;
+ TattooPerson &person = people[npcNum];
+ person._misc = 0;
+
+ if (person._seqTo) {
+ person._walkSequences[person._sequenceNumber]._sequences[person._frameNumber] = person._seqTo;
+ person._seqTo = 0;
+ }
+ person._sequenceNumber = person._savedNpcSequence;
+ person._frameNumber = person._savedNpcFrame;
+ person.checkWalkGraphics();
+
+ return RET_SUCCESS;
+}
+
+OpcodeReturn TattooTalk::cmdSetNPCDescOnOff(const byte *&str) {
+ int npcNum = *++str;
+ ++str;
+ TattooPeople &people = *(TattooPeople *)_vm->_people;
+ Person &person = people[npcNum];
+
+ // Copy over the NPC examine text until we reach a stop marker, which is
+ // the same as a start marker, or we reach the end of the file
+ person._examine = "";
+ while (*str && *str != _opcodes[OP_NPC_DESC_ON_OFF])
+ person._examine += *str++;
+
+ // Move past any leftover text till we reach a stop marker
+ while (*str && *str != _opcodes[OP_NPC_DESC_ON_OFF])
+ str++;
+
+ if (!*str)
+ // Reached end of file, so decrement pointer so outer loop will terminate on NULL
+ --str;
+ else
+ // Move past the ending OP_NPC_DEST_ON_OFF opcode
+ ++str;
+
+ return RET_SUCCESS;
+}
+
+OpcodeReturn TattooTalk::cmdSetNPCInfoLine(const byte *&str) {
+ int npcNum = *++str;
+ TattooPeople &people = *(TattooPeople *)_vm->_people;
+ TattooPerson &person = people[npcNum];
+
+ person._description = "";
+ int len = *++str;
+ for (int idx = 0; idx < len; ++idx)
+ person._description += str[idx + 1];
+
+ str += len;
+ return RET_SUCCESS;
+}
+
+OpcodeReturn TattooTalk::cmdSetNPCOff(const byte *&str) {
+ TattooPeople &people = *(TattooPeople *)_vm->_people;
+ int npcNum = *++str;
+ people[npcNum]._type = REMOVE;
+
+ return RET_SUCCESS;
+}
+
+OpcodeReturn TattooTalk::cmdSetNPCOn(const byte *&str) {
+ TattooPeople &people = *(TattooPeople *)_vm->_people;
+ int npcNum = *++str;
+ people[npcNum]._type = CHARACTER;
+
+ return RET_SUCCESS;
+}
+
+OpcodeReturn TattooTalk::cmdSetNPCPathDest(const byte *&str) {
+ int npcNum = *++str;
+ TattooPeople &people = *(TattooPeople *)_vm->_people;
+ TattooPerson &person = people[npcNum];
+
+ if (person._resetNPCPath) {
+ person._npcIndex = person._npcPause = 0;
+ person._resetNPCPath = false;
+ memset(person._npcPath, 0, 100);
+ }
+
+ person._npcPath[person._npcIndex] = 1;
+ for (int i = 1; i <= 4; i++)
+ person._npcPath[person._npcIndex + i] = str[i];
+ person._npcPath[person._npcIndex + 5] = DIRECTION_CONVERSION[str[5] - 1] + 1;
+
+ person._npcIndex += 6;
+ str += 5;
+
+ return RET_SUCCESS;
+}
+
+OpcodeReturn TattooTalk::cmdSetNPCPathPause(const byte *&str) {
+ int npcNum = *++str;
+ TattooPeople &people = *(TattooPeople *)_vm->_people;
+ TattooPerson &person = people[npcNum];
+
+ if (person._resetNPCPath) {
+ person._npcIndex = person._npcPause = 0;
+ person._resetNPCPath = false;
+ memset(person._npcPath, 0, 100);
+ }
+
+ person._npcPath[person._npcIndex] = 2;
+ for (int i = 1; i <= 2; i++)
+ person._npcPath[person._npcIndex + i] = str[i];
+
+ person._npcIndex += 3;
+ str += 2;
+
+ return RET_SUCCESS;
+}
+
+OpcodeReturn TattooTalk::cmdSetNPCPathPauseTakingNotes(const byte *&str) {
+ int npcNum = *++str;
+ TattooPeople &people = *(TattooPeople *)_vm->_people;
+ TattooPerson &person = people[npcNum];
+
+ if (person._resetNPCPath) {
+ person._npcIndex = person._npcPause = 0;
+ person._resetNPCPath = false;
+ memset(person._npcPath, 0, 100);
+ }
+
+ person._npcPath[person._npcIndex] = 5;
+ for (int i = 1; i <= 2; i++)
+ person._npcPath[person._npcIndex + i] = str[i];
+
+ person._npcIndex += 3;
+ str += 2;
+
+ return RET_SUCCESS;
+}
+
+OpcodeReturn TattooTalk::cmdSetNPCPathPauseLookingHolmes(const byte *&str) {
+ int npcNum = *++str;
+ TattooPeople &people = *(TattooPeople *)_vm->_people;
+ TattooPerson &person = people[npcNum];
+
+ if (person._resetNPCPath) {
+ person._npcIndex = person._npcPause = 0;
+ person._resetNPCPath = false;
+ memset(person._npcPath, 0, 100);
+ }
+
+ person._npcPath[person._npcIndex] = 6;
+ for (int i = 1; i <= 2; i++)
+ person._npcPath[person._npcIndex + i] = str[i];
+
+ person._npcIndex += 3;
+ str += 2;
+
+ return RET_SUCCESS;
+}
+
+OpcodeReturn TattooTalk::cmdSetNPCPosition(const byte *&str) {
+ int npcNum = *++str - 1;
+ ++str;
+ TattooPeople &people = *(TattooPeople *)_vm->_people;
+ TattooPerson &person = people[npcNum];
+ int posX = (str[0] - 1) * 256 + str[1] - 1;
+ if (posX > 16384)
+ posX = -1 * (posX - 16384);
+ int posY = (str[2] - 1) * 256 + str[3] - 1;
+
+ person._position = Point32(posX * FIXED_INT_MULTIPLIER, posY * FIXED_INT_MULTIPLIER);
+ if (person._seqTo && person._walkLoaded) {
+ person._walkSequences[person._sequenceNumber]._sequences[person._frameNumber] = person._seqTo;
+ person._seqTo = 0;
+ }
+
+ assert(str[4] - 1 < 16);
+ person._sequenceNumber = DIRECTION_CONVERSION[str[4] - 1];
+ person._frameNumber = 0;
+
+ if (person._walkLoaded)
+ person.checkWalkGraphics();
+
+ if (person._walkLoaded && person._type == CHARACTER &&
+ person._sequenceNumber >= STOP_UP && person._sequenceNumber <= STOP_UPLEFT) {
+ bool done = false;
+ do {
+ person.checkSprite();
+ for (int x = 0; x < person._frameNumber; x++) {
+ if (person._walkSequences[person._sequenceNumber]._sequences[x] == 0) {
+ done = true;
+ break;
+ }
+ }
+ } while (!done);
+ }
+
+ str += 4;
+
+ return RET_SUCCESS;
+}
+
+OpcodeReturn TattooTalk::cmdSetNPCTalkFile(const byte *&str) {
+ int npcNum = *++str;
+ TattooPeople &people = *(TattooPeople *)_vm->_people;
+ TattooPerson &person = people[npcNum];
+
+ if (person._resetNPCPath) {
+ person._npcIndex = person._npcPause = 0;
+ person._resetNPCPath = false;
+ memset(person._npcPath, 0, 100);
+ }
+
+ person._npcPath[person._npcIndex] = NPCPATH_SET_TALK_FILE;
+ for (int i = 1; i <= 8; i++)
+ person._npcPath[person._npcIndex + i] = str[i];
+
+ person._npcIndex += 9;
+ str += 8;
+
+ return RET_SUCCESS;
+}
+
+OpcodeReturn TattooTalk::cmdSetNPCVerb(const byte *&str) {
+ int npcNum = *++str;
+ int verbNum = *++str - 1;
+ TattooPeople &people = *(TattooPeople *)_vm->_people;
+ Common::String &verb = people[npcNum]._use[verbNum]._verb;
+
+ // Get the verb name
+ verb = "";
+ for (int idx = 0; idx < 12 && str[idx + 1] != '~'; ++idx)
+ verb += str[idx + 1];
+
+ // Strip off any trailing whitespace
+ while (verb.hasSuffix(" "))
+ verb.deleteLastChar();
+
+ str += 12;
+ return RET_SUCCESS;
+}
+
+OpcodeReturn TattooTalk::cmdSetNPCVerbCAnimation(const byte *&str) {
+ int npcNum = *++str;
+ int verbNum = *++str - 1;
+ TattooPeople &people = *(TattooPeople *)_vm->_people;
+ UseType &useType = people[npcNum]._use[verbNum];
+
+ useType._cAnimNum = (str[1] - 1) & 127;
+ useType._cAnimSpeed = 1 + 128 * (str[1] >= 128);
+ str++;
+
+ return RET_SUCCESS;
+}
+
+OpcodeReturn TattooTalk::cmdSetNPCVerbScript(const byte *&str) {
+ int npcNum = *++str;
+ int verbNum = *++str - 1;
+ TattooPeople &people = *(TattooPeople *)_vm->_people;
+ UseType &useType = people[npcNum]._use[verbNum];
+
+ Common::String &name = useType._names[0];
+ name = "*C";
+
+ for (int idx = 0; idx < 8 && str[idx + 1] != '~'; ++idx)
+ name += str[idx + 1];
+
+ useType._cAnimNum = 99;
+ useType._cAnimSpeed = 1;
+ str += 8;
+
+ return RET_SUCCESS;
+}
+
+OpcodeReturn TattooTalk::cmdSetNPCVerbTarget(const byte *&str) {
+ int npcNum = *++str;
+ int verbNum = *++str - 1;
+ TattooPeople &people = *(TattooPeople *)_vm->_people;
+ Common::String &target = people[npcNum]._use[verbNum]._target;
+
+ target = "";
+ for (int idx = 0; idx < 12 && str[idx + 1] != '~'; ++idx)
+ target += str[idx + 1];
+
+ while (target.hasSuffix(" "))
+ target.deleteLastChar();
+
+ str += 12;
+ return RET_SUCCESS;
+}
+
+OpcodeReturn TattooTalk::cmdSetNPCWalkGraphics(const byte *&str) {
+ int npcNum = *++str - 1;
+ TattooPeople &people = *(TattooPeople *)_vm->_people;
+ Person &person = people[npcNum];
+
+ // Build up walk library name for the given NPC
+ person._walkVGSName = "";
+ for (int idx = 0; idx < 8 && str[idx + 1] != '~'; ++idx)
+ person._walkVGSName += str[idx + 1];
+
+ person._walkVGSName += ".VGS";
+ people._forceWalkReload = true;
+ str += 8;
+
+ return RET_SUCCESS;
+}
+
+OpcodeReturn TattooTalk::cmdSetSceneEntryFlag(const byte *&str) {
+ TattooScene &scene = *(TattooScene *)_vm->_scene;
+ ++str;
+ int flag = (str[0] - 1) * 256 + str[1] - 1 - (str[1] == 1);
+
+ int flag1 = flag & 16383;
+ if (flag > 16383)
+ flag1 *= -1;
+
+ str += 2;
+
+ // Make sure that this instance is not already being tracked
+ bool found = false;
+ for (uint idx = 0; idx < scene._sceneTripCounters.size() && !found; ++idx) {
+ SceneTripEntry &entry = scene._sceneTripCounters[idx];
+ if (entry._flag == flag1 && entry._sceneNumber == str[0] - 1)
+ found = true;
+ }
+
+ // Only add it if it's not being tracked already
+ if (!found)
+ scene._sceneTripCounters.push_back(SceneTripEntry(flag1, str[0] - 1, str[1] - 1));
+
+ ++str;
+ return RET_SUCCESS;
+}
+
+OpcodeReturn TattooTalk::cmdSetTalkSequence(const byte *&str) {
+ TattooPeople &people = *(TattooPeople *)_vm->_people;
+ int speaker = str[1] - 1;
+ int sequenceNumber = str[2];
+
+ if (sequenceNumber < 128)
+ people.setTalkSequence(speaker, sequenceNumber);
+ else
+ people.setListenSequence(speaker, sequenceNumber);
+
+ str += 2;
+
+ return RET_SUCCESS;
+}
+
+OpcodeReturn TattooTalk::cmdSetWalkControl(const byte *&str) {
+ TattooPeople &people = *(TattooPeople *)_vm->_people;
+ ++str;
+ people._walkControl = str[0] - 1;
+
+ return RET_SUCCESS;
+}
+
+// Dummy opcode
+OpcodeReturn TattooTalk::cmdTalkInterruptsDisable(const byte *&str) { error("Dummy opcode cmdTalkInterruptsDisable called"); }
+
+// 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::cmdWalkHolmesAndNPCToCAnimation(const byte *&str) {
+ int npcNum = *++str;
+ int cAnimNum = *++str;
+ TattooPeople &people = *(TattooPeople *)_vm->_people;
+ TattooPerson &person = people[npcNum];
+ Scene &scene = *_vm->_scene;
+ CAnim &anim = scene._cAnim[cAnimNum];
+
+ if (person._pathStack.empty())
+ person.pushNPCPath();
+ person._npcMoved = true;
+
+ person.walkToCoords(anim._goto[1], anim._goto[1]._facing);
+
+ if (_talkToAbort)
+ return RET_EXIT;
+
+ return RET_SUCCESS;
+}
+
+OpcodeReturn TattooTalk::cmdWalkNPCToCAnimation(const byte *&str) {
+ int npcNum = *++str;
+ int cAnimNum = *++str;
+ TattooPeople &people = *(TattooPeople *)_vm->_people;
+ TattooPerson &person = people[npcNum];
+ Scene &scene = *_vm->_scene;
+ CAnim &anim = scene._cAnim[cAnimNum];
+
+ if (person._pathStack.empty())
+ person.pushNPCPath();
+ person._npcMoved = true;
+
+ person.walkToCoords(anim._goto[1], anim._goto[1]._facing);
+
+ if (_talkToAbort)
+ return RET_EXIT;
+
+ return RET_SUCCESS;
+}
+
+OpcodeReturn TattooTalk::cmdWalkNPCToCoords(const byte *&str) {
+ int npcNum = *++str;
+ str++;
+ TattooPeople &people = *(TattooPeople *)_vm->_people;
+ TattooPerson &person = people[npcNum];
+
+ if (person._pathStack.empty())
+ person.pushNPCPath();
+ person._npcMoved = true;
+
+ int xp = (str[0] - 1) * 256 + str[1] - 1;
+ if (xp > 16384)
+ xp = -1 * (xp - 16384);
+ int yp = (str[2] - 1) * 256 + str[3] - 1;
+
+ person.walkToCoords(Point32(xp * FIXED_INT_MULTIPLIER, yp * FIXED_INT_MULTIPLIER),
+ DIRECTION_CONVERSION[str[4] - 1]);
+ if (_talkToAbort)
+ return RET_EXIT;
+
+ str += 4;
+ return RET_SUCCESS;
+}
+
+OpcodeReturn TattooTalk::cmdWalkHomesAndNPCToCoords(const byte *&str) {
+ int npcNum = *++str;
+ str++;
+ TattooPeople &people = *(TattooPeople *)_vm->_people;
+ TattooPerson &person = people[npcNum];
+
+ if (person._pathStack.empty())
+ person.pushNPCPath();
+ person._npcMoved = true;
+
+ // Get destination position and facing for Holmes
+ int xp = (str[0] - 1) * 256 + str[1] - 1;
+ if (xp > 16384)
+ xp = -1 * (xp - 16384);
+ int yp = (str[2] - 1) * 256 + str[3] - 1;
+ PositionFacing holmesDest(xp * FIXED_INT_MULTIPLIER, yp * FIXED_INT_MULTIPLIER, DIRECTION_CONVERSION[str[4] - 1]);
+
+ // Get destination position and facing for specified NPC
+ xp = (str[5] - 1) * 256 + str[6] - 1;
+ if (xp > 16384)
+ xp = -1 * (xp - 16384);
+ yp = (str[7] - 1) * 256 + str[8] - 1;
+ PositionFacing npcDest(xp * FIXED_INT_MULTIPLIER, yp * FIXED_INT_MULTIPLIER, DIRECTION_CONVERSION[str[9] - 1]);
+
+ person.walkBothToCoords(holmesDest, npcDest);
+
+ if (_talkToAbort)
+ return RET_EXIT;
+
+ str += 9;
+ return RET_SUCCESS;
+}
+
+OpcodeReturn TattooTalk::cmdCallTalkFile(const byte *&str) {
+ TattooPeople &people = *(TattooPeople *)_vm->_people;
+ Common::String tempString;
+
+ int npc = *++str;
+ assert(npc >= 1 && npc < MAX_CHARACTERS);
+ TattooPerson &person = people[npc];
+
+ if (person._resetNPCPath) {
+ person._npcIndex = person._npcPause = 0;
+ person._resetNPCPath = false;
+ Common::fill(&person._npcPath[0], &person._npcPath[100], 0);
+ }
+
+ // Set the path control code and copy the filename
+ person._npcPath[person._npcIndex] = 4;
+ for (int idx = 1; idx <= 8; ++idx)
+ person._npcPath[person._npcIndex + idx] = str[idx];
+
+ person._npcIndex += 9;
+ str += 8;
+
+ return RET_SUCCESS;
+}
+
+void TattooTalk::pushSequenceEntry(Object *obj) {
+ // Check if the shape is already on the stack
+ for (uint idx = 0; idx < TALK_SEQUENCE_STACK_SIZE; ++idx) {
+ if (_sequenceStack[idx]._obj == obj)
+ return;
+ }
+
+ // Find a free slot and save the details in it
+ for (uint idx = 0; idx < TALK_SEQUENCE_STACK_SIZE; ++idx) {
+ SequenceEntry &seq = _sequenceStack[idx];
+ if (seq._obj == nullptr) {
+ seq._obj = obj;
+ seq._frameNumber = obj->_frameNumber;
+ seq._sequenceNumber = obj->_sequenceNumber;
+ seq._seqStack = obj->_seqStack;
+ seq._seqTo = obj->_seqTo;
+ seq._seqCounter = obj->_seqCounter;
+ seq._seqCounter2 = obj->_seqCounter2;
+ return;
+ }
+ }
+
+ error("Ran out of talk sequence stack space");
+}
+
+void TattooTalk::pullSequence(int slot) {
+ People &people = *_vm->_people;
+
+ for (int idx = 0; idx < TALK_SEQUENCE_STACK_SIZE; ++idx) {
+ SequenceEntry &seq = _sequenceStack[idx];
+ if (slot != -1 && idx != slot)
+ continue;
+
+ // Check for an entry in this slot
+ if (seq._obj) {
+ Object &o = *seq._obj;
+
+ // See if we're not supposed to restore it until an Allow Talk Interrupt
+ if (slot == -1 && seq._obj->hasAborts()) {
+ seq._obj->_gotoSeq = -1;
+ seq._obj->_restoreSlot = idx;
+ } else {
+ // Restore the object's sequence information immediately
+ o._frameNumber = seq._frameNumber;
+ o._sequenceNumber = seq._sequenceNumber;
+ o._seqStack = seq._seqStack;
+ o._seqTo = seq._seqTo;
+ o._seqCounter = seq._seqCounter;
+ o._seqCounter2 = seq._seqCounter2;
+ o._gotoSeq = 0;
+ o._talkSeq = 0;
+
+ // Flag the slot as free again
+ seq._obj = nullptr;
+ }
+ }
+ }
+
+ // Handle restoring any character positioning
+ for (int idx = 0; idx < MAX_CHARACTERS; ++idx) {
+ Person &person = people[idx];
+
+ if (person._type == CHARACTER && !person._walkSequences.empty() && person._sequenceNumber >= TALK_UPRIGHT
+ && person._sequenceNumber <= LISTEN_UPLEFT) {
+ person.gotoStand();
+
+ bool done = false;
+ do {
+ person.checkSprite();
+ for (int frameNum = 0; frameNum < person._frameNumber; ++frameNum) {
+ if (person._walkSequences[person._sequenceNumber]._sequences[frameNum] == 0)
+ done = true;
+ }
+ } while (!done);
+ }
+ }
+}
+
+bool TattooTalk::isSequencesEmpty() const {
+ for (int idx = 0; idx < TALK_SEQUENCE_STACK_SIZE; ++idx) {
+ if (_sequenceStack[idx]._obj)
+ return false;
+ }
+
+ return true;
+}
+
+void TattooTalk::clearSequences() {
+ for (int idx = 0; idx < TALK_SEQUENCE_STACK_SIZE; ++idx) {
+ _sequenceStack[idx]._obj = nullptr;
+ }
+}
+
+} // End of namespace Tattoo
+
+} // End of namespace Sherlock
diff --git a/engines/sherlock/tattoo/tattoo_talk.h b/engines/sherlock/tattoo/tattoo_talk.h
new file mode 100644
index 0000000000..9b010513dc
--- /dev/null
+++ b/engines/sherlock/tattoo/tattoo_talk.h
@@ -0,0 +1,143 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public 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_TALK_H
+#define SHERLOCK_TATTOO_TALK_H
+
+#include "common/scummsys.h"
+#include "common/array.h"
+#include "common/rect.h"
+#include "common/serializer.h"
+#include "common/stream.h"
+#include "common/stack.h"
+#include "sherlock/talk.h"
+#include "sherlock/tattoo/widget_password.h"
+#include "sherlock/tattoo/widget_talk.h"
+
+namespace Sherlock {
+
+namespace Tattoo {
+
+#define TALK_SEQUENCE_STACK_SIZE 20
+
+class WidgetTalk;
+
+class TattooTalk : public Talk {
+ friend class WidgetTalk;
+private:
+ WidgetTalk _talkWidget;
+ WidgetPassword _passwordWidget;
+ SequenceEntry _sequenceStack[TALK_SEQUENCE_STACK_SIZE];
+
+ OpcodeReturn cmdCallTalkFile(const byte *&str);
+ OpcodeReturn cmdSwitchSpeaker(const byte *&str);
+ OpcodeReturn cmdMouseOnOff(const byte *&str);
+ OpcodeReturn cmdGotoScene(const byte *&str);
+ OpcodeReturn cmdWalkHolmesToCoords(const byte *&str);
+ OpcodeReturn cmdNextSong(const byte *&str);
+ OpcodeReturn cmdPassword(const byte *&str);
+ OpcodeReturn cmdPlaySong(const byte *&str);
+ OpcodeReturn cmdRestorePeopleSequence(const byte *&str);
+ OpcodeReturn cmdSetNPCDescOnOff(const byte *&str);
+ OpcodeReturn cmdSetNPCInfoLine(const byte *&str);
+ OpcodeReturn cmdNPCLabelGoto(const byte *&str);
+ OpcodeReturn cmdNPCLabelIfFlagGoto(const byte *&str);
+ OpcodeReturn cmdNPCLabelSet(const byte *&str);
+ OpcodeReturn cmdSetNPCOff(const byte *&str);
+ OpcodeReturn cmdSetNPCOn(const byte *&str);
+ OpcodeReturn cmdSetNPCPathDest(const byte *&str);
+ OpcodeReturn cmdSetNPCPathPause(const byte *&str);
+ OpcodeReturn cmdSetNPCPathPauseTakingNotes(const byte *&str);
+ OpcodeReturn cmdSetNPCPathPauseLookingHolmes(const byte *&str);
+ OpcodeReturn cmdSetNPCPosition(const byte *&str);
+ OpcodeReturn cmdSetNPCTalkFile(const byte *&str);
+ OpcodeReturn cmdSetNPCVerb(const byte *&str);
+ OpcodeReturn cmdSetNPCVerbCAnimation(const byte *&str);
+ OpcodeReturn cmdSetNPCVerbScript(const byte *&str);
+ OpcodeReturn cmdSetNPCVerbTarget(const byte *&str);
+ OpcodeReturn cmdSetNPCWalkGraphics(const byte *&str);
+ OpcodeReturn cmdSetSceneEntryFlag(const byte *&str);
+ OpcodeReturn cmdSetTalkSequence(const byte *&str);
+ OpcodeReturn cmdSetWalkControl(const byte *&str);
+ OpcodeReturn cmdTalkInterruptsDisable(const byte *&str);
+ OpcodeReturn cmdTalkInterruptsEnable(const byte *&str);
+ OpcodeReturn cmdTurnSoundsOff(const byte *&str);
+ OpcodeReturn cmdWalkHolmesAndNPCToCAnimation(const byte *&str);
+ OpcodeReturn cmdWalkNPCToCAnimation(const byte *&str);
+ OpcodeReturn cmdWalkNPCToCoords(const byte *&str);
+ OpcodeReturn cmdWalkHomesAndNPCToCoords(const byte *&str);
+protected:
+ /**
+ * Display the talk interface window
+ */
+ virtual void talkInterface(const byte *&str);
+
+ /**
+ * Called when a character being spoken to has no talk options to display
+ */
+ virtual void nothingToSay();
+
+ /**
+ * Show the talk display
+ */
+ virtual void showTalk();
+public:
+ TattooTalk(SherlockEngine *vm);
+ virtual ~TattooTalk() {}
+
+ /**
+ * Called whenever a conversation or item script needs to be run. For standard conversations,
+ * it opens up a description window similar to how 'talk' does, but shows a 'reply' directly
+ * instead of waiting for a statement option.
+ * @remarks It seems that at some point, all item scripts were set up to use this as well.
+ * In their case, the conversation display is simply suppressed, and control is passed on to
+ * doScript to implement whatever action is required.
+ */
+ virtual void talkTo(const Common::String filename);
+
+ /**
+ * Push the details of a passed object onto the saved sequences stack
+ */
+ virtual void pushSequenceEntry(Object *obj);
+
+ /**
+ * Pulls a background object sequence from the sequence stack and restore's the
+ * object's sequence
+ */
+ virtual void pullSequence(int slot = -1);
+
+ /**
+ * Returns true if the script stack is empty
+ */
+ virtual bool isSequencesEmpty() const;
+
+ /**
+ * Clears the stack of pending object sequences associated with speakers in the scene
+ */
+ virtual void clearSequences();
+};
+
+} // End of namespace Tattoo
+
+} // End of namespace Sherlock
+
+#endif
diff --git a/engines/sherlock/tattoo/tattoo_user_interface.cpp b/engines/sherlock/tattoo/tattoo_user_interface.cpp
index e76322833f..160b1ca5a0 100644
--- a/engines/sherlock/tattoo/tattoo_user_interface.cpp
+++ b/engines/sherlock/tattoo/tattoo_user_interface.cpp
@@ -21,6 +21,8 @@
*/
#include "sherlock/tattoo/tattoo_user_interface.h"
+#include "sherlock/tattoo/tattoo_fixed_text.h"
+#include "sherlock/tattoo/tattoo_journal.h"
#include "sherlock/tattoo/tattoo_scene.h"
#include "sherlock/tattoo/tattoo.h"
@@ -28,121 +30,936 @@ namespace Sherlock {
namespace Tattoo {
-TattooUserInterface::TattooUserInterface(SherlockEngine *vm): UserInterface(vm) {
- _menuBuffer = nullptr;
- _invMenuBuffer = nullptr;
- _tagBuffer = nullptr;
- _invGraphic = nullptr;
+bool WidgetList::contains(const WidgetBase *item) const {
+ for (const_iterator i = begin(); i != end(); ++i) {
+ if ((*i) == item)
+ return true;
+ }
+
+ return false;
}
-void TattooUserInterface::handleInput() {
- // TODO
- _vm->_events->pollEventsAndWait();
+/*-------------------------------------------------------------------------*/
+
+TattooUserInterface::TattooUserInterface(SherlockEngine *vm): UserInterface(vm),
+ _inventoryWidget(vm), _messageWidget(vm), _textWidget(vm), _tooltipWidget(vm),
+ _verbsWidget(vm), _creditsWidget(vm), _optionsWidget(vm), _quitWidget(vm) {
+ Common::fill(&_lookupTable[0], &_lookupTable[PALETTE_COUNT], 0);
+ Common::fill(&_lookupTable1[0], &_lookupTable1[PALETTE_COUNT], 0);
+ _scrollSize = 0;
+ _scrollSpeed = 16;
+ _drawMenu = false;
+ _bgShape = nullptr;
+ _personFound = false;
+ _lockoutTimer = 0;
+ _exitZone = -1;
+ _scriptZone = -1;
+ _arrowZone = _oldArrowZone = -1;
+ _activeObj = -1;
+ _cAnimFramePause = 0;
+ _scrollHighlight = SH_NONE;
+ _mask = _mask1 = nullptr;
+ _maskCounter = 0;
+
+ _interfaceImages = new ImageFile("intrface.vgs");
}
-void TattooUserInterface::drawInterface(int bufferNum) {
+TattooUserInterface::~TattooUserInterface() {
+ delete _interfaceImages;
+ delete _mask;
+ delete _mask1;
+}
+
+void TattooUserInterface::initScrollVars() {
Screen &screen = *_vm->_screen;
- TattooEngine &vm = *((TattooEngine *)_vm);
+ _scrollSize = screen._backBuffer1.w() - SHERLOCK_SCREEN_WIDTH;
+ _targetScroll = Common::Point(0, 0);
+ screen._currentScroll = Common::Point(0, 0);
+}
+
+void TattooUserInterface::lookAtObject() {
+ Events &events = *_vm->_events;
+ People &people = *_vm->_people;
+ Scene &scene = *_vm->_scene;
+ Sound &sound = *_vm->_sound;
+ Talk &talk = *_vm->_talk;
+ Common::Point mousePos = events.mousePos();
+ Common::String desc;
+ int cAnimSpeed = 0;
+
+ _lookPos = mousePos;
+ _menuMode = LOOK_MODE;
+
+ if (_personFound) {
+ desc = people[_bgFound - 1000]._examine;
+ } else {
+ // Check if there is a Look animation
+ if (_bgShape->_lookcAnim != 0) {
+ cAnimSpeed = _bgShape->_lookcAnim & 0xe0;
+ cAnimSpeed >>= 5;
+ ++cAnimSpeed;
+
+ _cAnimFramePause = _bgShape->_lookFrames;
+ desc = _bgShape->_examine;
+
+ int cNum = (_bgShape->_lookcAnim & 0x1f) - 1;
+ scene.startCAnim(cNum);
+ } else if (_bgShape->_lookPosition.y != 0) {
+ // Need to walk to object before looking at it
+ people[HOLMES].walkToCoords(_bgShape->_lookPosition, _bgShape->_lookPosition._facing);
+ }
+
+ if (!talk._talkToAbort) {
+ desc = _bgShape->_examine;
+
+ if (_bgShape->_lookFlag)
+ _vm->setFlags(_bgShape->_lookFlag);
+
+ // Find the Sound File to Play if there is one
+ if (!desc.hasPrefix("_")) {
+ for (uint idx = 0; idx < scene._objSoundList.size(); ++idx) {
+ // Get the object name up to the equals
+ const char *p = strchr(scene._objSoundList[idx].c_str(), '=');
+
+ // Form the name and remove any trailing spaces
+ Common::String name(scene._objSoundList[idx].c_str(), p);
+ while (name.hasSuffix(" "))
+ name.deleteLastChar();
+
+ // See if this Object Sound List entry matches the object's name
+ if (!_bgShape->_name.compareToIgnoreCase(name)) {
+ // Move forward to get the sound filename
+ while ((*p == ' ') || (*p == '='))
+ ++p;
+
+ // If it's not "NONE", play the speech File
+ Common::String soundName(p);
+ if (soundName.compareToIgnoreCase("NONE")) {
+ soundName.toLowercase();
+ if (!soundName.contains('.'))
+ soundName += ".wav";
+
+ sound.playSound(soundName, WAIT_RETURN_IMMEDIATELY);
+ }
+
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ // Only show the desciption if the object has one, and if no talk file interrupted while walking to it
+ if (!talk._talkToAbort && !desc.empty()) {
+ if (_cAnimFramePause == 0)
+ printObjectDesc(desc, true);
+ else
+ // The description was already printed by an animation
+ _cAnimFramePause = 0;
+ } else if (desc.empty()) {
+ // There was no description to display, so reset back to STD_MODE
+ _menuMode = STD_MODE;
+ }
+}
+
+void TattooUserInterface::printObjectDesc(const Common::String &str, bool firstTime) {
+ Events &events = *_vm->_events;
+ TattooScene &scene = *(TattooScene *)_vm->_scene;
+ Talk &talk = *_vm->_talk;
+
+ if (str.hasPrefix("_")) {
+ // The passed string specifies a talk file
+ _lookScriptFlag = true;
+ events.setCursor(MAGNIFY);
+ int savedSelector = _selector;
+
+ if (!_invLookFlag)
+ _windowOpen = false;
+
+ talk.talkTo(str.c_str() + 1);
+ _lookScriptFlag = false;
+
+ if (talk._talkToAbort) {
+ events.setCursor(ARROW);
+ return;
+ }
+
+ // See if we're looking at an inventory item
+ if (_invLookFlag) {
+ _selector = _oldSelector = savedSelector;
+ doInventory(0);
+ _invLookFlag = false;
+
+ } else {
+ // Nope
+ events.setCursor(ARROW);
+ _key = -1;
+ _menuMode = scene._labTableScene ? LAB_MODE : STD_MODE;
+ events._pressed = events._released = events._rightReleased = false;
+ events._oldButtons = 0;
+ }
+ } else {
+ events._pressed = events._released = events._rightReleased = false;
+
+ // Show text dialog
+ _textWidget.load(str);
+ _textWidget.summonWindow();
+
+ if (firstTime)
+ _selector = _oldSelector = -1;
+
+ _drawMenu = _windowOpen = true;
+ }
+}
+
+void TattooUserInterface::doJournal() {
+ TattooJournal &journal = *(TattooJournal *)_vm->_journal;
+ TattooScene &scene = *(TattooScene *)_vm->_scene;
+ Screen &screen = *_vm->_screen;
+ byte lookupTable[PALETTE_SIZE];
+
+ Common::copy(&_lookupTable[0], &_lookupTable[PALETTE_SIZE], &lookupTable[0]);
+ _menuMode = JOURNAL_MODE;
+ journal.show();
+
+ _menuMode = STD_MODE;
+ _windowOpen = false;
+ _key = -1;
+
+ // Restore the the old screen palette and greyscale lookup table
+ screen.clear();
+ screen.setPalette(screen._cMap);
+ Common::copy(&lookupTable[0], &lookupTable[PALETTE_SIZE], &_lookupTable[0]);
+
+ // Restore the scene
+ screen._backBuffer1.blitFrom(screen._backBuffer2);
+ scene.updateBackground();
+ screen.slamArea(screen._currentScroll.x, screen._currentScroll.y, SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT);
+}
+
+void TattooUserInterface::reset() {
+ UserInterface::reset();
+ _lookPos = Common::Point(SHERLOCK_SCREEN_WIDTH / 2, SHERLOCK_SCREEN_HEIGHT / 2);
+ _tooltipWidget.setText("");
+ _widgets.clear();
+ _fixedWidgets.clear();
+}
+
+void TattooUserInterface::handleInput() {
+ TattooEngine &vm = *(TattooEngine *)_vm;
+ Events &events = *_vm->_events;
+ TattooScene &scene = *(TattooScene *)_vm->_scene;
+ Common::Point mousePos = events.mousePos();
+
+ _keyState.keycode = Common::KEYCODE_INVALID;
+
+ // Check for credits starting
+ if (_vm->readFlags(3000) && !_creditsWidget.active())
+ _creditsWidget.initCredits();
+
+ // Check the mouse positioning
+ if (events.isCursorVisible())
+ _bgFound = scene.findBgShape(mousePos);
+ _personFound = _bgFound >= 1000;
+ _bgShape = (_bgFound != -1 && _bgFound < 1000) ? &scene._bgShapes[_bgFound] : nullptr;
+
+ if (_lockoutTimer)
+ --_lockoutTimer;
- if (_invMenuBuffer != nullptr) {
- Common::Rect r = _invMenuBounds;
- r.grow(-3);
- r.translate(-screen._currentScroll, 0);
- _grayAreas.clear();
- _grayAreas.push_back(r);
+ // Key handling
+ if (events.kbHit()) {
+ _keyState = events.getKey();
- drawGrayAreas();
- screen._backBuffer1.transBlitFrom(*_invMenuBuffer, Common::Point(_invMenuBounds.left, _invMenuBounds.top));
+ if (_keyState.keycode == Common::KEYCODE_ESCAPE && vm._runningProlog && !_lockoutTimer) {
+ vm.setFlags(-76);
+ vm.setFlags(396);
+ scene._goToScene = STARTING_GAME_SCENE;
+ } else if (_menuMode == STD_MODE) {
+ if (_keyState.keycode == Common::KEYCODE_s && vm._allowFastMode) {
+ vm._fastMode = !vm._fastMode;
+
+ } else if (_keyState.keycode == Common::KEYCODE_l && _bgFound != -1) {
+ // Beging used for testing that Look dialogs work
+ lookAtObject();
+ }
+ }
}
- if (_menuBuffer != nullptr) {
- Common::Rect r = _menuBounds;
- r.grow(-3);
- r.translate(-screen._currentScroll, 0);
- _grayAreas.clear();
- _grayAreas.push_back(r);
+ if (!events.isCursorVisible())
+ _keyState.keycode = Common::KEYCODE_INVALID;
+
+ // If there's any active widgets/windows, let the most recently open one do event processing
+ if (!_widgets.empty())
+ _widgets.back()->handleEvents();
+ else if (!_fixedWidgets.empty())
+ _fixedWidgets.back()->handleEvents();
- drawGrayAreas();
- screen._backBuffer1.transBlitFrom(*_menuBuffer, Common::Point(_invMenuBounds.left, _invMenuBounds.top));
+ // Handle input depending on what mode we're in
+ switch (_menuMode) {
+ case STD_MODE:
+ doStandardControl();
+ break;
+ case LOOK_MODE:
+ doLookControl();
+ break;
+ default:
+ break;
}
+}
- // See if we need to draw a Text Tag floating with the cursor
- if (_tagBuffer != nullptr)
- screen._backBuffer1.transBlitFrom(*_tagBuffer, Common::Point(_tagBounds.left, _tagBounds.top));
+void TattooUserInterface::drawInterface(int bufferNum) {
+ Screen &screen = *_vm->_screen;
- // See if we need to draw an Inventory Item Graphic floating with the cursor
- if (_invGraphic != nullptr)
- screen._backBuffer1.transBlitFrom(*_invGraphic, Common::Point(_invGraphicBounds.left, _invGraphicBounds.top));
+ // Draw any active on-screen widgets
+ for (Common::List<WidgetBase *>::iterator i = _fixedWidgets.begin(); i != _fixedWidgets.end(); ++i)
+ (*i)->draw();
+ for (Common::List<WidgetBase *>::iterator i = _widgets.begin(); i != _widgets.end(); ++i)
+ (*i)->draw();
- if (vm._creditsActive)
- vm.drawCredits();
+ // Handle drawing credits
+ // TODO: See if credits are only shown on a single screen. If so, _fixedWidgets could be used
+ if (_creditsWidget.active())
+ _creditsWidget.drawCredits();
+
+ // Bring the widgets to the screen
+ if (_mask != nullptr)
+ screen._flushScreen = true;
}
void TattooUserInterface::doBgAnimRestoreUI() {
TattooScene &scene = *((TattooScene *)_vm->_scene);
Screen &screen = *_vm->_screen;
- // If _oldMenuBounds was set, then either a new menu has been opened or the current menu has been closed.
- // Either way, we need to restore the area where the menu was displayed
- if (_oldMenuBounds.width() > 0)
- screen._backBuffer1.blitFrom(screen._backBuffer2, Common::Point(_oldMenuBounds.left, _oldMenuBounds.top),
- _oldMenuBounds);
-
- if (_oldInvMenuBounds.width() > 0)
- screen._backBuffer1.blitFrom(screen._backBuffer2, Common::Point(_oldInvMenuBounds.left, _oldInvMenuBounds.top),
- _oldInvMenuBounds);
-
- if (_menuBuffer != nullptr)
- screen._backBuffer1.blitFrom(screen._backBuffer2, Common::Point(_menuBounds.left, _menuBounds.top), _menuBounds);
- if (_invMenuBuffer != nullptr)
- screen._backBuffer1.blitFrom(screen._backBuffer2, Common::Point(_invMenuBounds.left, _invMenuBounds.top), _invMenuBounds);
+ // If there are any on-screen widgets, then erase them
+ for (Common::List<WidgetBase *>::iterator i = _widgets.begin(); i != _widgets.end(); ++i)
+ (*i)->erase();
+ for (Common::List<WidgetBase *>::iterator i = _fixedWidgets.begin(); i != _fixedWidgets.end(); ++i)
+ (*i)->erase();
// If there is a Text Tag being display, restore the area underneath it
- if (_oldTagBounds.width() > 0)
- screen._backBuffer1.blitFrom(screen._backBuffer2, Common::Point(_oldTagBounds.left, _oldTagBounds.top),
- _oldTagBounds);
-
- // If there is an Inventory being shown, restore the graphics underneath it
- if (_oldInvGraphicBounds.width() > 0)
- screen._backBuffer1.blitFrom(screen._backBuffer2, Common::Point(_oldInvGraphicBounds.left, _oldInvGraphicBounds.top),
- _oldInvGraphicBounds);
+ _tooltipWidget.erase();
// If a canimation is active, restore the graphics underneath it
- if (scene._activeCAnim._images != nullptr)
+ if (scene._activeCAnim.active())
screen.restoreBackground(scene._activeCAnim._oldBounds);
- // If a canimation just ended, remove it's graphics from the backbuffer
+ // If a canimation just ended, remove its graphics from the backbuffer
if (scene._activeCAnim._removeBounds.width() > 0)
screen.restoreBackground(scene._activeCAnim._removeBounds);
}
void TattooUserInterface::doScroll() {
Screen &screen = *_vm->_screen;
- int oldScroll = screen._currentScroll;
// If we're already at the target scroll position, nothing needs to be done
- if (screen._targetScroll == screen._currentScroll)
+ if (_targetScroll.x == screen._currentScroll.x)
return;
screen._flushScreen = true;
- if (screen._targetScroll > screen._currentScroll) {
- screen._currentScroll += screen._scrollSpeed;
- if (screen._currentScroll > screen._targetScroll)
- screen._currentScroll = screen._targetScroll;
- } else if (screen._targetScroll < screen._currentScroll) {
- screen._currentScroll -= screen._scrollSpeed;
- if (screen._currentScroll < screen._targetScroll)
- screen._currentScroll = screen._targetScroll;
+ if (_targetScroll.x > screen._currentScroll.x) {
+ screen._currentScroll.x += _scrollSpeed;
+ if (screen._currentScroll.x > _targetScroll.x)
+ screen._currentScroll.x = _targetScroll.x;
+ } else if (_targetScroll.x < screen._currentScroll.x) {
+ screen._currentScroll.x -= _scrollSpeed;
+ if (screen._currentScroll.x < _targetScroll.x)
+ screen._currentScroll.x = _targetScroll.x;
+ }
+
+ // Reset the default look position to the center of the new screen area
+ _lookPos = screen._currentScroll + Common::Point(SHERLOCK_SCREEN_WIDTH / 2, SHERLOCK_SCREEN_HEIGHT / 2);
+}
+
+void TattooUserInterface::doStandardControl() {
+ TattooEngine &vm = *(TattooEngine *)_vm;
+ Events &events = *_vm->_events;
+ People &people = *_vm->_people;
+ TattooScene &scene = *(TattooScene *)_vm->_scene;
+ Talk &talk = *_vm->_talk;
+ Common::Point mousePos = events.mousePos();
+ bool noDesc = false;
+
+ // Don't do any input processing whilst the prolog is running
+ if (vm._runningProlog)
+ return;
+
+ // When the end credits are active, any press will open the ScummVM global main menu
+ if (_creditsWidget.active()) {
+ if (_keyState.keycode || events._released || events._rightReleased) {
+ vm._canLoadSave = true;
+ vm.openMainMenuDialog();
+ vm._canLoadSave = false;
+ }
+
+ return;
+ }
+
+ // Display the names of any Objects the cursor is pointing at
+ displayObjectNames();
+
+ switch (_keyState.keycode) {
+ case Common::KEYCODE_F5:
+ // Save game
+ events.warpMouse();
+ saveGame();
+ return;
+
+ case Common::KEYCODE_F7:
+ // Load game
+ events.warpMouse();
+ loadGame();
+ return;
+
+ case Common::KEYCODE_F1:
+ // Display journal
+ if (vm.readFlags(FLAG_PLAYER_IS_HOLMES)) {
+ freeMenu();
+ doJournal();
+
+ // See if we're in a Lab Table Room
+ _menuMode = (scene._labTableScene) ? LAB_MODE : STD_MODE;
+ return;
+ }
+ break;
+
+ case Common::KEYCODE_TAB:
+ case Common::KEYCODE_F3:
+ // Display inventory
+ freeMenu();
+ doInventory(3);
+ return;
+
+ case Common::KEYCODE_F4:
+ // Display options
+ events.warpMouse();
+ _optionsWidget.load();
+ return;
+
+ case Common::KEYCODE_F10:
+ // Quit menu
+ freeMenu();
+ events.warpMouse();
+ doQuitMenu();
+ return;
+
+ default:
+ break;
+ }
+
+ // See if a mouse button was released
+ if (events._released || events._rightReleased) {
+ // See if the mouse was released in an exit (Arrow) zone. Unless it's also pointing at an object
+ // within the zone, in which case the object gets precedence
+ _exitZone = -1;
+ if (_arrowZone != -1 && events._released)
+ _exitZone = _arrowZone;
+
+ // Turn any Text display off
+ if (_arrowZone == -1 || events._rightReleased)
+ freeMenu();
+
+ if (_personFound) {
+ if (people[_bgFound - 1000]._description.empty() || people[_bgFound - 1000]._description.hasPrefix(" "))
+ noDesc = true;
+ } else if (_bgFound != -1) {
+ if (_bgShape->_description.empty() || _bgShape->_description.hasPrefix(" "))
+ noDesc = true;
+ } else {
+ noDesc = true;
+ }
+
+ if (events._rightReleased) {
+ // Show the verbs menu for the highlighted object
+ _tooltipWidget.banishWindow();
+ _verbsWidget.load(!noDesc);
+ _verbsWidget.summonWindow();
+
+ _selector = _oldSelector = -1;
+ _activeObj = _bgFound;
+ _menuMode = VERB_MODE;
+ } else if (_personFound || (_bgFound != -1 && _bgFound < 1000 && _bgShape->_aType == PERSON)) {
+ // The object found is a person (the default for people is TALK)
+ talk.initTalk(_bgFound);
+ _activeObj = -1;
+ } else if (!noDesc) {
+ // Either call the code to Look at its Examine Field or call the Exit animation
+ // if the object is an exit, specified by the first four characters of the name being "EXIT"
+ Common::String name = _personFound ? people[_bgFound - 1000]._name : _bgShape->_name;
+ if (!name.hasPrefix("EXIT")) {
+ lookAtObject();
+ } else {
+ // Run the Exit animation and set which scene to go to next
+ for (int idx = 0; idx < 6; ++idx) {
+ if (!_bgShape->_use[idx]._verb.compareToIgnoreCase("Open")) {
+ checkAction(_bgShape->_use[idx], _bgFound);
+ _activeObj = -1;
+ }
+ }
+ }
+ } else {
+ // See if there are any Script Zones where they clicked
+ if (scene.checkForZones(mousePos, _scriptZone) != 0) {
+ // Mouse click in a script zone
+ events._pressed = events._released = false;
+ } else if (scene.checkForZones(mousePos, NOWALK_ZONE) != 0) {
+ events._pressed = events._released = false;
+ } else {
+ // Walk to where the mouse was clicked
+ people[HOLMES]._walkDest = mousePos;
+ people[HOLMES].goAllTheWay();
+ }
+ }
+ }
+}
+
+void TattooUserInterface::doLookControl() {
+ Events &events = *_vm->_events;
+ TattooScene &scene = *(TattooScene *)_vm->_scene;
+ Sound &sound = *_vm->_sound;
+
+ // See if a mouse button was released or a key pressed, and we want to initiate an action
+ // TODO: Not sure about _soundOn.. should be check for speaking voice for text being complete
+ if (events._released || events._rightReleased || _keyState.keycode || (sound._voices && !sound._soundOn)) {
+ // See if we were looking at an inventory object
+ if (!_invLookFlag) {
+ // See if there is any more text to display
+ if (!_textWidget._remainingText.empty()) {
+ printObjectDesc(_textWidget._remainingText, false);
+ } else {
+ // Otherwise restore the background and go back into STD_MODE
+ freeMenu();
+ _key = -1;
+ _menuMode = scene._labTableScene ? LAB_MODE : STD_MODE;
+
+ events.setCursor(ARROW);
+ events._pressed = events._released = events._rightReleased = false;
+ events._oldButtons = 0;
+ }
+ } else {
+ // We were looking at a Inventory object
+ // Erase the text window, and then redraw the inventory window
+ _textWidget.banishWindow();
+ doInventory(0);
+
+ _invLookFlag = false;
+ _key = -1;
+
+ events.setCursor(ARROW);
+ events._pressed = events._released = events._rightReleased = false;
+ events._oldButtons = 0;
+ }
+ }
+}
+
+void TattooUserInterface::displayObjectNames() {
+ Events &events = *_vm->_events;
+ Scene &scene = *_vm->_scene;
+ Common::Point mousePos = events.mousePos();
+ _arrowZone = -1;
+
+ if (_bgFound == -1 || scene._currentScene == OVERHEAD_MAP2) {
+ for (uint idx = 0; idx < scene._exits.size() && _arrowZone == -1; ++idx) {
+ Exit &exit = scene._exits[idx];
+ if (exit.contains(mousePos))
+ _arrowZone = idx;
+ }
}
- if (_menuBuffer != nullptr)
- _menuBounds.translate(screen._currentScroll - oldScroll, 0);
- if (_invMenuBuffer != nullptr)
- _invMenuBounds.translate(screen._currentScroll - oldScroll, 0);
+ _tooltipWidget.handleEvents();
+ _oldArrowZone = _arrowZone;
+}
+
+void TattooUserInterface::doInventory(int mode) {
+ People &people = *_vm->_people;
+ people[HOLMES].gotoStand();
+
+ _inventoryWidget.load(mode);
+ _inventoryWidget.summonWindow();
+
+ _menuMode = INV_MODE;
+}
+
+void TattooUserInterface::doControls() {
+ _optionsWidget.load();
+}
+
+void TattooUserInterface::pickUpObject(int objNum) {
+ Inventory &inv = *_vm->_inventory;
+ Scene &scene = *_vm->_scene;
+ Talk &talk = *_vm->_talk;
+ Object &obj = scene._bgShapes[objNum];
+ bool printed = false;
+ int verbField = -1;
+
+ // Find which Verb field to use for pick up data
+ for (int idx = 0; idx < 6; ++idx) {
+ if (!scumm_stricmp(obj._use[idx]._target.c_str(), "*PICKUP"))
+ verbField = idx;
+ }
+
+ if (verbField != -1) {
+ if (obj._use[verbField]._cAnimNum)
+ scene.startCAnim(obj._use[verbField]._cAnimNum - 1);
+ }
+
+ if (!talk._talkToAbort) {
+ if (obj._type == NO_SHAPE)
+ obj._type = INVALID;
+ else
+ // Erase shape
+ obj._type = REMOVE;
+ } else {
+ return;
+ }
+
+ if (verbField != -1) {
+ for (int idx = 0; idx < 4 && !talk._talkToAbort; ++idx) {
+ if (obj.checkNameForCodes(obj._use[verbField]._names[idx])) {
+ if (!talk._talkToAbort)
+ printed = true;
+ }
+ }
+ }
+
+ if (talk._talkToAbort)
+ return;
+
+ // Add the item to the player's inventory
+ inv.putItemInInventory(obj);
+
+ if (!printed) {
+ Common::String desc = obj._description;
+ desc.setChar(tolower(desc[0]), 0);
+
+ putMessage("%s %s", FIXED(PickedUp), desc.c_str());
+ }
+
+ if (_menuMode != TALK_MODE && _menuMode != MESSAGE_MODE) {
+ _menuMode = STD_MODE;
+ _keyState.keycode = Common::KEYCODE_INVALID;
+ }
+}
+
+void TattooUserInterface::doQuitMenu() {
+ _quitWidget.show();
+}
+
+void TattooUserInterface::putMessage(const char *formatStr, ...) {
+ // Create the string to display
+ va_list args;
+ va_start(args, formatStr);
+ Common::String str = Common::String::vformat(formatStr, args);
+ va_end(args);
+
+ // Open the message widget
+ _menuMode = MESSAGE_MODE;
+ _messageWidget.load(str, 25);
+ _messageWidget.summonWindow();
+}
+
+void TattooUserInterface::setupBGArea(const byte cMap[PALETTE_SIZE]) {
+ Scene &scene = *_vm->_scene;
+
+ // This requires that there is a 16 grayscale palette sequence in the palette that goes from lighter
+ // to darker as the palette numbers go up. The last palette entry in that run is specified by _bgColor
+ byte *p = &_lookupTable[0];
+ for (int idx = 0; idx < PALETTE_COUNT; ++idx)
+ *p++ = BG_GREYSCALE_RANGE_END - (cMap[idx * 3] * 30 + cMap[idx * 3 + 1] * 59 + cMap[idx * 3 + 2] * 11) / 480;
+
+ // If we're going to a scene with a haze special effect, initialize the translate table to lighten the colors
+ if (_mask != nullptr) {
+ p = &_lookupTable1[0];
+
+ for (int idx = 0; idx < PALETTE_COUNT; ++idx) {
+ int r, g, b;
+ switch (scene._currentScene) {
+ case 8:
+ r = cMap[idx * 3] * 4 / 5;
+ g = cMap[idx * 3 + 1] * 3 / 4;
+ b = cMap[idx * 3 + 2] * 3 / 4;
+ break;
+
+ case 18:
+ case 68:
+ r = cMap[idx * 3] * 4 / 3;
+ g = cMap[idx * 3 + 1] * 4 / 3;
+ b = cMap[idx * 3 + 2] * 4 / 3;
+ break;
+
+ case 7:
+ case 53:
+ r = cMap[idx * 3] * 4 / 3;
+ g = cMap[idx * 3 + 1] * 4 / 3;
+ b = cMap[idx * 3 + 2] * 4 / 3;
+ break;
+
+ default:
+ r = g = b = 0;
+ break;
+ }
+
+ byte c = 0xff;
+ int cd = 99999;
+
+ for (int pal = 0; pal < PALETTE_COUNT; ++pal) {
+ int d = (r - cMap[pal * 3]) * (r - cMap[pal * 3]) + (g - cMap[pal * 3 + 1]) * (g - cMap[pal * 3 + 1]) +
+ (b - cMap[pal * 3 + 2]) * (b - cMap[pal * 3 + 2]);
+
+ if (d < cd) {
+ c = pal;
+ cd = d;
+ if (!d)
+ break;
+ }
+ }
+ *p++ = c;
+ }
+ }
+}
+
+void TattooUserInterface::doBgAnimEraseBackground() {
+ People &people = *_vm->_people;
+ Scene &scene = *_vm->_scene;
+ Screen &screen = *_vm->_screen;
+
+ static const int16 OFFSETS[16] = { -1, -2, -3, -3, -2, -1, -1, 0, 1, 2, 3, 3, 2, 1, 0, 0 };
+
+ 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._currentScroll.x + SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT));
+
+ switch (scene._currentScene) {
+ case 7:
+ if (++_maskCounter == 2) {
+ _maskCounter = 0;
+ if (--_maskOffset.x < 0)
+ _maskOffset.x = SHERLOCK_SCREEN_WIDTH - 1;
+ }
+ break;
+
+ case 8:
+ _maskOffset.x += 2;
+ if (_maskOffset.x >= SHERLOCK_SCREEN_WIDTH)
+ _maskOffset.x = 0;
+ break;
+
+ case 18:
+ case 68:
+ ++_maskCounter;
+ if (_maskCounter / 4 >= 16)
+ _maskCounter = 0;
+
+ _maskOffset.x = OFFSETS[_maskCounter / 4];
+ break;
+
+ case 53:
+ if (++_maskCounter == 2) {
+ _maskCounter = 0;
+ if (++_maskOffset.x == screen._backBuffer1.w())
+ _maskOffset.x = 0;
+ }
+ break;
+
+ default:
+ break;
+ }
+ } else {
+ // Standard scene without mask, so call user interface to erase any UI elements as necessary
+ doBgAnimRestoreUI();
+
+ // Restore background for any areas covered by characters and shapes
+ for (int idx = 0; idx < MAX_CHARACTERS; ++idx)
+ screen.restoreBackground(Common::Rect(people[idx]._oldPosition.x, people[idx]._oldPosition.y,
+ people[idx]._oldPosition.x + people[idx]._oldSize.x, people[idx]._oldPosition.y + people[idx]._oldSize.y));
+
+ for (uint idx = 0; idx < scene._bgShapes.size(); ++idx) {
+ Object &obj = scene._bgShapes[idx];
+
+ 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,
+ Common::Rect(obj._oldPosition.x, obj._oldPosition.y, obj._oldPosition.x + obj._oldSize.x,
+ obj._oldPosition.y + obj._oldSize.y));
+ }
+
+ // If credits are active, erase the area they cover
+ if (_creditsWidget.active())
+ _creditsWidget.eraseCredits();
+ }
+
+ for (uint idx = 0; idx < scene._bgShapes.size(); ++idx) {
+ Object &obj = scene._bgShapes[idx];
+
+ if (obj._type == NO_SHAPE && (obj._flags & 1) == 0) {
+ screen._backBuffer1.blitFrom(screen._backBuffer2, obj._position, obj.getNoShapeBounds());
+
+ obj._oldPosition = obj._position;
+ obj._oldSize = obj._noShapeSize;
+ }
+ }
+
+ // Adjust the Target Scroll if needed
+ if ((people[people._walkControl]._position.x / FIXED_INT_MULTIPLIER - screen._currentScroll.x) <
+ (SHERLOCK_SCREEN_WIDTH / 8) && people[people._walkControl]._delta.x < 0) {
+
+ _targetScroll.x = (short)(people[people._walkControl]._position.x / FIXED_INT_MULTIPLIER -
+ SHERLOCK_SCREEN_WIDTH / 8 - 250);
+ if (_targetScroll.x < 0)
+ _targetScroll.x = 0;
+ }
+
+ if ((people[people._walkControl]._position.x / FIXED_INT_MULTIPLIER - screen._currentScroll.x) >
+ (SHERLOCK_SCREEN_WIDTH / 4 * 3) && people[people._walkControl]._delta.x > 0)
+ _targetScroll.x = (short)(people[people._walkControl]._position.x / FIXED_INT_MULTIPLIER -
+ SHERLOCK_SCREEN_WIDTH / 4 * 3 + 250);
+
+ if (_targetScroll.x > _scrollSize)
+ _targetScroll.x = _scrollSize;
+
+ doScroll();
+}
+
+void TattooUserInterface::drawMaskArea(bool mode) {
+ Scene &scene = *_vm->_scene;
+ int xp = mode ? _maskOffset.x : 0;
+
+ if (_mask != nullptr) {
+ switch (scene._currentScene) {
+ case 7:
+ maskArea(*_mask, Common::Point(_maskOffset.x - SHERLOCK_SCREEN_WIDTH, 110));
+ maskArea(*_mask, Common::Point(_maskOffset.x, 110));
+ maskArea(*_mask, Common::Point(_maskOffset.x + SHERLOCK_SCREEN_WIDTH, 110));
+ break;
+
+ case 8:
+ maskArea(*_mask, Common::Point(_maskOffset.x - SHERLOCK_SCREEN_WIDTH, 180));
+ maskArea(*_mask, Common::Point(_maskOffset.x, 180));
+ maskArea(*_mask, Common::Point(_maskOffset.x + SHERLOCK_SCREEN_WIDTH, 180));
+ if (!_vm->readFlags(880))
+ maskArea(*_mask1, Common::Point(940, 300));
+ break;
+
+ case 18:
+ maskArea(*_mask, Common::Point(xp, 203));
+ if (!_vm->readFlags(189))
+ maskArea(*_mask1, Common::Point(124 + xp, 239));
+ break;
+
+ case 53:
+ maskArea(*_mask, Common::Point(_maskOffset.x, 110));
+ if (mode)
+ maskArea(*_mask, Common::Point(_maskOffset.x - SHERLOCK_SCREEN_WIDTH, 110));
+ break;
+
+ case 68:
+ maskArea(*_mask, Common::Point(xp, 203));
+ maskArea(*_mask1, Common::Point(124 + xp, 239));
+ break;
+ }
+ }
+}
+
+void TattooUserInterface::maskArea(Common::SeekableReadStream &mask, const Common::Point &pt) {
+ Screen &screen = *_vm->_screen;
+ Surface &bb1 = screen._backBuffer1;
+ mask.seek(0);
+ int xSize = mask.readUint16LE();
+ int ySize = mask.readUint16LE();
+ int pixel, len, xp, yp;
+
+ for (yp = 0; yp < ySize; ++yp) {
+ byte *ptr = 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
+ // given pixel on the back buffer is darkened (the mask pixel value isn't otherwise used)
+ pixel = mask.readByte();
+ len = mask.readByte();
+
+ for (; len > 0; --len, ++xp, ++ptr) {
+ if (pixel && (pt.x + xp) >= screen._currentScroll.x && (pt.x + xp) < (screen._currentScroll.x + SHERLOCK_SCREEN_WIDTH)) {
+ *ptr = _lookupTable1[*ptr];
+ }
+ }
+ }
+
+ assert(xp == xSize);
+ }
+}
+
+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);
+
+ for (int xp = r.left; xp < r.right; ++xp, ++ptr)
+ *ptr = _lookupTable[*ptr];
+ }
+
+ screen.slamRect(r);
+}
+
+void TattooUserInterface::drawDialogRect(Surface &s, const Common::Rect &r, bool raised) {
+ if (raised) {
+ // Draw Left
+ s.vLine(r.left, r.top, r.bottom - 1, INFO_TOP);
+ s.vLine(r.left + 1, r.top, r.bottom - 2, INFO_TOP);
+ // Draw Top
+ s.hLine(r.left + 2, r.top, r.right - 1, INFO_TOP);
+ s.hLine(r.left + 2, r.top + 1, r.right - 2, INFO_TOP);
+ // Draw Right
+ s.vLine(r.right - 1, r.top + 1, r.bottom - 1, INFO_BOTTOM);
+ s.vLine(r.right - 2, r.top + 2, r.bottom - 1, INFO_BOTTOM);
+ // Draw Bottom
+ s.hLine(r.left + 1, r.bottom - 1, r.right - 3, INFO_BOTTOM);
+ s.hLine(r.left + 2, r.bottom - 2, r.right - 3, INFO_BOTTOM);
+
+ } else {
+ // Draw Left
+ s.vLine(r.left, r.top, r.bottom - 1, INFO_BOTTOM);
+ s.vLine(r.left + 1, r.top, r.bottom - 2, INFO_BOTTOM);
+ // Draw Top
+ s.hLine(r.left + 2, r.top, r.right - 1, INFO_BOTTOM);
+ s.hLine(r.left + 2, r.top + 1, r.right - 2, INFO_BOTTOM);
+ // Draw Right
+ s.vLine(r.right - 1, r.top + 1, r.bottom - 1, INFO_TOP);
+ s.vLine(r.right - 2, r.top + 2, r.bottom - 1, INFO_TOP);
+ // Draw Bottom
+ s.hLine(r.left + 1, r.bottom - 1, r.right - 3, INFO_TOP);
+ s.hLine(r.left + 2, r.bottom - 2, r.right - 3, INFO_TOP);
+ }
+}
+
+void TattooUserInterface::banishWindow(bool slideUp) {
+ if (!_widgets.empty())
+ _widgets.back()->banishWindow();
+}
+
+void TattooUserInterface::freeMenu() {
+ for (Common::List<WidgetBase *>::iterator i = _widgets.begin(); i != _widgets.end(); ++i)
+ (*i)->erase();
+ _widgets.clear();
+}
+
+void TattooUserInterface::clearWindow() {
+ banishWindow();
+}
+
+void TattooUserInterface::loadGame() {
+ WidgetFiles &files = *(WidgetFiles *)_vm->_saves;
+ files.show(SAVEMODE_LOAD);
+}
+
+void TattooUserInterface::saveGame() {
+ WidgetFiles &files = *(WidgetFiles *)_vm->_saves;
+ files.show(SAVEMODE_SAVE);
}
-void TattooUserInterface::drawGrayAreas() {
- // TODO
+void TattooUserInterface::addFixedWidget(WidgetBase *widget) {
+ _fixedWidgets.push_back(widget);
+ widget->summonWindow();
}
} // End of namespace Tattoo
diff --git a/engines/sherlock/tattoo/tattoo_user_interface.h b/engines/sherlock/tattoo/tattoo_user_interface.h
index 2125f1ba07..c92ff21dd1 100644
--- a/engines/sherlock/tattoo/tattoo_user_interface.h
+++ b/engines/sherlock/tattoo/tattoo_user_interface.h
@@ -24,34 +24,99 @@
#define SHERLOCK_TATTOO_UI_H
#include "common/scummsys.h"
+#include "common/list.h"
+#include "sherlock/saveload.h"
+#include "sherlock/screen.h"
#include "sherlock/user_interface.h"
+#include "sherlock/tattoo/widget_credits.h"
+#include "sherlock/tattoo/widget_files.h"
+#include "sherlock/tattoo/widget_inventory.h"
+#include "sherlock/tattoo/widget_options.h"
+#include "sherlock/tattoo/widget_quit.h"
+#include "sherlock/tattoo/widget_text.h"
+#include "sherlock/tattoo/widget_tooltip.h"
+#include "sherlock/tattoo/widget_verbs.h"
namespace Sherlock {
namespace Tattoo {
+// Button width/height
+#define BUTTON_SIZE 15
+// How long to play the intro before it can be skipped
+#define STARTUP_KEYS_DISABLED_DELAY 200
+
+class WidgetBase;
+
+enum ScrollHighlight { SH_NONE = 0, SH_SCROLL_UP = 1, SH_PAGE_UP = 2, SH_THUMBNAIL = 3, SH_PAGE_DOWN = 4, SH_SCROLL_DOWN = 5 };
+
+class WidgetList : public Common::List <WidgetBase *> {
+public:
+ bool contains(const WidgetBase *item) const;
+};
+
class TattooUserInterface : public UserInterface {
+ friend class WidgetBase;
private:
- Common::Rect _menuBounds;
- Common::Rect _oldMenuBounds;
- Common::Rect _invMenuBounds;
- Common::Rect _oldInvMenuBounds;
- Common::Rect _tagBounds;
- Common::Rect _oldTagBounds;
- Common::Rect _invGraphicBounds;
- Common::Rect _oldInvGraphicBounds;
- Surface *_menuBuffer;
- Surface *_invMenuBuffer;
- Surface *_tagBuffer;
- Surface *_invGraphic;
- Common::Array<Common::Rect> _grayAreas;
+ int _scriptZone;
+ int _cAnimFramePause;
+ WidgetInventory _inventoryWidget;
+ WidgetMessage _messageWidget;
+ WidgetQuit _quitWidget;
+ WidgetList _fixedWidgets;
+ WidgetList _widgets;
+ byte _lookupTable[PALETTE_COUNT];
+ byte _lookupTable1[PALETTE_COUNT];
private:
/**
- * Draws designated areas of the screen that are meant to be grayed out using grayscale colors
+ * Handle any input when we're in standard mode (with no windows open)
*/
- void drawGrayAreas();
+ void doStandardControl();
+
+ /**
+ * Handle input when in look mode
+ */
+ void doLookControl();
+
+ /**
+ * Handle input when the File window is open
+ */
+ void doFileControl();
+
+ /**
+ * Handle input while the verb menu is open
+ */
+ void doVerbControl();
+
+ /**
+ * Free any active menu
+ */
+ void freeMenu();
+public:
+ Common::Point _targetScroll;
+ int _scrollSize, _scrollSpeed;
+ bool _drawMenu;
+ int _arrowZone, _oldArrowZone;
+ Object *_bgShape;
+ bool _personFound;
+ int _activeObj;
+ Common::KeyState _keyState;
+ Common::Point _lookPos;
+ ScrollHighlight _scrollHighlight;
+ Common::SeekableReadStream *_mask, *_mask1;
+ Common::Point _maskOffset;
+ int _maskCounter;
+ int _lockoutTimer;
+ ImageFile *_interfaceImages;
+ WidgetCredits _creditsWidget;
+ WidgetOptions _optionsWidget;
+ WidgetText _textWidget;
+ WidgetSceneTooltip _tooltipWidget;
+ WidgetVerbs _verbsWidget;
+ WidgetList _postRenderWidgets;
public:
TattooUserInterface(SherlockEngine *vm);
+ virtual ~TattooUserInterface();
/**
* Handles restoring any areas of the back buffer that were/are covered by UI elements
@@ -62,8 +127,109 @@ public:
* Checks to see if the screen needs to be scrolled. If so, scrolls it towards the target position
*/
void doScroll();
+
+ /**
+ * Initializes scroll variables
+ */
+ void initScrollVars();
+
+ /**
+ * Display the long description for an object in a window
+ */
+ void lookAtObject();
+
+ /**
+ * Display the passed long description for an object. If the flag firstTime is set,
+ * the window will be opened to accomodate the text. Otherwise, the remaining text
+ * will be printed in an already open window
+ */
+ void printObjectDesc(const Common::String &str, bool firstTime);
+
+ /**
+ * Handles displaying the journal
+ */
+ void doJournal();
+
+ /**
+ * Put the game in inventory mode by opening the inventory dialog
+ */
+ void doInventory(int mode);
+
+ /**
+ * Handle the display of the options/setup menu
+ */
+ void doControls();
+
+ /**
+ * Handle the display of the quit menu
+ */
+ void doQuitMenu();
+
+ /**
+ * Pick up the selected object
+ */
+ void pickUpObject(int objNum);
+
+ /**
+ * This will display a text message in a dialog at the bottom of the screen
+ */
+ void putMessage(const char *formatStr, ...) GCC_PRINTF(2, 3);
+
+ /**
+ * Makes a greyscale translation table for each palette entry in the table
+ */
+ void setupBGArea(const byte cMap[PALETTE_SIZE]);
+
+ /**
+ * Erase any background as needed before drawing frame
+ */
+ void doBgAnimEraseBackground();
+
+ void drawMaskArea(bool mode);
+
+ /**
+ * Takes the data passed in the image and apply it to the surface at the given position.
+ * The src mask data is encoded with a different color for each item. To highlight one,
+ the runs that do not match the highlight number will be darkened
+ */
+ void maskArea(Common::SeekableReadStream &mask, const Common::Point &pt);
+
+ /**
+ * Translate a given area of the back buffer to greyscale shading
+ */
+ void makeBGArea(const Common::Rect &r);
+
+ /**
+ * Draws all the dialog rectangles for any items that need them
+ */
+ void drawDialogRect(Surface &s, const Common::Rect &r, bool raised);
+
+ /**
+ * If the mouse cursor is point at the cursor, then display the name of the object on the screen.
+ * If there is no object being pointed it, clear any previously displayed name
+ */
+ void displayObjectNames();
+
+ /**
+ * Show the load game dialog, and allow the user to load a game
+ */
+ void loadGame();
+
+ /**
+ * Show the save game dialog, and allow the user to save the game
+ */
+ void saveGame();
+
+ /**
+ * Add a widget to the current scene to be executed if there are no active widgets in the
+ * main _widgets list
+ */
+ void addFixedWidget(WidgetBase *widget);
public:
- virtual ~TattooUserInterface() {}
+ /**
+ * Resets the user interface
+ */
+ virtual void reset();
/**
* Main input handler for the user interface
@@ -74,6 +240,18 @@ public:
* Draw the user interface onto the screen's back buffers
*/
virtual void drawInterface(int bufferNum = 3);
+
+ /**
+ * Clear any active text window
+ */
+ virtual void clearWindow();
+
+ /**
+ * Banish any active window
+ * @remarks Tattoo doesn't use sliding windows, but the parameter is in the base
+ * UserInterface class as a convenience for Scalpel UI code
+ */
+ virtual void banishWindow(bool slideUp = true);
};
} // End of namespace Tattoo
diff --git a/engines/sherlock/tattoo/widget_base.cpp b/engines/sherlock/tattoo/widget_base.cpp
new file mode 100644
index 0000000000..9e10cee0d1
--- /dev/null
+++ b/engines/sherlock/tattoo/widget_base.cpp
@@ -0,0 +1,375 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public 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/widget_base.h"
+#include "sherlock/tattoo/tattoo.h"
+#include "sherlock/tattoo/tattoo_scene.h"
+#include "sherlock/tattoo/tattoo_talk.h"
+#include "sherlock/tattoo/tattoo_user_interface.h"
+
+namespace Sherlock {
+
+namespace Tattoo {
+
+WidgetBase::WidgetBase(SherlockEngine *vm) : _vm(vm) {
+ _scroll = false;
+ _dialogTimer = 0;
+}
+
+void WidgetBase::summonWindow() {
+ TattooUserInterface &ui = *(TattooUserInterface *)_vm->_ui;
+
+ // Double-check that the same widget isn't added twice
+ if (ui._widgets.contains(this))
+ error("Tried to add a widget multiple times");
+
+ // Add widget to the screen
+ if (!ui._fixedWidgets.contains(this))
+ ui._widgets.push_back(this);
+ ui._windowOpen = true;
+
+ _outsideMenu = false;
+
+ draw();
+}
+
+void WidgetBase::banishWindow() {
+ TattooUserInterface &ui = *(TattooUserInterface *)_vm->_ui;
+
+ erase();
+ _surface.free();
+ ui._widgets.remove(this);
+ ui._windowOpen = false;
+}
+
+void WidgetBase::close() {
+ Events &events = *_vm->_events;
+ TattooScene &scene = *(TattooScene *)_vm->_scene;
+ TattooUserInterface &ui = *(TattooUserInterface *)_vm->_ui;
+
+ banishWindow();
+ ui._menuMode = scene._labTableScene ? LAB_MODE : STD_MODE;
+ events.clearEvents();
+}
+
+bool WidgetBase::active() const {
+ TattooUserInterface &ui = *(TattooUserInterface *)_vm->_ui;
+ for (Common::List<WidgetBase *>::iterator i = ui._widgets.begin(); i != ui._widgets.end(); ++i) {
+ if ((*i) == this)
+ return true;
+ }
+
+ return false;
+}
+
+
+void WidgetBase::erase() {
+ Screen &screen = *_vm->_screen;
+
+ 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.slamRect(_oldBounds);
+
+ // Reset the old bounds so it won't be erased again
+ _oldBounds = Common::Rect(0, 0, 0, 0);
+ }
+}
+
+void WidgetBase::draw() {
+ Screen &screen = *_vm->_screen;
+
+ // If there was a previously drawn frame in a different position that hasn't yet been erased, then erase it
+ if (_oldBounds.width() > 0 && _oldBounds != _bounds)
+ erase();
+
+ if (_bounds.width() > 0 && !_surface.empty()) {
+ // Get the area to draw, adjusted for scroll position
+ restrictToScreen();
+
+ // Draw the background for the widget
+ 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.slamRect(_bounds);
+
+ // Store a copy of the drawn area for later erasing
+ _oldBounds = _bounds;
+ }
+}
+
+void WidgetBase::drawBackground() {
+ TattooEngine &vm = *(TattooEngine *)_vm;
+ Screen &screen = *_vm->_screen;
+ TattooUserInterface &ui = *(TattooUserInterface *)_vm->_ui;
+
+ Common::Rect bounds = _bounds;
+
+ if (vm._transparentMenus) {
+ ui.makeBGArea(bounds);
+ } else {
+ bounds.grow(-3);
+ screen._backBuffer1.fillRect(bounds, MENU_BACKGROUND);
+ }
+}
+
+Common::String WidgetBase::splitLines(const Common::String &str, Common::StringArray &lines, int maxWidth, uint maxLines) {
+ Talk &talk = *_vm->_talk;
+ const char *strP = str.c_str();
+
+ // Loop counting up lines
+ lines.clear();
+ do {
+ int width = 0;
+ const char *spaceP = nullptr;
+ const char *lineStartP = strP;
+
+ // Find how many characters will fit on the next line
+ while (width < maxWidth && *strP && ((byte)*strP < talk._opcodes[OP_SWITCH_SPEAKER] ||
+ (byte)*strP == talk._opcodes[OP_NULL])) {
+ width += _surface.charWidth(*strP);
+
+ // Keep track of the last space
+ if (*strP == ' ')
+ spaceP = strP;
+ ++strP;
+ }
+
+ // If the line was too wide to fit on a single line, go back to the last space
+ // if there was one, or otherwise simply break the line at this point
+ if (width >= maxWidth && spaceP != nullptr)
+ strP = spaceP;
+
+ // Add the line to the output array
+ lines.push_back(Common::String(lineStartP, strP));
+
+ // Move the string ahead to the next line
+ if (*strP == ' ' || *strP == 13)
+ ++strP;
+ } while (*strP && (lines.size() < maxLines) && ((byte)*strP < talk._opcodes[OP_SWITCH_SPEAKER]
+ || (byte)*strP == talk._opcodes[OP_NULL]));
+
+ // Return any remaining text left over
+ return *strP ? Common::String(strP) : Common::String();
+}
+
+void WidgetBase::restrictToScreen() {
+ Screen &screen = *_vm->_screen;
+
+ if (_bounds.left < screen._currentScroll.x)
+ _bounds.moveTo(screen._currentScroll.x, _bounds.top);
+ if (_bounds.top < 0)
+ _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());
+}
+
+void WidgetBase::makeInfoArea(Surface &s) {
+ TattooUserInterface &ui = *(TattooUserInterface *)_vm->_ui;
+ 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()));
+
+ // 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);
+
+ // 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);
+
+ // 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);
+
+ // 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);
+}
+
+void WidgetBase::makeInfoArea() {
+ makeInfoArea(_surface);
+}
+
+void WidgetBase::drawDialogRect(const Common::Rect &r, bool raised) {
+ static_cast<TattooUserInterface *>(_vm->_ui)->drawDialogRect(_surface, r, raised);
+}
+
+void WidgetBase::checkTabbingKeys(int numOptions) {
+}
+
+Common::Rect WidgetBase::getScrollBarBounds() const {
+ Common::Rect r(BUTTON_SIZE, _bounds.height() - 6);
+ r.moveTo(_bounds.width() - BUTTON_SIZE - 3, 3);
+ return r;
+}
+
+void WidgetBase::drawScrollBar(int index, int pageSize, int count) {
+ TattooUserInterface &ui = *(TattooUserInterface *)_vm->_ui;
+
+ // Fill the area with transparency
+ Common::Rect r = getScrollBarBounds();
+ _surface.fillRect(r, TRANSPARENCY);
+
+ bool raised = ui._scrollHighlight != 1;
+ _surface.fillRect(Common::Rect(r.left + 2, r.top + 2, r.right - 2, r.top + BUTTON_SIZE - 2), INFO_MIDDLE);
+ ui.drawDialogRect(_surface, Common::Rect(r.left, r.top, r.left + BUTTON_SIZE, r.top + BUTTON_SIZE), raised);
+
+ raised = ui._scrollHighlight != 5;
+ _surface.fillRect(Common::Rect(r.left + 2, r.bottom - BUTTON_SIZE + 2, r.right - 2, r.bottom - 2), INFO_MIDDLE);
+ ui.drawDialogRect(_surface, Common::Rect(r.left, r.bottom - BUTTON_SIZE, r.right, r.bottom), raised);
+
+ // Draw the arrows on the scroll buttons
+ byte color = index ? INFO_BOTTOM + 2 : INFO_BOTTOM;
+ _surface.hLine(r.left + r.width() / 2, r.top - 2 + BUTTON_SIZE / 2, r.left + r.width() / 2, color);
+ _surface.hLine(r.left + r.width() / 2 - 1, r.top - 1 + BUTTON_SIZE / 2, r.left + r.width() / 2 + 1, color);
+ _surface.hLine(r.left + r.width() / 2 - 2, r.top + BUTTON_SIZE / 2, r.left + r.width() / 2 + 2, color);
+ _surface.hLine(r.left + r.width() / 2 - 3, r.top + 1 + BUTTON_SIZE / 2, r.left + r.width() / 2 + 3, color);
+
+ color = (index + pageSize) < count ? INFO_BOTTOM + 2 : INFO_BOTTOM;
+ _surface.hLine(r.left + r.width() / 2 - 3, r.bottom - 1 - BUTTON_SIZE + BUTTON_SIZE / 2, r.left + r.width() / 2 + 3, color);
+ _surface.hLine(r.left + r.width() / 2 - 2, r.bottom - 1 - BUTTON_SIZE + 1 + BUTTON_SIZE / 2, r.left + r.width() / 2 + 2, color);
+ _surface.hLine(r.left + r.width() / 2 - 1, r.bottom - 1 - BUTTON_SIZE + 2 + BUTTON_SIZE / 2, r.left + r.width() / 2 + 1, color);
+ _surface.hLine(r.left + r.width() / 2, r.bottom - 1 - BUTTON_SIZE + 3 + BUTTON_SIZE / 2, r.left + r.width() / 2, color);
+
+ // Draw the scroll position bar
+ int barHeight = (r.height() - BUTTON_SIZE * 2) * pageSize / count;
+ barHeight = CLIP(barHeight, BUTTON_SIZE, r.height() - BUTTON_SIZE * 2);
+ int barY = (count <= pageSize) ? r.top + BUTTON_SIZE : r.top + BUTTON_SIZE +
+ (r.height() - BUTTON_SIZE * 2 - barHeight) * index / (count - pageSize);
+
+ _surface.fillRect(Common::Rect(r.left + 2, barY + 2, r.right - 2, barY + barHeight - 3), INFO_MIDDLE);
+ ui.drawDialogRect(_surface, Common::Rect(r.left, barY, r.right, barY + barHeight), true);
+}
+
+void WidgetBase::handleScrollbarEvents(int index, int pageSize, int count) {
+ Events &events = *_vm->_events;
+ TattooUserInterface &ui = *(TattooUserInterface *)_vm->_ui;
+ Common::Point mousePos = events.mousePos();
+
+ // If they're dragging the scrollbar thumb, keep it selected whilst the button is being held
+ if ((events._pressed || events._released) && ui._scrollHighlight == SH_THUMBNAIL)
+ return;
+
+ ui._scrollHighlight = SH_NONE;
+
+ if ((!events._pressed && !events._rightReleased) || !_scroll)
+ return;
+
+ Common::Rect r = getScrollBarBounds();
+ r.translate(_bounds.left, _bounds.top);
+
+ // Calculate the Scroll Position bar
+ int barHeight = (r.height() - BUTTON_SIZE * 2) * pageSize / count;
+ barHeight = CLIP(barHeight, BUTTON_SIZE, r.height() - BUTTON_SIZE * 2);
+ int barY = (count <= pageSize) ? r.top + BUTTON_SIZE : r.top + BUTTON_SIZE +
+ (r.height() - BUTTON_SIZE * 2 - barHeight) * index / (count - pageSize);
+
+ if (Common::Rect(r.left, r.top, r.right, r.top + BUTTON_SIZE).contains(mousePos))
+ // Mouse on scroll up button
+ ui._scrollHighlight = SH_SCROLL_UP;
+ else if (Common::Rect(r.left, r.top + BUTTON_SIZE, r.right, barY).contains(mousePos))
+ // Mouse on paging up area (the area of the vertical bar above the thumbnail)
+ ui._scrollHighlight = SH_PAGE_UP;
+ else if (Common::Rect(r.left, barY, r.right, barY + barHeight).contains(mousePos))
+ // Mouse on scrollbar thumb
+ ui._scrollHighlight = SH_THUMBNAIL;
+ else if (Common::Rect(r.left, barY + barHeight, r.right, r.bottom - BUTTON_SIZE).contains(mousePos))
+ // Mouse on paging down area (the area of the vertical bar below the thumbnail)
+ ui._scrollHighlight = SH_PAGE_DOWN;
+ else if (Common::Rect(r.left, r.bottom - BUTTON_SIZE, r.right, r.bottom).contains(mousePos))
+ // Mouse on scroll down button
+ ui._scrollHighlight = SH_SCROLL_DOWN;
+}
+
+void WidgetBase::handleScrolling(int &scrollIndex, int pageSize, int max) {
+ Events &events = *_vm->_events;
+ TattooUserInterface &ui = *(TattooUserInterface *)_vm->_ui;
+ Common::KeyCode keycode = ui._keyState.keycode;
+ Common::Point mousePos = events.mousePos();
+
+ Common::Rect r = getScrollBarBounds();
+ r.translate(_bounds.left, _bounds.top);
+
+ if (ui._scrollHighlight != SH_NONE || keycode == Common::KEYCODE_HOME || keycode == Common::KEYCODE_END
+ || keycode == Common::KEYCODE_PAGEUP || keycode == Common::KEYCODE_PAGEDOWN
+ || keycode == Common::KEYCODE_UP || keycode == Common::KEYCODE_DOWN) {
+ // Check for the scrollbar
+ if (ui._scrollHighlight == SH_THUMBNAIL) {
+ int yp = mousePos.y;
+ yp = CLIP(yp, r.top + BUTTON_SIZE + 3, r.bottom - BUTTON_SIZE - 3);
+
+ // Calculate the line number that corresponds to the position that the mouse is on the scrollbar
+ int lineNum = (yp - r.top - BUTTON_SIZE - 3) * (max - pageSize) / (r.height() - BUTTON_SIZE * 2 - 6);
+ scrollIndex = CLIP(lineNum, 0, max - pageSize);
+ }
+
+ // Get the current frame so we can check the scroll timer against it
+ uint32 frameNum = events.getFrameCounter();
+
+ if (frameNum > _dialogTimer) {
+ // Set the timeout for the next scroll if the mouse button remains held down
+ _dialogTimer = (_dialogTimer == 0) ? frameNum + pageSize : frameNum + 1;
+
+ // Check for Scroll Up
+ if ((ui._scrollHighlight == SH_SCROLL_UP || keycode == Common::KEYCODE_UP) && scrollIndex)
+ --scrollIndex;
+
+ // Check for Page Up
+ else if ((ui._scrollHighlight == SH_PAGE_UP || keycode == Common::KEYCODE_PAGEUP) && scrollIndex)
+ scrollIndex -= pageSize;
+
+ // Check for Page Down
+ else if ((ui._scrollHighlight == SH_PAGE_DOWN || keycode == Common::KEYCODE_PAGEDOWN)
+ && (scrollIndex + pageSize < max)) {
+ scrollIndex += pageSize;
+ if (scrollIndex + pageSize >max)
+ scrollIndex = max - pageSize;
+ }
+
+ // Check for Scroll Down
+ else if ((ui._scrollHighlight == SH_SCROLL_DOWN || keycode == Common::KEYCODE_DOWN) && (scrollIndex + pageSize < max))
+ ++scrollIndex;
+ }
+
+ if (keycode == Common::KEYCODE_END)
+ scrollIndex = max - pageSize;
+
+ if (scrollIndex < 0 || keycode == Common::KEYCODE_HOME)
+ scrollIndex = 0;
+ }
+}
+
+} // End of namespace Tattoo
+
+} // End of namespace Sherlock
diff --git a/engines/sherlock/tattoo/widget_base.h b/engines/sherlock/tattoo/widget_base.h
new file mode 100644
index 0000000000..dcafc8fb21
--- /dev/null
+++ b/engines/sherlock/tattoo/widget_base.h
@@ -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.
+ *
+ */
+
+#ifndef SHERLOCK_TATTOO_WIDGET_BASE_H
+#define SHERLOCK_TATTOO_WIDGET_BASE_H
+
+#include "common/scummsys.h"
+#include "common/rect.h"
+#include "common/str-array.h"
+#include "sherlock/surface.h"
+
+namespace Sherlock {
+
+class SherlockEngine;
+class ImageFile;
+
+namespace Tattoo {
+
+class WidgetBase {
+private:
+ uint32 _dialogTimer;
+protected:
+ SherlockEngine *_vm;
+ Common::Rect _bounds;
+ Common::Rect _oldBounds;
+ Surface _surface;
+ bool _outsideMenu;
+ bool _scroll;
+
+ /**
+ * Used by descendent classes to split up long text for display across multiple lines
+ */
+ Common::String splitLines(const Common::String &str, Common::StringArray &lines, int maxWidth, uint maxLines);
+
+ /**
+ * Ensure that menu is drawn entirely on-screen
+ */
+ void restrictToScreen();
+
+ /**
+ * Draw a window frame around the dges of the passed surface
+ */
+ void makeInfoArea(Surface &s);
+
+ /**
+ * Draw a window frame around the widget's surface
+ */
+ void makeInfoArea();
+
+ /**
+ * Draw a dialog rectangle
+ */
+ void drawDialogRect(const Common::Rect &r, bool raised = true);
+
+ /**
+ * Return the area of a widget that the scrollbar will be drawn in
+ */
+ virtual Common::Rect getScrollBarBounds() const;
+
+ /**
+ * Draw the scrollbar for the dialog
+ */
+ void drawScrollBar(int index, int pageSize, int count);
+
+ /**
+ * Handles any events when the mouse is on the scrollbar
+ */
+ void handleScrollbarEvents(int index, int pageSize, int count);
+
+ /**
+ * Handle adjusting a passed scrolling index as necessary
+ */
+ void handleScrolling(int &scrollIndex, int pageSize, int max);
+
+ /**
+ * Close the dialog
+ */
+ void close();
+
+ /**
+ * Handle drawing the background on the area the widget is going to cover
+ */
+ virtual void drawBackground();
+public:
+ WidgetBase(SherlockEngine *vm);
+ virtual ~WidgetBase() {}
+
+ /**
+ * Returns true if the given widget is active in the user interface's widget list
+ */
+ bool active() const;
+
+ /**
+ * Erase any previous display of the widget on the screen
+ */
+ virtual void erase();
+
+ /**
+ * Update the display of the widget on the screen
+ */
+ virtual void draw();
+
+ /**
+ * Used by some descendents to check for keys to mouse the mouse within the dialog
+ */
+ void checkTabbingKeys(int numOptions);
+
+ /**
+ * Summon the window
+ */
+ virtual void summonWindow();
+
+ /**
+ * Close a currently active menu
+ */
+ virtual void banishWindow();
+
+ /**
+ * Handle event processing
+ */
+ virtual void handleEvents() {}
+};
+
+} // End of namespace Tattoo
+
+} // End of namespace Sherlock
+
+#endif
diff --git a/engines/sherlock/tattoo/widget_credits.cpp b/engines/sherlock/tattoo/widget_credits.cpp
new file mode 100644
index 0000000000..b8e297709f
--- /dev/null
+++ b/engines/sherlock/tattoo/widget_credits.cpp
@@ -0,0 +1,215 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public 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/widget_credits.h"
+#include "sherlock/tattoo/tattoo.h"
+
+namespace Sherlock {
+
+namespace Tattoo {
+
+WidgetCredits::WidgetCredits(SherlockEngine *vm) : _vm(vm) {
+ _creditSpeed = 4;
+ _creditsActive = false;
+}
+
+void WidgetCredits::initCredits() {
+ Resources &res = *_vm->_res;
+ Screen &screen = *_vm->_screen;
+ Common::SeekableReadStream *stream = res.load("credits.txt");
+ int spacing = screen.fontHeight() * 2;
+ int yp = screen.h();
+
+ _creditsActive = true;
+ _creditLines.clear();
+
+ while (stream->pos() < stream->size()) {
+ Common::String line = stream->readLine();
+
+ if (line.hasPrefix("Scroll Speed")) {
+ const char *p = line.c_str() + 12;
+ while ((*p < '0') || (*p > '9'))
+ p++;
+
+ _creditSpeed = atoi(p);
+ } else if (line.hasPrefix("Y Spacing")) {
+ const char *p = line.c_str() + 12;
+ while ((*p < '0') || (*p > '9'))
+ p++;
+
+ spacing = atoi(p) + screen.fontHeight() + 1;
+ } else {
+ int width = screen.stringWidth(line) + 2;
+
+ _creditLines.push_back(CreditLine(line, Common::Point((screen.w() - width) / 2 + 1, yp), width));
+ yp += spacing;
+ }
+ }
+
+ // Post-processing for finding split lines
+ for (int l = 0; l < (int)_creditLines.size(); ++l) {
+ CreditLine &cl = _creditLines[l];
+ const char *p = strchr(cl._line.c_str(), '-');
+
+ if (p != nullptr && p[1] == '>') {
+ cl._line2 = Common::String(p + 3);
+ cl._line = Common::String(cl._line.c_str(), p);
+
+ int width = cl._width;
+ int width1 = screen.stringWidth(cl._line);
+ int width2 = screen.stringWidth(cl._line2);
+
+ int c = 1;
+ for (int l1 = l + 1; l1 < (int)_creditLines.size(); ++l1) {
+ if ((p = strchr(_creditLines[l1]._line.c_str(), '-')) != nullptr) {
+ if (p[1] == '>') {
+ Common::String line1 = Common::String(_creditLines[l1]._line.c_str(), p);
+ Common::String line2 = Common::String(p + 3);
+
+ width1 = MAX(width1, screen.stringWidth(line1));
+
+ if (screen.stringWidth(line2) > width2)
+ width2 = screen.stringWidth(line2);
+ ++c;
+ } else {
+ break;
+ }
+ } else {
+ break;
+ }
+ }
+
+ width = width1 + width2 + screen.widestChar();
+ width1 += screen.widestChar();
+
+ for (int l1 = l; l1 < l + c; ++l1) {
+ _creditLines[l1]._width = width;
+ _creditLines[l1]._xOffset = width1;
+ }
+
+ l += c - 1;
+ }
+ }
+
+ delete stream;
+}
+
+void WidgetCredits::close() {
+ _creditsActive = false;
+ _creditLines.clear();
+}
+
+void WidgetCredits::drawCredits() {
+ Screen &screen = *_vm->_screen;
+ Common::Rect screenRect(0, 0, screen.w(), screen.h());
+ Surface &bb1 = screen._backBuffer1;
+
+ for (uint idx = 0; idx < _creditLines.size() && _creditLines[idx]._position.y < screen.h(); ++idx) {
+ if (screenRect.contains(_creditLines[idx]._position)) {
+ if (!_creditLines[idx]._line2.empty()) {
+ int x1 = _creditLines[idx]._position.x;
+ int x2 = x1 + _creditLines[idx]._xOffset;
+ const Common::String &line1 = _creditLines[idx]._line;
+ const Common::String &line2 = _creditLines[idx]._line2;
+
+ bb1.writeString(line1, Common::Point(x1 - 1, _creditLines[idx]._position.y - 1), 0);
+ bb1.writeString(line1, Common::Point(x1, _creditLines[idx]._position.y - 1), 0);
+ bb1.writeString(line1, Common::Point(x1 + 1, _creditLines[idx]._position.y - 1), 0);
+
+ bb1.writeString(line1, Common::Point(x1 - 1, _creditLines[idx]._position.y), 0);
+ bb1.writeString(line1, Common::Point(x1 + 1, _creditLines[idx]._position.y), 0);
+
+ bb1.writeString(line1, Common::Point(x1 - 1, _creditLines[idx]._position.y + 1), 0);
+ bb1.writeString(line1, Common::Point(x1, _creditLines[idx]._position.y + 1), 0);
+ bb1.writeString(line1, Common::Point(x1 + 1, _creditLines[idx]._position.y + 1), 0);
+
+ bb1.writeString(line1, Common::Point(x1, _creditLines[idx]._position.y), INFO_TOP);
+
+ bb1.writeString(line2, Common::Point(x2 - 1, _creditLines[idx]._position.y - 1), 0);
+ bb1.writeString(line2, Common::Point(x2, _creditLines[idx]._position.y - 1), 0);
+ bb1.writeString(line2, Common::Point(x2 + 1, _creditLines[idx]._position.y - 1), 0);
+
+ bb1.writeString(line2, Common::Point(x2 - 1, _creditLines[idx]._position.y), 0);
+ bb1.writeString(line2, Common::Point(x2 + 1, _creditLines[idx]._position.y), 0);
+
+ bb1.writeString(line2, Common::Point(x2 - 1, _creditLines[idx]._position.y + 1), 0);
+ bb1.writeString(line2, Common::Point(x2, _creditLines[idx]._position.y + 1), 0);
+ bb1.writeString(line2, Common::Point(x2 + 1, _creditLines[idx]._position.y + 1), 0);
+
+ bb1.writeString(line2, Common::Point(x2, _creditLines[idx]._position.y), INFO_TOP);
+ } else {
+ bb1.writeString(_creditLines[idx]._line, Common::Point(_creditLines[idx]._position.x - 1, _creditLines[idx]._position.y - 1), 0);
+ bb1.writeString(_creditLines[idx]._line, Common::Point(_creditLines[idx]._position.x, _creditLines[idx]._position.y - 1), 0);
+ bb1.writeString(_creditLines[idx]._line, Common::Point(_creditLines[idx]._position.x + 1, _creditLines[idx]._position.y - 1), 0);
+
+ bb1.writeString(_creditLines[idx]._line, Common::Point(_creditLines[idx]._position.x - 1, _creditLines[idx]._position.y), 0);
+ bb1.writeString(_creditLines[idx]._line, Common::Point(_creditLines[idx]._position.x + 1, _creditLines[idx]._position.y), 0);
+
+ bb1.writeString(_creditLines[idx]._line, Common::Point(_creditLines[idx]._position.x - 1, _creditLines[idx]._position.y + 1), 0);
+ bb1.writeString(_creditLines[idx]._line, Common::Point(_creditLines[idx]._position.x, _creditLines[idx]._position.y + 1), 0);
+ bb1.writeString(_creditLines[idx]._line, Common::Point(_creditLines[idx]._position.x + 1, _creditLines[idx]._position.y + 1), 0);
+
+ bb1.writeString(_creditLines[idx]._line, Common::Point(_creditLines[idx]._position.x, _creditLines[idx]._position.y), INFO_TOP);
+ }
+ }
+ }
+}
+
+void WidgetCredits::blitCredits() {
+ Screen &screen = *_vm->_screen;
+ Common::Rect screenRect(0, -_creditSpeed, screen.w(), screen.h() + _creditSpeed);
+
+ for (uint idx = 0; idx < _creditLines.size(); ++idx) {
+ if (screenRect.contains(_creditLines[idx]._position)) {
+ Common::Rect r(_creditLines[idx]._width, screen.fontHeight() + 2);
+ r.moveTo(_creditLines[idx]._position.x, _creditLines[idx]._position.y - 1);
+
+ 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);
+
+ for (uint idx = 0; idx < _creditLines.size(); ++idx) {
+ if (screenRect.contains(_creditLines[idx]._position)) {
+ Common::Rect r(_creditLines[idx]._width, screen.fontHeight() + 3);
+ r.moveTo(_creditLines[idx]._position.x, _creditLines[idx]._position.y - 1 + _creditSpeed);
+
+ screen.restoreBackground(r);
+ }
+ }
+
+ if (_creditLines[_creditLines.size() - 1]._position.y < -_creditSpeed) {
+ // Completely finished credits display. Note that the credits will still remain flagged as active,
+ // so that the user interface knows not to allow and standard scene interaction
+ _creditLines.clear();
+ }
+}
+
+} // End of namespace Tattoo
+
+} // End of namespace Sherlock
diff --git a/engines/sherlock/tattoo/widget_credits.h b/engines/sherlock/tattoo/widget_credits.h
new file mode 100644
index 0000000000..d31c6ac216
--- /dev/null
+++ b/engines/sherlock/tattoo/widget_credits.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 SHERLOCK_TATTOO_CREDITS_H
+#define SHERLOCK_TATTOO_CREDITS_H
+
+#include "common/array.h"
+#include "common/rect.h"
+
+namespace Sherlock {
+
+ class SherlockEngine;
+
+namespace Tattoo {
+
+struct CreditLine {
+ Common::Point _position;
+ int _xOffset;
+ int _width;
+ Common::String _line, _line2;
+
+ CreditLine(const Common::String &line, const Common::Point &pt, int width) :
+ _line(line), _position(pt), _width(width), _xOffset(0) {}
+};
+
+class WidgetCredits {
+private:
+ SherlockEngine *_vm;
+ Common::Array<CreditLine> _creditLines;
+ int _creditSpeed;
+ bool _creditsActive;
+public:
+ WidgetCredits(SherlockEngine *vm);
+
+ /**
+ * Returns true if the credits are active
+ */
+ bool active() const { return _creditsActive; }
+
+ /**
+ * Initialize and load credit data for display
+ */
+ void initCredits();
+
+ /**
+ * Closes down credits display
+ */
+ void close();
+
+ /**
+ * Draw credits on the screen
+ */
+ void drawCredits();
+
+ /**
+ * Blit the drawn credits to the screen
+ */
+ void blitCredits();
+
+ /**
+ * Erase any area of the screen covered by credits
+ */
+ void eraseCredits();
+};
+
+} // End of namespace Tattoo
+
+} // End of namespace Sherlock
+
+#endif
diff --git a/engines/sherlock/tattoo/widget_files.cpp b/engines/sherlock/tattoo/widget_files.cpp
new file mode 100644
index 0000000000..c9a20b0f8a
--- /dev/null
+++ b/engines/sherlock/tattoo/widget_files.cpp
@@ -0,0 +1,428 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public 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/translation.h"
+#include "gui/saveload.h"
+#include "sherlock/tattoo/widget_files.h"
+#include "sherlock/tattoo/tattoo.h"
+#include "sherlock/tattoo/tattoo_fixed_text.h"
+#include "sherlock/tattoo/tattoo_scene.h"
+#include "sherlock/tattoo/tattoo_user_interface.h"
+
+namespace Sherlock {
+
+namespace Tattoo {
+
+#define FILES_LINES_COUNT 5
+
+WidgetFiles::WidgetFiles(SherlockEngine *vm, const Common::String &target) :
+ SaveManager(vm, target), WidgetBase(vm), _vm(vm) {
+ _fileMode = SAVEMODE_NONE;
+ _selector = _oldSelector = -1;
+}
+
+void WidgetFiles::show(SaveMode mode) {
+ Events &events = *_vm->_events;
+ TattooUserInterface &ui = *(TattooUserInterface *)_vm->_ui;
+ Common::Point mousePos = events.mousePos();
+
+ if (_vm->_showOriginalSavesDialog) {
+ // Render and display the file dialog
+ _fileMode = mode;
+ ui._menuMode = FILES_MODE;
+ _selector = _oldSelector = -1;
+ _scroll = true;
+ createSavegameList();
+
+ // Set up the display area
+ _bounds = Common::Rect(SHERLOCK_SCREEN_WIDTH * 2 / 3, (_surface.fontHeight() + 1) *
+ (FILES_LINES_COUNT + 1) + 17);
+ _bounds.moveTo(mousePos.x - _bounds.width() / 2, mousePos.y - _bounds.height() / 2);
+
+ // Create the surface and render its contents
+ _surface.create(_bounds.width(), _bounds.height());
+ render(RENDER_ALL);
+
+ summonWindow();
+ ui._menuMode = FILES_MODE;
+ } else if (mode == SAVEMODE_LOAD) {
+ showScummVMRestoreDialog();
+ } else {
+ showScummVMSaveDialog();
+ }
+}
+
+void WidgetFiles::showScummVMSaveDialog() {
+ 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);
+ }
+
+ _vm->saveGameState(slot, desc);
+ }
+
+ close();
+ delete dialog;
+}
+
+void WidgetFiles::showScummVMRestoreDialog() {
+ GUI::SaveLoadChooser *dialog = new GUI::SaveLoadChooser(_("Restore game:"), _("Restore"), false);
+ int slot = dialog->runModalWithCurrentTarget();
+ close();
+ delete dialog;
+
+ if (slot >= 0) {
+ _vm->loadGameState(slot);
+ }
+}
+
+void WidgetFiles::render(FilesRenderMode mode) {
+ TattooUserInterface &ui = *(TattooUserInterface *)_vm->_ui;
+ ImageFile &images = *ui._interfaceImages;
+ byte color;
+
+ if (mode == RENDER_ALL) {
+ _surface.fill(TRANSPARENCY);
+ makeInfoArea();
+
+ switch (_fileMode) {
+ case SAVEMODE_LOAD:
+ _surface.writeString(FIXED(LoadGame),
+ Common::Point((_surface.w() - _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);
+ 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));
+
+ int xp = _surface.w() - 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));
+ }
+
+ 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 (mode == RENDER_NAMES_AND_SCROLLBAR)
+ _surface.fillRect(Common::Rect(4, yp, _surface.w() - 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);
+ }
+
+ yp += _surface.fontHeight() + 1;
+ }
+
+ // Draw the Scrollbar if neccessary
+ if (mode != RENDER_NAMES)
+ drawScrollBar(_savegameIndex, FILES_LINES_COUNT, _savegames.size());
+}
+
+void WidgetFiles::handleEvents() {
+ Events &events = *_vm->_events;
+ TattooUserInterface &ui = *(TattooUserInterface *)_vm->_ui;
+ Common::Point mousePos = events.mousePos();
+ Common::KeyState keyState = ui._keyState;
+
+ // Handle scrollbar events
+ ScrollHighlight oldHighlight = ui._scrollHighlight;
+ handleScrollbarEvents(_savegameIndex, FILES_LINES_COUNT, _savegames.size());
+
+ int oldScrollIndex = _savegameIndex;
+ handleScrolling(_savegameIndex, FILES_LINES_COUNT, _savegames.size());
+
+ // See if the mouse is pointing at any filenames in the window
+ if (Common::Rect(_bounds.left, _bounds.top + _surface.fontHeight() + 14,
+ _bounds.right - BUTTON_SIZE - 5, _bounds.bottom - 5).contains(mousePos)) {
+ _selector = (mousePos.y - _bounds.top - _surface.fontHeight() - 14) / (_surface.fontHeight() + 1) +
+ _savegameIndex;
+ } else {
+ _selector = -1;
+ }
+
+ // Check for the Tab key
+ if (keyState.keycode == Common::KEYCODE_TAB) {
+ // If the mouse is not over any of the filenames, move the mouse so that it points to the first one
+ if (_selector == -1) {
+ events.warpMouse(Common::Point(_bounds.right - BUTTON_SIZE - 20,
+ _bounds.top + _surface.fontHeight() * 2 + 8));
+ } else {
+ // See if we're doing Tab or Shift Tab
+ if (keyState.flags & Common::KBD_SHIFT) {
+ // We're doing Shift Tab
+ if (_selector == _savegameIndex)
+ _selector = _savegameIndex + 4;
+ else
+ --_selector;
+ } else {
+ // We're doing Tab
+ ++_selector;
+ if (_selector >= _savegameIndex + 5)
+ _selector = _savegameIndex;
+ }
+
+ events.warpMouse(Common::Point(mousePos.x, _bounds.top + _surface.fontHeight() * 2
+ + 8 + (_selector - _savegameIndex) * (_surface.fontHeight() + 1)));
+ }
+ }
+
+ // Only redraw the window if the the scrollbar position has changed
+ if (ui._scrollHighlight != oldHighlight || oldScrollIndex != _savegameIndex || _selector != _oldSelector)
+ render(RENDER_NAMES_AND_SCROLLBAR);
+ _oldSelector = _selector;
+
+ if (events._firstPress && !_bounds.contains(mousePos))
+ _outsideMenu = true;
+
+ if (events._released || events._rightReleased || keyState.keycode == Common::KEYCODE_ESCAPE) {
+ ui._scrollHighlight = SH_NONE;
+
+ if (_outsideMenu && !_bounds.contains(mousePos)) {
+ close();
+ } else {
+ _outsideMenu = false;
+
+ if (_selector != -1) {
+ if (_fileMode == SAVEMODE_LOAD) {
+ // We're in Load Mode
+ _vm->loadGameState(_selector);
+ } else if (_fileMode == SAVEMODE_SAVE) {
+ // We're in Save Mode
+ if (getFilename())
+ _vm->saveGameState(_selector, _savegames[_selector]);
+ close();
+ }
+ }
+ }
+ }
+}
+
+bool WidgetFiles::getFilename() {
+ Events &events = *_vm->_events;
+ TattooScene &scene = *(TattooScene *)_vm->_scene;
+ Screen &screen = *_vm->_screen;
+ Talk &talk = *_vm->_talk;
+ int index = 0;
+ int done = 0;
+ bool blinkFlag = false;
+ int blinkCountdown = 0;
+ int width;
+ int cursorColor = 192;
+ byte color, textColor;
+ bool insert = true;
+
+ assert(_selector != -1);
+ Common::Point pt(_surface.stringWidth("00.") + _surface.widestChar() + 5,
+ _surface.fontHeight() + 14 + (_selector - _savegameIndex) * (_surface.fontHeight() + 1));
+
+ Common::String numStr = Common::String::format("%d.", _selector + 1);
+ _surface.writeString(numStr, Common::Point(_surface.widestChar(), pt.y), COMMAND_HIGHLIGHTED);
+
+ Common::String filename = _savegames[_selector];
+
+ if (isSlotEmpty(_selector)) {
+ index = 0;
+ _surface.fillRect(Common::Rect(pt.x, pt.y, _bounds.right - BUTTON_SIZE - 9, pt.y + _surface.fontHeight() - 1), TRANSPARENCY);
+ filename = "";
+ } else {
+ index = filename.size();
+ _surface.writeString(filename, pt, COMMAND_HIGHLIGHTED);
+ pt.x = _surface.stringWidth("00.") + _surface.stringWidth(filename) + _surface.widestChar() + 5;
+ }
+
+ do {
+ scene.doBgAnim();
+
+ if (talk._talkToAbort)
+ return false;
+
+ char currentChar = (index == (int)filename.size()) ? ' ' : filename[index];
+ Common::String charString = Common::String::format("%c", currentChar);
+ width = screen.charWidth(currentChar);
+
+ // Wait for keypress
+ while (!events.kbHit()) {
+ events.pollEventsAndWait();
+ events.setButtonState();
+
+ scene.doBgAnim();
+
+ if (talk._talkToAbort)
+ return false;
+
+ if (--blinkCountdown <= 0) {
+ blinkCountdown = 3;
+ blinkFlag = !blinkFlag;
+ if (blinkFlag) {
+ textColor = 236;
+ color = cursorColor;
+ } else {
+ textColor = COMMAND_HIGHLIGHTED;
+ color = TRANSPARENCY;
+ }
+
+ _surface.fillRect(Common::Rect(pt.x, pt.y, pt.x + width, pt.y + _surface.fontHeight()), color);
+ if (currentChar != ' ')
+ _surface.writeString(charString, pt, textColor);
+ }
+ if (_vm->shouldQuit())
+ return false;
+ }
+
+ Common::KeyState keyState = events.getKey();
+ if (keyState.keycode == Common::KEYCODE_BACKSPACE && index > 0) {
+ pt.x -= _surface.charWidth(filename[index - 1]);
+ --index;
+
+ if (insert) {
+ filename.deleteChar(index);
+ } else {
+ filename.setChar(' ', index);
+ }
+
+ _surface.fillRect(Common::Rect(pt.x, pt.y, _surface.w() - 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)
+ || (keyState.keycode == Common::KEYCODE_RIGHT && index < 49 && pt.x < (_bounds.right - BUTTON_SIZE - 20))
+ || (keyState.keycode == Common::KEYCODE_HOME && index > 0)
+ || (keyState.keycode == Common::KEYCODE_END)) {
+ _surface.fillRect(Common::Rect(pt.x, pt.y, pt.x + width, pt.y + _surface.fontHeight()), TRANSPARENCY);
+ if (currentChar)
+ _surface.writeString(charString, pt, COMMAND_HIGHLIGHTED);
+
+ switch (keyState.keycode) {
+ case Common::KEYCODE_LEFT:
+ pt.x -= _surface.charWidth(filename[index - 1]);
+ --index;
+ break;
+
+ case Common::KEYCODE_RIGHT:
+ pt.x += _surface.charWidth(filename[index]);
+ ++index;
+ break;
+
+ case Common::KEYCODE_HOME:
+ pt.x = _surface.stringWidth("00.") + _surface.widestChar() + 5;
+ index = 0;
+ break;
+
+ case Common::KEYCODE_END:
+ pt.x = _surface.stringWidth("00.") + _surface.stringWidth(filename) + _surface.widestChar() + 5;
+ index = filename.size();
+
+ while (filename[index - 1] == ' ' && index > 0) {
+ pt.x -= _surface.charWidth(filename[index - 1]);
+ --index;
+ }
+ break;
+
+ default:
+ break;
+ }
+ } else if (keyState.keycode == Common::KEYCODE_INSERT) {
+ insert = !insert;
+ if (insert)
+ cursorColor = 192;
+ else
+ cursorColor = 200;
+
+ } else if (keyState.keycode == Common::KEYCODE_DELETE) {
+ filename.deleteChar(index);
+
+ _surface.fillRect(Common::Rect(pt.x, pt.y, _bounds.right - BUTTON_SIZE - 9, pt.y + _surface.fontHeight() - 1), TRANSPARENCY);
+ _surface.writeString(filename + index, pt, COMMAND_HIGHLIGHTED);
+
+ } else if (keyState.keycode == Common::KEYCODE_RETURN) {
+ done = 1;
+
+ } else if (keyState.keycode == Common::KEYCODE_ESCAPE) {
+ _selector = -1;
+ render(RENDER_NAMES_AND_SCROLLBAR);
+ 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 (insert)
+ filename.insertChar(keyState.ascii, index);
+ else
+ filename.setChar(keyState.ascii, index);
+
+ _surface.fillRect(Common::Rect(pt.x, pt.y, _bounds.width() - BUTTON_SIZE - 9,
+ pt.y + _surface.fontHeight() - 1), TRANSPARENCY);
+ _surface.writeString(filename.c_str() + index, pt, COMMAND_HIGHLIGHTED);
+ pt.x += _surface.charWidth(keyState.ascii);
+ ++index;
+ }
+ }
+ } while (!done && !_vm->shouldQuit());
+
+ scene.doBgAnim();
+
+ if (talk._talkToAbort)
+ return false;
+
+ if (done == 1)
+ _savegames[_selector] = filename;
+
+ return done == 1;
+}
+
+Common::Rect WidgetFiles::getScrollBarBounds() const {
+ Common::Rect scrollRect(BUTTON_SIZE, _bounds.height() - _surface.fontHeight() - 16);
+ scrollRect.moveTo(_bounds.width() - BUTTON_SIZE - 3, _surface.fontHeight() + 13);
+
+ return scrollRect;
+}
+
+} // End of namespace Tattoo
+
+} // End of namespace Sherlock
diff --git a/engines/sherlock/tattoo/widget_files.h b/engines/sherlock/tattoo/widget_files.h
new file mode 100644
index 0000000000..94a029d18d
--- /dev/null
+++ b/engines/sherlock/tattoo/widget_files.h
@@ -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.
+ *
+ */
+
+#ifndef SHERLOCK_TATTOO_WIDGET_FILES_H
+#define SHERLOCK_TATTOO_WIDGET_FILES_H
+
+#include "common/scummsys.h"
+#include "sherlock/tattoo/widget_base.h"
+#include "sherlock/saveload.h"
+
+namespace Sherlock {
+
+class SherlockEngine;
+
+namespace Tattoo {
+
+enum FilesRenderMode { RENDER_ALL, RENDER_NAMES, RENDER_NAMES_AND_SCROLLBAR };
+
+class WidgetFiles: public WidgetBase, public SaveManager {
+private:
+ SherlockEngine *_vm;
+ SaveMode _fileMode;
+ int _selector, _oldSelector;
+
+ /**
+ * Render the dialog
+ */
+ void render(FilesRenderMode mode);
+
+ /**
+ * Show the ScummVM Save Game dialog
+ */
+ void showScummVMSaveDialog();
+
+ /**
+ * Show the ScummVM Load Game dialog
+ */
+ void showScummVMRestoreDialog();
+
+ /**
+ * Prompt the user for a savegame name in the currently selected slot
+ */
+ bool getFilename();
+
+ /**
+ * Return the area of a widget that the scrollbar will be drawn in
+ */
+ virtual Common::Rect getScrollBarBounds() const;
+public:
+ WidgetFiles(SherlockEngine *vm, const Common::String &target);
+ virtual ~WidgetFiles() {}
+
+ /**
+ * Prompt the user whether to quit
+ */
+ void show(SaveMode mode);
+
+ /**
+ * Handle event processing
+ */
+ virtual void handleEvents();
+};
+
+} // End of namespace Tattoo
+
+} // End of namespace Sherlock
+
+#endif
diff --git a/engines/sherlock/tattoo/widget_foolscap.cpp b/engines/sherlock/tattoo/widget_foolscap.cpp
new file mode 100644
index 0000000000..8246e9a371
--- /dev/null
+++ b/engines/sherlock/tattoo/widget_foolscap.cpp
@@ -0,0 +1,299 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public 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/widget_foolscap.h"
+#include "sherlock/tattoo/tattoo_fixed_text.h"
+#include "sherlock/tattoo/tattoo_scene.h"
+#include "sherlock/tattoo/tattoo_user_interface.h"
+#include "sherlock/tattoo/tattoo.h"
+
+namespace Sherlock {
+
+namespace Tattoo {
+
+WidgetFoolscap::WidgetFoolscap(TattooEngine *vm) : WidgetBase(vm) {
+ for (int idx = 0; idx < 3; ++idx) {
+ Common::fill(&_answers[idx][0], &_answers[idx][10], 0);
+ _solutions[idx] = nullptr;
+ }
+ _images = nullptr;
+ _numWide = 0;
+ _spacing = 0;
+ _blinkFlag = false;
+ _blinkCounter = 0;
+ _lineNum = _charNum = 0;
+ _solved = false;
+}
+
+WidgetFoolscap::~WidgetFoolscap() {
+ delete _images;
+}
+
+void WidgetFoolscap::show() {
+ Screen &screen = *_vm->_screen;
+ TattooUserInterface &ui = *(TattooUserInterface *)_vm->_ui;
+
+ switch (_vm->getLanguage()) {
+ case Common::FR_FRA:
+ _lines[0] = Common::Point(34, 210);
+ _lines[1] = Common::Point(72, 242);
+ _lines[2] = Common::Point(34, 276);
+ _numWide = 8;
+ _spacing = 19;
+ _images = new ImageFile("paperf.vgs");
+ break;
+
+ case Common::DE_DEU:
+ _lines[0] = Common::Point(44, 73);
+ _lines[1] = Common::Point(56, 169);
+ _lines[2] = Common::Point(47, 256);
+ _numWide = 7;
+ _spacing = 19;
+ _images = new ImageFile("paperg.vgs");
+ break;
+
+ default:
+ // English
+ _lines[0] = Common::Point(65, 84);
+ _lines[1] = Common::Point(65, 159);
+ _lines[2] = Common::Point(75, 234);
+ _numWide = 5;
+ _spacing = 20;
+ _images = new ImageFile("paper.vgs");
+ break;
+ }
+
+ _solved = false;
+ _blinkFlag = false;
+ _blinkCounter = 0;
+ _lineNum = _charNum = 0;
+ _cursorPos = Common::Point(_lines[0].x + 8 - screen.widestChar() / 2, _lines[0].y - screen.fontHeight() - 2);
+
+ // Set up window bounds
+ ImageFrame &paperFrame = (*_images)[0];
+ _bounds = Common::Rect(paperFrame._width, paperFrame._height);
+ _bounds.moveTo(screen._currentScroll.x + (SHERLOCK_SCREEN_WIDTH - paperFrame._width) / 2,
+ (SHERLOCK_SCREEN_HEIGHT - paperFrame._height) / 2);
+
+ // Clear answer data and set correct solution strings
+ for (int idx = 0; idx < 3; ++idx)
+ Common::fill(&_answers[idx][0], &_answers[idx][10], 0);
+ _solutions[0] = FIXED(Apply);
+ _solutions[1] = FIXED(Water);
+ _solutions[2] = FIXED(Heat);
+
+ // Set up the window background
+ _surface.create(_bounds.width(), _bounds.height());
+ _surface.blitFrom(paperFrame, Common::Point(0, 0));
+
+ // If they have already solved the puzzle, put the answer on the graphic
+ if (_vm->readFlags(299)) {
+ Common::Point cursorPos;
+ for (int line = 0; line < 3; ++line) {
+ cursorPos.y = _lines[line].y - screen.fontHeight() - 2;
+
+ for (uint idx = 0; idx < strlen(_solutions[line]); ++idx) {
+ cursorPos.x = _lines[line].x + 8 - screen.widestChar() / 2 + idx * _spacing;
+ char c = _solutions[line][idx];
+
+ Common::String str = Common::String::format("%c", c);
+ _surface.writeString(str, Common::Point(cursorPos.x + screen.widestChar() / 2
+ - screen.charWidth(c) / 2, cursorPos.y), 0);
+ }
+ }
+ }
+
+ // Show the window
+ summonWindow();
+ ui._menuMode = FOOLSCAP_MODE;
+}
+
+void WidgetFoolscap::handleEvents() {
+ Events &events = *_vm->_events;
+ Screen &screen = *_vm->_screen;
+ TattooUserInterface &ui = *(TattooUserInterface *)_vm->_ui;
+ Common::Point mousePos = events.mousePos();
+ byte cursorColor = 254;
+
+ if (events._firstPress && !_bounds.contains(mousePos))
+ _outsideMenu = true;
+
+ // If they have not solved the puzzle, let them solve it here
+ if (!_vm->readFlags(299)) {
+ if (!ui._keyState.keycode) {
+ if (--_blinkCounter < 0) {
+ _blinkCounter = 3;
+ _blinkFlag = !_blinkFlag;
+
+ if (_blinkFlag) {
+ // Draw the caret
+ _surface.fillRect(Common::Rect(_cursorPos.x, _cursorPos.y, _cursorPos.x + screen.widestChar() - 1,
+ _cursorPos.y + screen.fontHeight() - 1), cursorColor);
+
+ if (_answers[_lineNum][_charNum]) {
+ Common::String str = Common::String::format("%c", _answers[_lineNum][_charNum]);
+ _surface.writeString(str, Common::Point(_cursorPos.x + screen.widestChar() / 2
+ - screen.charWidth(_answers[_lineNum][_charNum]) / 2, _cursorPos.y), 0);
+ }
+ } else {
+ // Restore background
+ restoreChar();
+
+ // Draw the character at that position if there is one
+ if (_answers[_lineNum][_charNum]) {
+ Common::String str = Common::String::format("%c", _answers[_lineNum][_charNum]);
+ _surface.writeString(str, Common::Point(_cursorPos.x + screen.widestChar() / 2
+ - screen.charWidth(_answers[_lineNum][_charNum]) / 2, _cursorPos.y), 0);
+ }
+ }
+ }
+ } else {
+ // Handle keyboard events
+ handleKeyboardEvents();
+ }
+ }
+
+ if ((events._released || events._rightReleased) && _outsideMenu && !_bounds.contains(mousePos)) {
+ // Clicked outside window to close it
+ events.clearEvents();
+ close();
+ }
+}
+
+void WidgetFoolscap::handleKeyboardEvents() {
+ Screen &screen = *_vm->_screen;
+ 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)))) {
+ // 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;
+ }
+
+ // Restore background
+ restoreChar();
+
+ if (_answers[_lineNum][_charNum]) {
+ Common::String str = Common::String::format("%c", _answers[_lineNum][_charNum]);
+ _surface.writeString(str, Common::Point(_cursorPos.x + screen.widestChar() / 2
+ - screen.charWidth(_answers[_lineNum][_charNum]) / 2, _cursorPos.y), 0);
+ }
+
+ switch (keyState.keycode) {
+ case Common::KEYCODE_ESCAPE:
+ close();
+ break;
+
+ case Common::KEYCODE_UP:
+ if (_lineNum) {
+ --_lineNum;
+ if (_charNum >= (int)strlen(_solutions[_lineNum]))
+ _charNum = (int)strlen(_solutions[_lineNum]) - 1;
+ }
+ break;
+
+ case Common::KEYCODE_DOWN:
+ if (_lineNum < 2) {
+ ++_lineNum;
+ if (_charNum >= (int)strlen(_solutions[_lineNum]))
+ _charNum = (int)strlen(_solutions[_lineNum]) - 1;
+ }
+ break;
+
+ case Common::KEYCODE_BACKSPACE:
+ case Common::KEYCODE_LEFT:
+ if (_charNum)
+ --_charNum;
+ else if (_lineNum) {
+ --_lineNum;
+
+ _charNum = strlen(_solutions[_lineNum]) - 1;
+ }
+
+ if (keyState.keycode == Common::KEYCODE_BACKSPACE)
+ _answers[_lineNum][_charNum] = ' ';
+ break;
+
+ case Common::KEYCODE_RIGHT:
+ if (_charNum < (int)strlen(_solutions[_lineNum]) - 1)
+ ++_charNum;
+ else if (_lineNum < 2) {
+ ++_lineNum;
+ _charNum = 0;
+ }
+ break;
+
+ case Common::KEYCODE_DELETE:
+ _answers[_lineNum][_charNum] = ' ';
+ break;
+
+ default:
+ break;
+ }
+
+ _cursorPos.x = _lines[_lineNum].x + 8 - screen.widestChar() / 2 + _charNum * _spacing;
+ _cursorPos.y = _lines[_lineNum].y - screen.fontHeight() - 2;
+
+ // See if all of their anwers are correct
+ if (!scumm_stricmp(_answers[0], _solutions[0]) && !scumm_stricmp(_answers[1], _solutions[1])
+ && !scumm_stricmp(_answers[2], _solutions[2])) {
+ _solved = true;
+ close();
+ }
+}
+
+void WidgetFoolscap::restoreChar() {
+ Screen &screen = *_vm->_screen;
+ ImageFrame &bgFrame = (*_images)[0];
+ _surface.blitFrom(bgFrame, _cursorPos, Common::Rect(_cursorPos.x, _cursorPos.y,
+ _cursorPos.x + screen.widestChar(), _cursorPos.y + screen.fontHeight()));
+}
+
+void WidgetFoolscap::close() {
+ TattooScene &scene = *(TattooScene *)_vm->_scene;
+ Talk &talk = *_vm->_talk;
+ TattooUserInterface &ui = *(TattooUserInterface *)_vm->_ui;
+ delete _images;
+ _images = nullptr;
+
+ // Close the window
+ banishWindow();
+ ui._menuMode = scene._labTableScene ? LAB_MODE : STD_MODE;
+
+ // Don't call the talk files if the puzzle has already been solved
+ if (!_vm->readFlags(299)) {
+ // Run the appropriate script depending on whether or not they solved the puzzle correctly
+ if (_solved) {
+ talk.talkTo("SLVE12S.TLK");
+ talk.talkTo("WATS12X.TLK");
+ _vm->setFlags(299);
+ } else {
+ talk.talkTo("HOLM12X.TLK");
+ }
+ }
+}
+
+} // End of namespace Tattoo
+
+} // End of namespace Sherlock
diff --git a/engines/sherlock/tattoo/widget_foolscap.h b/engines/sherlock/tattoo/widget_foolscap.h
new file mode 100644
index 0000000000..3c85998cee
--- /dev/null
+++ b/engines/sherlock/tattoo/widget_foolscap.h
@@ -0,0 +1,82 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public 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_FOOLSCAP_H
+#define SHERLOCK_TATTOO_FOOLSCAP_H
+
+#include "sherlock/tattoo/widget_base.h"
+#include "sherlock/image_file.h"
+
+namespace Sherlock {
+
+namespace Tattoo {
+
+class TattooEngine;
+
+class WidgetFoolscap: public WidgetBase {
+private:
+ ImageFile *_images;
+ Common::Point _lines[3];
+ char _answers[3][10];
+ const char *_solutions[3];
+ int _numWide;
+ int _spacing;
+ Common::Point _cursorPos;
+ int _blinkCounter;
+ bool _blinkFlag;
+ int _lineNum, _charNum;
+ bool _solved;
+
+ /**
+ * Handle keyboard events
+ */
+ void handleKeyboardEvents();
+
+ /**
+ * Restore the background for the current line/horiz position
+ */
+ void restoreChar();
+public:
+ WidgetFoolscap(TattooEngine *vm);
+ virtual ~WidgetFoolscap();
+
+ /**
+ * Show the foolscap puzzle
+ */
+ void show();
+
+ /**
+ * Close the window
+ */
+ void close();
+
+ /**
+ * Handle events whilst the widget is on-screen
+ */
+ virtual void handleEvents();
+};
+
+} // End of namespace Tattoo
+
+} // End of namespace Sherlock
+
+#endif
diff --git a/engines/sherlock/tattoo/widget_inventory.cpp b/engines/sherlock/tattoo/widget_inventory.cpp
new file mode 100644
index 0000000000..3555ecdffd
--- /dev/null
+++ b/engines/sherlock/tattoo/widget_inventory.cpp
@@ -0,0 +1,789 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public 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/widget_inventory.h"
+#include "sherlock/tattoo/tattoo_fixed_text.h"
+#include "sherlock/tattoo/tattoo_people.h"
+#include "sherlock/tattoo/tattoo_scene.h"
+#include "sherlock/tattoo/tattoo_user_interface.h"
+#include "sherlock/tattoo/tattoo.h"
+
+namespace Sherlock {
+
+namespace Tattoo {
+
+#define INVENTORY_XSIZE 70 // Width of the box that surrounds inventory items
+#define INVENTORY_YSIZE 70 // Height of the box that surrounds inventory items
+#define MAX_INV_COMMANDS 10 // Maximum elements in dialog
+#define NUM_INV_PER_LINE 4 // Number of inentory items per line in the dialog
+
+WidgetInventoryTooltip::WidgetInventoryTooltip(SherlockEngine *vm, WidgetInventory *owner) :
+ WidgetTooltipBase(vm), _owner(owner) {
+}
+
+void WidgetInventoryTooltip::setText(const Common::String &str) {
+ // If no text specified, erase any previously displayed tooltip and free its surface
+ if (str.empty()) {
+ erase();
+ _surface.free();
+ return;
+ }
+
+ int width = _surface.stringWidth(str) + 2;
+ int height = 0;
+ Common::String line1 = str, line2;
+
+ // See if we need to split it into two lines
+ if (width > 150) {
+ // Yes, we do
+ const char *s = str.c_str();
+ const char *space = nullptr;
+ int dif = 10000;
+
+ while (*s) {
+ s = strchr(s, ' ');
+
+ if (!s) {
+ if (!space) {
+ height = _surface.stringHeight(str) + 2;
+ } else {
+ line1 = Common::String(str.c_str(), space);
+ line2 = Common::String(space + 1);
+ height = _surface.stringHeight(line1) + _surface.stringHeight(line2) + 4;
+ }
+ break;
+ } else {
+ line1 = Common::String(str.c_str(), s);
+ line2 = Common::String(s + 1);
+ int width1 = _surface.stringWidth(line1);
+ int width2 = _surface.stringWidth(line2);
+
+ if (ABS(width1 - width2) < dif) {
+ // Found a split point that results in less overall width
+ space = s;
+ dif = ABS(width1 - width2);
+ width = MAX(width1, width2);
+ }
+
+ s++;
+ }
+ }
+ } else {
+ height = _surface.stringHeight(str) + 2;
+ }
+
+ // Allocate a fresh surface for the new string
+ _bounds = Common::Rect(width, height);
+ _surface.create(width, height);
+ _surface.fill(TRANSPARENCY);
+
+ if (line2.empty()) {
+ _surface.writeFancyString(str, Common::Point(0, 0), BLACK, INFO_TOP);
+ } else {
+ int xp, yp;
+
+ xp = (_bounds.width() - _surface.stringWidth(line1) - 2) / 2;
+ _surface.writeFancyString(line1, Common::Point(xp, 0), BLACK, INFO_TOP);
+
+ xp = (_bounds.width() - _surface.stringWidth(line2) - 2) / 2;
+ yp = _surface.stringHeight(line2) + 2;
+ _surface.writeFancyString(line2, Common::Point(xp, yp), BLACK, INFO_TOP);
+ }
+}
+
+void WidgetInventoryTooltip::handleEvents() {
+ Events &events = *_vm->_events;
+ FixedText &fixedText = *_vm->_fixedText;
+ Inventory &inv = *_vm->_inventory;
+ TattooPeople &people = *(TattooPeople *)_vm->_people;
+ Scene &scene = *_vm->_scene;
+ TattooUserInterface &ui = *(TattooUserInterface *)_vm->_ui;
+ Common::Point mousePos = events.mousePos();
+ Common::String str;
+ int select = -1, oldSelect = 999;
+ Common::String strWith = fixedText.getText(kFixedText_With);
+ Common::String strUse = fixedText.getText(kFixedText_Use);
+
+ // Register the tooltip for requiring post-rendering drawing, since we draw directly to the screen if a scene
+ // mask is active, since the initial draw to the screen will be covered by the mask rendering
+ if (ui._mask) {
+ ui._postRenderWidgets.push_back(this);
+ }
+
+ // If we are using an inventory item on an object in the room, display the appropriate text above the mouse cursor
+ if (_owner->_invVerbMode == 3) {
+ select = ui._bgFound;
+ oldSelect = ui._oldBgFound;
+
+ if (select != -1 && (select != oldSelect || (select != -1 && _surface.empty()))) {
+ // See if we're pointing at a shape or a sprite
+ if (select < 1000) {
+ Object &obj = scene._bgShapes[select];
+
+ if (!obj._description.empty() && !obj._description.hasPrefix(" ")) {
+ if (_vm->getLanguage() == Common::GR_GRE) {
+
+ if (!_owner->_swapItems)
+ str = Common::String::format("%s %s %s %s", _owner->_action.c_str(), obj._description.c_str(),
+ inv[_owner->_invSelect]._name.c_str(), _owner->_verb.c_str());
+ else
+ str = Common::String::format("%s %s %s %s", _owner->_action.c_str(), inv[_owner->_invSelect]._name.c_str(),
+ obj._description.c_str(), _owner->_verb.c_str());
+ } else {
+ if (_owner->_swapItems)
+ str = Common::String::format("%s %s %s %s", _owner->_verb.c_str(), obj._description.c_str(), _owner->_action.c_str(),
+ inv[_owner->_invSelect]._name.c_str());
+ else
+ str = Common::String::format("%s %s %s %s", _owner->_verb.c_str(), inv[_owner->_invSelect]._name.c_str(),
+ _owner->_action.c_str(), obj._description.c_str());
+ }
+ }
+ } else {
+ Person &person = people[ui._bgFound - 1000];
+
+ if (!person._description.empty() && !person._description.hasPrefix(" ")) {
+ if (_vm->getLanguage() == Common::GR_GRE) {
+ if (!_owner->_swapItems)
+ str = Common::String::format("%s %s %s %s", _owner->_action.c_str(), person._description.c_str(),
+ inv[_owner->_invSelect]._name.c_str(), _owner->_verb.c_str());
+ else
+ str = Common::String::format("%s %s %s %s", _owner->_action.c_str(), inv[_owner->_invSelect]._name.c_str(),
+ person._description.c_str(), _owner->_verb.c_str());
+ } else {
+
+ if (_owner->_swapItems)
+ str = Common::String::format("%s %s %s %s", _owner->_verb.c_str(), person._description.c_str(),
+ _owner->_action.c_str(), inv[_owner->_invSelect]._name.c_str());
+ else
+ str = Common::String::format("%s %s %s %s", _owner->_verb.c_str(),
+ inv[_owner->_invSelect]._name.c_str(), _owner->_action.c_str(), person._description.c_str());
+ }
+ }
+ }
+ }
+ } else {
+ const Common::Rect &b = _owner->_bounds;
+ Common::Rect r(b.left + 3, b.top + 3, b.right - 3 - BUTTON_SIZE, b.bottom - 3);
+
+ if (r.contains(mousePos)) {
+ select = (mousePos.x - r.left) / (INVENTORY_XSIZE + 3) + NUM_INVENTORY_SHOWN / 2 *
+ ((mousePos.y - r.top) / (INVENTORY_YSIZE + 3)) + inv._invIndex;
+
+ if (select >= inv._holdings) {
+ select = -1;
+ } else {
+ oldSelect = _owner->_invSelect;
+
+ if (select != _owner->_invSelect || _surface.empty()) {
+
+ if (_owner->_invMode == 1) {
+ // See if we were pointing at a shapre or sprite
+ if (ui._activeObj < 1000) {
+ Object &obj = scene._bgShapes[ui._activeObj];
+
+ if (!obj._description.empty() && !obj._description.hasPrefix(" "))
+ str = Common::String::format("%s %s %s %s", strUse.c_str(), inv[select]._name.c_str(),
+ strWith.c_str(), obj._description.c_str());
+ } else {
+ Person &person = people[ui._activeObj - 1000];
+
+ if (!person._description.empty() && !person._description.hasPrefix(" "))
+ str = Common::String::format("%s %s %s %s", strUse.c_str(), inv[select]._name.c_str(),
+ strWith.c_str(), person._description.c_str());
+ }
+ } else {
+ if (_owner->_invVerbMode == 2)
+ str = Common::String::format("%s %s %s %s", strUse.c_str(), inv[_owner->_invSelect]._name.c_str(),
+ strWith.c_str(), inv[select]._name.c_str());
+ else
+ str = inv[select]._description.c_str();
+ }
+ }
+ }
+ }
+ }
+
+ // See if they are pointing at a different inventory object and we need to
+ // change the graphics of the Text Tag
+ if (select != oldSelect || (select != -1 && _surface.empty())) {
+ // Set the text
+ setText(str);
+
+ if (_owner->_invVerbMode != 3)
+ _owner->_invSelect = select;
+ else
+ ui._oldBgFound = select;
+ } else if (select == -1 && oldSelect != -1) {
+ setText(Common::String());
+ return;
+ }
+
+ if (_owner->_invVerbMode == 3)
+ // Adjust tooltip to be above the inventory item being shown above the standard cursor
+ mousePos.y -= events._hotspotPos.y;
+
+ // Update the position of the tooltip
+ int xs = CLIP(mousePos.x - _bounds.width() / 2, 0, SHERLOCK_SCENE_WIDTH - _bounds.width());
+ int ys = CLIP(mousePos.y - _bounds.height(), 0, SHERLOCK_SCREEN_HEIGHT - _bounds.height());
+ _bounds.moveTo(xs, ys);
+}
+
+/*----------------------------------------------------------------*/
+
+WidgetInventoryVerbs::WidgetInventoryVerbs(SherlockEngine *vm, WidgetInventory *owner) :
+ WidgetBase(vm), _owner(owner) {
+ _invVerbSelect = _oldInvVerbSelect = -1;
+}
+
+void WidgetInventoryVerbs::load() {
+ Events &events = *_vm->_events;
+ Inventory &inv = *_vm->_inventory;
+ People &people = *_vm->_people;
+ Scene &scene = *_vm->_scene;
+ TattooUserInterface &ui = *(TattooUserInterface *)_vm->_ui;
+ Common::Point mousePos = events.mousePos();
+
+ // Make the Verb List for this Inventory Item
+ _inventCommands.clear();
+ _inventCommands.push_back(FIXED(Look));
+
+ // Default the Action word to "with"
+ _owner->_action = _vm->getLanguage() == Common::GR_GRE ? "" : FIXED(With);
+
+ // Search all the bgshapes for any matching Target Fields
+ for (uint idx = 0; idx < scene._bgShapes.size(); ++idx) {
+ Object &obj = scene._bgShapes[idx];
+
+ if (obj._type != INVALID && obj._type != HIDDEN) {
+ for (int useNum = 0; useNum < 6; ++useNum) {
+ if (!obj._use[useNum]._verb.hasPrefix("*") &&
+ !obj._use[useNum]._target.compareToIgnoreCase(inv[_owner->_invSelect]._name)) {
+ // Make sure the Verb is not already in the list
+ bool found1 = false;
+ for (uint cmdNum = 0; cmdNum < _inventCommands.size() && !found1; ++cmdNum) {
+ if (!_inventCommands[cmdNum].compareToIgnoreCase(obj._use[useNum]._verb))
+ found1 = true;
+ }
+
+ if (!found1) {
+ _inventCommands.push_back(obj._use[useNum]._verb);
+
+ // Check for any Special Action commands
+ for (int nameNum = 0; nameNum < 4; ++nameNum) {
+ if (!scumm_strnicmp(obj._use[useNum]._names[nameNum].c_str(), "*V", 2)) {
+ if (!scumm_strnicmp(obj._use[useNum]._names[nameNum].c_str(), "*VSWAP", 6))
+ _owner->_swapItems = true;
+ else
+ _owner->_action = Common::String(obj._use[useNum]._names[nameNum].c_str() + 2);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ // Search the NPCs for matches as well
+ for (int idx = 1; idx < MAX_CHARACTERS; ++idx) {
+ for (int useNum = 0; useNum < 2; ++useNum) {
+ if (!people[idx]._use[useNum]._target.compareToIgnoreCase(inv[_owner->_invSelect]._name) &&
+ !people[idx]._use[useNum]._verb.empty() && !people[idx]._use[useNum]._verb.hasPrefix(" ")) {
+ bool found1 = false;
+ for (uint cmdNum = 0; cmdNum < _inventCommands.size() && !found1; ++cmdNum) {
+ if (!_inventCommands[cmdNum].compareToIgnoreCase(people[idx]._use[cmdNum]._verb))
+ found1 = true;
+ }
+
+ if (!found1)
+ _inventCommands.push_back(people[idx]._use[useNum]._verb);
+ }
+ }
+ }
+
+ // Finally see if the item itself has a verb
+ if (!inv[_owner->_invSelect]._verb._verb.empty()) {
+ // Don't add "Solve" to the Foolscap if it's already been "Solved"
+ if (inv[_owner->_invSelect]._verb._verb.compareToIgnoreCase(FIXED(Solve)) || !_vm->readFlags(299))
+ _inventCommands.push_back(inv[_owner->_invSelect]._verb._verb);
+ }
+
+ // Now find the widest command in the _inventCommands array
+ int width = 0;
+ for (uint idx = 0; idx < _inventCommands.size(); ++idx)
+ width = MAX(width, _surface.stringWidth(_inventCommands[idx]));
+
+ // Set up bounds for the menu
+ _bounds = Common::Rect(width + _surface.widestChar() * 2 + 6,
+ (_surface.fontHeight() + 7) * _inventCommands.size() + 3);
+ _bounds.moveTo(mousePos.x - _bounds.width() / 2, mousePos.y - _bounds.height() / 2);
+
+ // Create the surface
+ _surface.create(_bounds.width(), _bounds.height());
+ _surface.fill(TRANSPARENCY);
+ makeInfoArea();
+
+ // Draw the Verb commands and the lines separating them
+ ImageFile &images = *ui._interfaceImages;
+ for (int idx = 0; idx < (int)_inventCommands.size(); ++idx) {
+ _surface.writeString(_inventCommands[idx], Common::Point((_bounds.width() -
+ _surface.stringWidth(_inventCommands[idx])) / 2, (_surface.fontHeight() + 7) * idx + 5), INFO_TOP);
+
+ if (idx < (int)_inventCommands.size() - 1) {
+ _surface.vLine(3, (_surface.fontHeight() + 7) * (idx + 1), _bounds.right - 4, INFO_TOP);
+ _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.fontHeight() + 7) * (idx + 1) - 1));
+ }
+ }
+
+ summonWindow();
+}
+
+void WidgetInventoryVerbs::handleEvents() {
+ Events &events = *_vm->_events;
+ Inventory &inv = *_vm->_inventory;
+ TattooScene &scene = *(TattooScene *)_vm->_scene;
+ Common::Point mousePos = events.mousePos();
+ TattooUserInterface &ui = *(TattooUserInterface *)_vm->_ui;
+ TattooEngine &vm = *(TattooEngine *)_vm;
+
+ // Handle changing highlighted verb entry
+ highlightControls();
+
+ // See if they want to close the menu (by clicking outside the menu)
+ Common::Rect innerBounds = _bounds;
+ innerBounds.grow(-3);
+
+ // Flag is they started pressing outside of the menu
+ if (events._firstPress && !_bounds.contains(mousePos))
+ _outsideMenu = true;
+
+ if (events._released || events._rightReleased || ui._keyState.keycode == Common::KEYCODE_ESCAPE) {
+ ui._scrollHighlight = SH_NONE;
+ banishWindow();
+
+ if ((_outsideMenu && !innerBounds.contains(mousePos)) || ui._keyState.keycode == Common::KEYCODE_ESCAPE) {
+ _owner->_invVerbMode = 0;
+ } else if (innerBounds.contains(mousePos)) {
+ _outsideMenu = false;
+
+ // Check if they are trying to solve the Foolscap puzzle, or looking at the completed puzzle
+ bool doFoolscap = !inv[_owner->_invSelect]._name.compareToIgnoreCase(FIXED(Inv6)) &&
+ !_inventCommands[_invVerbSelect].compareToIgnoreCase(FIXED(Solve));
+ doFoolscap |= (!inv[_owner->_invSelect]._name.compareToIgnoreCase(FIXED(Inv6)) || !inv[_owner->_invSelect]._name.compareToIgnoreCase(FIXED(Inv7)))
+ && !_inventCommands[_invVerbSelect].compareToIgnoreCase(FIXED(Look)) && vm.readFlags(299);
+
+ if (doFoolscap) {
+ // Close the entire Inventory and return to Standard Mode
+ _owner->_invVerbMode = 0;
+
+ _owner->_tooltipWidget.banishWindow();
+ _owner->banishWindow();
+ inv.freeInv();
+
+ events.clearEvents();
+ vm.doFoolscapPuzzle();
+ } else if (_invVerbSelect == 0) {
+ // They have released the mouse on the Look Verb command, so Look at the inventory item
+ ui._invLookFlag = true;
+ inv.freeInv();
+ ui._windowOpen = false;
+ ui._lookPos = mousePos;
+ ui.printObjectDesc(inv[_owner->_invSelect]._examine, true);
+ } else {
+ _owner->_invVerbMode = 3;
+ ui._oldBgFound = -1;
+
+ // See if the selected Verb with the selected Iventory Item, is to be used by itself
+ if (!_inventCommands[_invVerbSelect].compareToIgnoreCase(inv[_owner->_invSelect]._verb._verb) ||
+ !inv[_owner->_invSelect]._verb._target.compareToIgnoreCase("*SELF")) {
+ inv.freeInv();
+
+ ui._menuMode = scene._labTableScene ? LAB_MODE : STD_MODE;
+ events.clearEvents();
+ ui.checkAction(inv[_owner->_invSelect]._verb, 2000);
+ } else {
+ _owner->_verb = _inventCommands[_invVerbSelect];
+ }
+
+ // If we are still in Inventory Mode, setup the graphic to float in front of the mouse cursor
+ if (ui._menuMode == INV_MODE) {
+ // Add the inventory item to the cursor
+ ImageFrame &imgFrame = (*inv._invShapes[_owner->_invSelect - inv._invIndex])[0];
+ events.setCursor(ARROW, Common::Point(-100, imgFrame._height), imgFrame._frame);
+
+ // Close the inventory dialog without banishing it, so it can keep getting events
+ // to handle tooltips and actually making the selection of what object to use them item on
+ inv.freeInv();
+ _owner->_surface.free();
+ }
+ }
+ }
+ }
+}
+
+void WidgetInventoryVerbs::highlightControls() {
+ Events &events = *_vm->_events;
+ Common::Point mousePos = events.mousePos();
+
+ Common::Rect innerBounds = _bounds;
+ innerBounds.grow(-3);
+
+ // Set the highlighted verb
+ _invVerbSelect = -1;
+ if (innerBounds.contains(mousePos))
+ _invVerbSelect = (mousePos.y - _bounds.top - 3) / (_surface.fontHeight() + 7);
+
+ // See if the highlighted verb has changed
+ if (_invVerbSelect != _oldInvVerbSelect) {
+ // Draw the list again, with the new highlighting
+ for (int idx = 0; idx < (int)_inventCommands.size(); ++idx) {
+ byte color = (idx == _invVerbSelect) ? COMMAND_HIGHLIGHTED : INFO_TOP;
+ _surface.writeString(_inventCommands[idx], Common::Point(
+ (_bounds.width() - _surface.stringWidth(_inventCommands[idx])) / 2,
+ (_surface.fontHeight() + 7) * idx + 5), color);
+ }
+
+ _oldInvVerbSelect = _invVerbSelect;
+ }
+}
+
+/*----------------------------------------------------------------*/
+
+WidgetInventory::WidgetInventory(SherlockEngine *vm) : WidgetBase(vm),
+ _tooltipWidget(vm, this), _verbList(vm, this) {
+ _invMode = 0;
+ _invVerbMode = 0;
+ _invSelect = _oldInvSelect = -1;
+ _selector = _oldSelector = -1;
+ _swapItems = false;
+}
+
+void WidgetInventory::load(int mode) {
+ Events &events = *_vm->_events;
+ Inventory &inv = *_vm->_inventory;
+ Screen &screen = *_vm->_screen;
+ Common::Point mousePos = events.mousePos();
+
+ if (mode == 3) {
+ mode = 2;
+ mousePos = Common::Point(screen._currentScroll.x + SHERLOCK_SCREEN_WIDTH / 2, SHERLOCK_SCREEN_HEIGHT / 2);
+ }
+
+ if (mode != 0)
+ _invMode = mode;
+ _invVerbMode = 0;
+ _invSelect = _oldInvSelect = -1;
+ _selector = _oldSelector = -1;
+ _scroll = true;
+
+ if (mode == 0) {
+ banishWindow();
+ } else {
+ _bounds = Common::Rect((INVENTORY_XSIZE + 3) * NUM_INVENTORY_SHOWN / 2 + BUTTON_SIZE + 6,
+ (INVENTORY_YSIZE + 3) * 2 + 3);
+ _bounds.moveTo(mousePos.x - _bounds.width() / 2, mousePos.y - _bounds.height() / 2);
+ }
+
+ // Ensure menu will be on-screen
+ restrictToScreen();
+
+ // Load the inventory data
+ inv.loadInv();
+
+ // Redraw the inventory menu on the widget surface
+ _surface.create(_bounds.width(), _bounds.height());
+ _surface.fill(TRANSPARENCY);
+
+ // Draw the window background and then the inventory on top of it
+ makeInfoArea(_surface);
+ drawBars();
+ drawInventory();
+}
+
+void WidgetInventory::drawBars() {
+ TattooUserInterface &ui = *(TattooUserInterface *)_vm->_ui;
+ ImageFile &images = *ui._interfaceImages;
+ int x;
+
+ _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));
+
+ for (int idx = 1; idx <= NUM_INVENTORY_SHOWN / 2; ++idx) {
+ x = idx * (INVENTORY_XSIZE + 3);
+
+ _surface.vLine(x, 3, _bounds.height() - 4, INFO_TOP);
+ _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.hLine(x + 2, INVENTORY_YSIZE + 2, INVENTORY_YSIZE + 8, INFO_BOTTOM);
+}
+
+void WidgetInventory::drawInventory() {
+ Inventory &inv = *_vm->_inventory;
+
+ // TODO: Refactor _invIndex into this widget class
+ for (int idx = 0, itemId = inv._invIndex; idx < NUM_INVENTORY_SHOWN; ++idx, ++itemId) {
+ // Figure out the drawing position
+ Common::Point pt(3 + (INVENTORY_XSIZE + 3) * (idx % (NUM_INVENTORY_SHOWN / 2)),
+ 3 + (INVENTORY_YSIZE + 3) * (idx / (NUM_INVENTORY_SHOWN / 2)));
+
+ // Draw the box to serve as the background for the item
+ _surface.hLine(pt.x + 1, pt.y, pt.x + INVENTORY_XSIZE - 2, TRANSPARENCY);
+ _surface.fillRect(Common::Rect(pt.x, pt.y + 1, pt.x + INVENTORY_XSIZE, pt.y + INVENTORY_YSIZE - 1), TRANSPARENCY);
+ _surface.hLine(pt.x + 1, pt.y + INVENTORY_YSIZE - 1, pt.x + INVENTORY_XSIZE - 2, TRANSPARENCY);
+
+ // 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,
+ pt.y + (INVENTORY_YSIZE - img._height) / 2));
+ }
+ }
+
+ drawScrollBar(inv._invIndex / NUM_INV_PER_LINE, NUM_INVENTORY_SHOWN / NUM_INV_PER_LINE,
+ (inv._holdings + NUM_INV_PER_LINE - 1) / NUM_INV_PER_LINE);
+}
+
+void WidgetInventory::handleEvents() {
+ TattooEngine &vm = *(TattooEngine *)_vm;
+ Events &events = *_vm->_events;
+ Inventory &inv = *_vm->_inventory;
+ People &people = *_vm->_people;
+ TattooScene &scene = *(TattooScene *)_vm->_scene;
+ TattooUserInterface &ui = *(TattooUserInterface *)_vm->_ui;
+ Common::Point mousePos = events.mousePos();
+
+ if (_invVerbMode == 1) {
+ checkTabbingKeys(MAX_INV_COMMANDS);
+ } else if (_invVerbMode == 0) {
+ checkInvTabbingKeys();
+
+ // Handle scrollbar events
+ int oldScrollIndex = inv._invIndex / NUM_INV_PER_LINE;
+ int invIndex = inv._invIndex / NUM_INV_PER_LINE;
+
+ ScrollHighlight oldHighlight = ui._scrollHighlight;
+ handleScrollbarEvents(invIndex, NUM_INVENTORY_SHOWN / NUM_INV_PER_LINE,
+ (inv._holdings + NUM_INV_PER_LINE - 1) / NUM_INV_PER_LINE);
+
+ handleScrolling(invIndex, NUM_INVENTORY_SHOWN / NUM_INV_PER_LINE,
+ (inv._holdings + NUM_INV_PER_LINE - 1) / NUM_INV_PER_LINE);
+
+ if (oldScrollIndex != invIndex) {
+ // Starting visible item index has changed, so set the index and reload inventory graphics
+ inv._invIndex = invIndex * NUM_INV_PER_LINE;
+ inv.freeGraphics();
+ inv.loadGraphics();
+ }
+
+ if (ui._scrollHighlight != oldHighlight || oldScrollIndex != invIndex) {
+ drawInventory();
+ return;
+ }
+ }
+
+ if (_invVerbMode != 1)
+ _tooltipWidget.handleEvents();
+
+ // Flag is they started pressing outside of the menu
+ if (events._firstPress && !_bounds.contains(mousePos))
+ _outsideMenu = true;
+
+ if (_invVerbMode != 3)
+ highlightControls();
+
+ // See if they released a mouse button button
+ if (events._released || events._rightReleased || ui._keyState.keycode == Common::KEYCODE_ESCAPE) {
+ ui._scrollHighlight = SH_NONE;
+
+ // See if they have a Verb List open for an Inventry Item
+ if (_invVerbMode == 1)
+ return;
+
+ if (_invVerbMode == 3) {
+ // Selecting object after inventory verb has been selected
+ _tooltipWidget.banishWindow();
+ close();
+
+ if (ui._keyState.keycode != Common::KEYCODE_ESCAPE) {
+ // If user pointed at an item, use the selected inventory item with this item
+ bool found = false;
+ if (ui._bgFound != -1) {
+ if (ui._personFound) {
+ 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);
+ found = true;
+ }
+ }
+ } else {
+ for (int idx = 0; idx < 6; ++idx) {
+ if (!ui._bgShape->_use[idx]._verb.compareToIgnoreCase(_verb) &&
+ !ui._bgShape->_use[idx]._target.compareToIgnoreCase(_invTarget)) {
+ ui.checkAction(ui._bgShape->_use[idx], ui._bgFound);
+ found = true;
+ }
+ }
+ }
+ }
+
+ if (!found)
+ ui.putMessage("%s", FIXED(NoEffect));
+ }
+ } else if ((_outsideMenu && !_bounds.contains(mousePos)) || ui._keyState.keycode == Common::KEYCODE_ESCAPE) {
+ // Want to close the window (clicked outside of it). So close the window and return to Standard
+ close();
+
+ } else if (_bounds.contains(mousePos)) {
+ // Mouse button was released inside the inventory window
+ _outsideMenu = false;
+
+ // See if they are pointing at one of the inventory items
+ if (_invSelect != -1) {
+ // See if they are in Use Obj with Inv. Mode (they right clicked on an item
+ // in the room and selected "Use with Inv.")
+ if (_invMode == 1) {
+ _tooltipWidget.banishWindow();
+ banishWindow();
+
+ // See if the item in the room that they started with was a person
+ bool found = false;
+ if (ui._activeObj >= 1000) {
+ // Object was a person, activate anything in his two verb fields
+ for (int idx = 0; idx < 2; ++idx) {
+ if (!people[ui._activeObj - 1000]._use[idx]._target.compareToIgnoreCase(inv[_invSelect]._name)) {
+ ui.checkAction(people[ui._activeObj - 1000]._use[idx], ui._activeObj);
+ found = true;
+ }
+ }
+ } else {
+ // Object was a regular object, activate anything in its verb fields
+ for (int idx = 0; idx < 6; ++idx) {
+ if (!scene._bgShapes[ui._activeObj]._use[idx]._target.compareToIgnoreCase(inv[_invSelect]._name)) {
+ ui.checkAction(scene._bgShapes[ui._activeObj]._use[idx], ui._activeObj);
+ found = true;
+ }
+ }
+ }
+ if (!found)
+ ui.putMessage("%s", FIXED(NoEffect));
+
+ } else {
+ // See if they right clicked on an item
+ if (events._rightReleased) {
+ _invVerbMode = 1;
+ _verbList._oldInvVerbSelect = -1;
+ _tooltipWidget.banishWindow();
+
+ // Keep track of the name of the inventory object so we can check it against the target fields
+ // of verbs when we activate it
+ _invTarget = inv[_invSelect]._name;
+ _swapItems = false;
+
+ _verbList.load();
+ } else {
+ // They left clicked on an inventory item, so Look at it
+
+ // Check if they are looking at the solved Foolscap
+ if ((!inv[_invSelect]._name.compareToIgnoreCase(FIXED(Inv6)) || !inv[_invSelect]._name.compareToIgnoreCase(FIXED(Inv7)))
+ && vm.readFlags(299)) {
+ banishWindow();
+ _tooltipWidget.erase();
+
+ _invVerbMode = 0;
+ inv.freeInv();
+
+ events.clearEvents();
+ events.setCursor(ARROW);
+ ui._menuMode = scene._labTableScene ? LAB_MODE : STD_MODE;
+
+ scene.doBgAnim();
+ vm.doFoolscapPuzzle();
+ } else {
+ ui._invLookFlag = true;
+ inv.freeInv();
+
+ _tooltipWidget.banishWindow();
+ ui._windowOpen = false;
+ ui._lookPos = mousePos;
+ ui.printObjectDesc(inv[_invSelect]._examine, true);
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+void WidgetInventory::checkInvTabbingKeys() {
+}
+
+void WidgetInventory::highlightControls() {
+ // TODO
+}
+
+void WidgetInventory::banishWindow() {
+ WidgetBase::banishWindow();
+
+ _verbList.banishWindow();
+}
+
+void WidgetInventory::draw() {
+ WidgetBase::draw();
+ _tooltipWidget.draw();
+}
+
+void WidgetInventory::erase() {
+ WidgetBase::erase();
+ _tooltipWidget.erase();
+}
+
+void WidgetInventory::close() {
+ Events &events = *_vm->_events;
+ Inventory &inv = *_vm->_inventory;
+ TattooScene &scene = *(TattooScene *)_vm->_scene;
+ TattooUserInterface &ui = *(TattooUserInterface *)_vm->_ui;
+
+ banishWindow();
+ inv.freeInv();
+ events.clearEvents();
+
+ events.setCursor(ARROW);
+ ui._menuMode = scene._labTableScene ? LAB_MODE : STD_MODE;
+}
+
+} // End of namespace Tattoo
+
+} // End of namespace Sherlock
diff --git a/engines/sherlock/tattoo/widget_inventory.h b/engines/sherlock/tattoo/widget_inventory.h
new file mode 100644
index 0000000000..a051c328e9
--- /dev/null
+++ b/engines/sherlock/tattoo/widget_inventory.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.
+ *
+ */
+
+#ifndef SHERLOCK_TATTOO_WIDGET_INVENTORY_H
+#define SHERLOCK_TATTOO_WIDGET_INVENTORY_H
+
+#include "common/scummsys.h"
+#include "sherlock/tattoo/widget_base.h"
+#include "sherlock/tattoo/widget_tooltip.h"
+
+namespace Sherlock {
+
+class SherlockEngine;
+
+namespace Tattoo {
+
+#define NUM_INVENTORY_SHOWN 8 // Number of Inventory Items Shown
+
+class WidgetInventory;
+
+class WidgetInventoryTooltip: public WidgetTooltipBase {
+private:
+ WidgetInventory *_owner;
+protected:
+ /**
+ * Overriden from base class, since tooltips have a completely transparent background
+ */
+ virtual void drawBackground() {}
+public:
+ WidgetInventoryTooltip(SherlockEngine *vm, WidgetInventory *owner);
+ virtual ~WidgetInventoryTooltip() {}
+
+ /**
+ * Set the text for the tooltip
+ */
+ void setText(const Common::String &str);
+
+ /**
+ * Handle updating the tooltip state
+ */
+ virtual void handleEvents();
+};
+
+class WidgetInventoryVerbs : public WidgetBase {
+private:
+ WidgetInventory *_owner;
+ Common::StringArray _inventCommands;
+
+ void highlightControls();
+public:
+ int _invVerbSelect, _oldInvVerbSelect;
+public:
+ WidgetInventoryVerbs(SherlockEngine *vm, WidgetInventory *owner);
+ virtual ~WidgetInventoryVerbs() {}
+
+ void load();
+
+ /**
+ * Handle updating the tooltip state
+ */
+ virtual void handleEvents();
+};
+
+class WidgetInventory: public WidgetBase {
+ friend class WidgetInventoryTooltip;
+ friend class WidgetInventoryVerbs;
+private:
+ int _invVerbMode;
+ int _selector, _oldSelector;
+ int _invSelect, _oldInvSelect;
+ WidgetInventoryTooltip _tooltipWidget;
+ WidgetInventoryVerbs _verbList;
+ bool _swapItems;
+ Surface _menuSurface;
+ Common::String _invTarget;
+
+ /**
+ * Draw the bars within the dialog
+ */
+ void drawBars();
+
+ /**
+ * Check for keys to mouse the mouse within the inventory dialog
+ */
+ void checkInvTabbingKeys();
+
+ /**
+ * Highlights the controls
+ */
+ void highlightControls();
+public:
+ int _invMode;
+ Common::String _action;
+ Common::String _verb;
+public:
+ WidgetInventory(SherlockEngine *vm);
+ virtual ~WidgetInventory() {}
+
+ /**
+ * Load the inventory window
+ */
+ void load(int mode);
+
+ /**
+ * Draw the inventory on the surface
+ */
+ void drawInventory();
+
+ /**
+ * Close the window
+ */
+ void close();
+
+ /**
+ * Handle events whilst the widget is on-screen
+ */
+ virtual void handleEvents();
+
+ /**
+ * Close a currently active menu
+ */
+ virtual void banishWindow();
+
+ /**
+ * Erase any previous display of the widget on the screen
+ */
+ virtual void erase();
+
+ /**
+ * Update the display of the widget on the screen
+ */
+ virtual void draw();
+};
+
+} // End of namespace Tattoo
+
+} // End of namespace Sherlock
+
+#endif
diff --git a/engines/sherlock/tattoo/widget_lab.cpp b/engines/sherlock/tattoo/widget_lab.cpp
new file mode 100644
index 0000000000..2873b12f22
--- /dev/null
+++ b/engines/sherlock/tattoo/widget_lab.cpp
@@ -0,0 +1,198 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public 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/widget_lab.h"
+#include "sherlock/tattoo/tattoo_fixed_text.h"
+#include "sherlock/tattoo/tattoo_user_interface.h"
+#include "sherlock/tattoo/tattoo.h"
+
+namespace Sherlock {
+
+namespace Tattoo {
+
+WidgetLab::WidgetLab(SherlockEngine *vm) : WidgetBase(vm) {
+ _labObject = nullptr;
+}
+
+void WidgetLab::summonWindow() {
+ WidgetBase::summonWindow();
+ _labObject = nullptr;
+}
+
+void WidgetLab::handleEvents() {
+ Events &events = *_vm->_events;
+ Scene &scene = *_vm->_scene;
+ TattooUserInterface &ui = *(TattooUserInterface *)_vm->_ui;
+ Common::Point mousePos = events.mousePos();
+
+ WidgetBase::handleEvents();
+ bool noDesc = false;
+
+ // Handle drawing tooltips. If the user is dragging a lab item, display a tooltip for using the item
+ // on another. Otherwise, fall back on showing standard tooltips
+ if (events.getCursor() == INVALID_CURSOR)
+ displayLabNames();
+ else
+ ui.displayObjectNames();
+
+ // See if they've released a mouse button to do an action
+ if (events._released || events._rightReleased) {
+ // See if the mouse was released in an exit/arrow zone (ie. the "Exit" button)
+ ui._exitZone = -1;
+ if (ui._arrowZone != -1 && events._released)
+ ui._exitZone = ui._arrowZone;
+
+ // Turn any current tooltip off
+ if (ui._arrowZone == -1 || events._rightReleased)
+ ui._tooltipWidget.setText("");
+
+ if (ui._bgFound != -1) {
+ if (ui._bgShape->_description.hasPrefix(" ") || ui._bgShape->_description.empty())
+ noDesc = true;
+ } else {
+ noDesc = true;
+ }
+
+ events.setCursor(ARROW);
+
+ if (events._rightReleased) {
+ // If the player is dragging an object around, restore it to its previous location and reset the cursor
+ if (_labObject) {
+ _labObject->toggleHidden();
+
+ // Toggle any other objects (like shadows) tied to this object
+ for (int idx = 0; idx < 6; ++idx) {
+ if (!_labObject->_use[idx]._target.compareToIgnoreCase("Toggle")) {
+ for (int nameNum = 0; nameNum < 4; ++nameNum)
+ scene.toggleObject(_labObject->_use[idx]._names[nameNum]);
+ }
+ }
+
+ events.setCursor(ARROW);
+ }
+
+ // Show the command list for this object
+ ui._verbsWidget.load(!noDesc);
+ } else if (!noDesc) {
+ // The player has released on an object, see if they had an object selected
+ // that will be used with this new object
+ if (_labObject) {
+ // See if the dragged object can be used with the new object
+ for (int idx = 0; idx < 6; ++idx) {
+ // See if the name of the dragged object is in any of the Target
+ // fields of the verbs for the new object
+ if (!_labObject->_name.compareToIgnoreCase(ui._bgShape->_use[idx]._target.c_str())) {
+ // This object can be used, so use it
+ ui.checkAction(ui._bgShape->_use[idx], ui._bgFound);
+ ui._activeObj = -1;
+ }
+ }
+
+ // Restore the dragged object to its previous location
+ _labObject->toggleHidden();
+
+ // Toggle any other objects (like shadows) tied to this object
+ for (int idx = 0; idx < 6; ++idx) {
+ if (!_labObject->_use[idx]._target.compareToIgnoreCase("Toggle")) {
+ for (int nameNum = 0; nameNum < 4; ++nameNum)
+ scene.toggleObject(_labObject->_use[idx]._names[nameNum]);
+ }
+ }
+ } else if (!ui._bgShape->_name.compareToIgnoreCase("Exit")) {
+ // Execute the Exit button's script, which will leave the scene
+ ui.lookAtObject();
+ }
+ } else {
+ // The player has released the mouse while NOT over an object. If theu were dragging an object
+ // around with the mouse, restore it to its previous location and reset the cursor
+ if (_labObject) {
+ _labObject->toggleHidden();
+
+ // Toggle any other objects (like shadows) tied to this object
+ for (int idx = 0; idx < 6; ++idx) {
+ if (!_labObject->_use[idx]._target.compareToIgnoreCase("Toggle")) {
+ for (int nameNum = 0; nameNum < 4; ++nameNum)
+ scene.toggleObject(_labObject->_use[idx]._names[nameNum]);
+ }
+ }
+ }
+ }
+
+ _labObject = nullptr;
+ ui._tooltipWidget._offsetY = 0;
+ } else if (events._pressed && !_labObject) {
+ // If the mouse is over an object and the object is not SOLID, then we need to pick this object
+ // up so the player can move it around
+ if (ui._bgFound != -1) {
+ // Check if the object is set as SOLID, you can't pick up Solid items
+ if (ui._bgShape->_aType != SOLID && ui._bgShape->_type != NO_SHAPE) {
+ // Save a reference to the object about to be dragged
+ _labObject = ui._bgShape;
+
+ // Set the mouse cursor to the object
+ Graphics::Surface &img = _labObject->_imageFrame->_frame;
+ Common::Point cursorOffset = mousePos - _labObject->_position;
+ events.setCursor(ARROW, cursorOffset, img);
+ ui._tooltipWidget._offsetY = cursorOffset.y;
+
+ // Hide this object until they are done with it (releasing it)
+ _labObject->toggleHidden();
+
+ // Toggle any other objects (like shadows) tied to this object
+ for (int idx = 0; idx < 6; ++idx) {
+ if (!_labObject->_use[idx]._target.compareToIgnoreCase("Toggle")) {
+ for (int nameNum = 0; nameNum < 4; ++nameNum)
+ scene.toggleObject(_labObject->_use[idx]._names[nameNum]);
+ }
+ }
+ }
+ }
+ }
+}
+
+void WidgetLab::displayLabNames() {
+ TattooUserInterface &ui = *(TattooUserInterface *)_vm->_ui;
+
+ // See if thay are pointing at a different object and we need to change the tooltip
+ if (ui._bgFound != ui._oldBgFound) {
+ // See if there is a new object to be displayed
+ if (ui._bgFound == -1) {
+ ui._tooltipWidget.setText("");
+ } else {
+ Common::String str = Common::String::format("%s %s %s %s", FIXED(Use), _labObject->_description.c_str(),
+ FIXED(With), ui._bgShape->_description.c_str());
+
+ // Make sure that the Object has a name
+ if (!ui._bgShape->_description.empty() && !ui._bgShape->_description.hasPrefix(" ")) {
+ ui._tooltipWidget.setText(str);
+ } else {
+ ui._tooltipWidget.setText("");
+ }
+ }
+ }
+
+ ui._oldArrowZone = ui._arrowZone;
+}
+
+} // End of namespace Tattoo
+
+} // End of namespace Sherlock
diff --git a/engines/sherlock/tattoo/widget_lab.h b/engines/sherlock/tattoo/widget_lab.h
new file mode 100644
index 0000000000..2f19200b81
--- /dev/null
+++ b/engines/sherlock/tattoo/widget_lab.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 SHERLOCK_TATTOO_WIDGET_LAB_H
+#define SHERLOCK_TATTOO_WIDGET_LAB_H
+
+#include "common/scummsys.h"
+#include "sherlock/tattoo/widget_base.h"
+#include "sherlock/objects.h"
+
+namespace Sherlock {
+
+class SherlockEngine;
+
+namespace Tattoo {
+
+class WidgetLab: public WidgetBase {
+private:
+ Object *_labObject;
+
+ /**
+ * Display tooltips of an object being dragged along with any object the dragged
+ * object is currently over
+ */
+ void displayLabNames();
+public:
+ Common::String _remainingText;
+public:
+ WidgetLab(SherlockEngine *vm);
+ virtual ~WidgetLab() {}
+
+ /**
+ * Summon the window
+ */
+ virtual void summonWindow();
+
+ /**
+ * Handle event processing
+ */
+ virtual void handleEvents();
+};
+
+} // End of namespace Tattoo
+
+} // End of namespace Sherlock
+
+#endif
diff --git a/engines/sherlock/tattoo/widget_options.cpp b/engines/sherlock/tattoo/widget_options.cpp
new file mode 100644
index 0000000000..5dc6fc55b9
--- /dev/null
+++ b/engines/sherlock/tattoo/widget_options.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.
+ *
+ */
+
+#include "sherlock/tattoo/widget_options.h"
+#include "sherlock/tattoo/tattoo.h"
+#include "sherlock/tattoo/tattoo_fixed_text.h"
+#include "sherlock/tattoo/tattoo_scene.h"
+#include "sherlock/tattoo/tattoo_user_interface.h"
+
+namespace Sherlock {
+
+namespace Tattoo {
+
+WidgetOptions::WidgetOptions(SherlockEngine *vm) : WidgetBase(vm) {
+ _midiSliderX = _digiSliderX = 0;
+ _selector = _oldSelector = -1;
+}
+
+void WidgetOptions::load() {
+ Events &events = *_vm->_events;
+ TattooUserInterface &ui = *(TattooUserInterface *)_vm->_ui;
+ _centerPos = events.mousePos();
+
+ render();
+
+ summonWindow();
+ ui._menuMode = OPTION_MODE;
+}
+
+void WidgetOptions::handleEvents() {
+ TattooEngine &vm = *(TattooEngine *)_vm;
+ Events &events = *_vm->_events;
+ Music &music = *_vm->_music;
+ Screen &screen = *_vm->_screen;
+ Sound &sound = *_vm->_sound;
+ Talk &talk = *_vm->_talk;
+ TattooUserInterface &ui = *(TattooUserInterface *)_vm->_ui;
+ Common::Point mousePos = events.mousePos();
+
+ if (talk._talkToAbort) {
+ sound.stopSound();
+ return;
+ }
+
+ // Flag if they started pressing outside the window
+ if (events._firstPress && !_bounds.contains(mousePos))
+ _outsideMenu = true;
+
+ if (events.kbHit()) {
+ ui._keyState = events.getKey();
+
+ // Emulate a mouse release if Enter or Space Bar is pressed
+ if (ui._keyState.keycode == Common::KEYCODE_RETURN || ui._keyState.keycode == Common::KEYCODE_SPACE) {
+ events._pressed = events._oldButtons = false;
+ events._released = true;
+ } else if (ui._keyState.keycode == Common::KEYCODE_ESCAPE) {
+ close();
+ return;
+ } else {
+ checkTabbingKeys(11);
+ }
+ }
+
+ // Check highlighting the various controls
+ if (_bounds.contains(mousePos)) {
+ _selector = (mousePos.y - _bounds.top) / (_surface.fontHeight() + 7);
+
+ // If one of the sliders has been selected, & the mouse is not pressed, reset the selector to -1
+ if ((_selector == 3 || _selector == 6) && !events._pressed)
+ _selector = -1;
+ } else {
+ _selector = -1;
+ if (_outsideMenu && (events._released || events._rightReleased)) {
+ events.clearEvents();
+ close();
+ return;
+ }
+ }
+
+ // If the selected control has changed, redraw the dialog contents
+ if (_selector != _oldSelector)
+ render(OP_CONTENTS);
+ _oldSelector = _selector;
+
+ // Adjust the Volume Sliders (if neccessary) here
+ switch (_selector) {
+ case 3: {
+ // Set Music Volume
+ _midiSliderX = mousePos.x - _bounds.left;
+ if (_midiSliderX < _surface.widestChar())
+ _midiSliderX = _surface.widestChar();
+ else
+ if (_midiSliderX > _bounds.width() - _surface.widestChar())
+ _midiSliderX = _bounds.width() - _surface.widestChar();
+
+ int newVolume = (_midiSliderX - _surface.widestChar()) * 255 / (_bounds.width() - _surface.widestChar() * 2);
+ if (newVolume != music._musicVolume) {
+ music.setMusicVolume(newVolume);
+ vm.saveConfig();
+ }
+
+ render(OP_NAMES);
+ break;
+ }
+
+ case 6: {
+ // Set Digitized Volume
+ _digiSliderX = mousePos.x - _bounds.left;
+ if (_digiSliderX < _surface.widestChar())
+ _digiSliderX = _surface.widestChar();
+ 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);
+ vm.saveConfig();
+ }
+
+ render(OP_NAMES);
+ break;
+ }
+
+ default:
+ break;
+ }
+
+ // Option selected
+ if (events._released || events._rightReleased) {
+ events.clearEvents();
+ _outsideMenu = false;
+ int temp = _selector;
+ _selector = -1;
+
+ switch (temp) {
+ case 0:
+ // Load Game
+ close();
+ ui.loadGame();
+ break;
+
+ case 1:
+ // Save Game
+ close();
+ ui.saveGame();
+ break;
+
+ case 2:
+ // Toggle Music
+ music._musicOn = !music._musicOn;
+ if (!music._musicOn)
+ music.stopMusic();
+ else
+ music.startSong();
+
+ render(OP_NAMES);
+ vm.saveConfig();
+ break;
+
+ case 4:
+ // Toggle Sound Effects
+ sound.stopSound();
+ sound._digitized = !sound._digitized;
+
+ render(OP_NAMES);
+ vm.saveConfig();
+ break;
+
+ case 5:
+ // Toggle Voices
+ sound._voices = !sound._voices;
+
+ render(OP_NAMES);
+ vm.saveConfig();
+ break;
+
+ case 7:
+ // Toggle Text Windows
+ vm._textWindowsOn = !vm._textWindowsOn;
+
+ render(OP_NAMES);
+ vm.saveConfig();
+ break;
+
+ case 8: {
+ // New Font Style
+ int fontNumber = screen.fontNumber() + 1;
+ if (fontNumber == 7)
+ fontNumber = 0;
+ screen.setFont(fontNumber);
+
+ render(OP_ALL);
+ vm.saveConfig();
+ break;
+ }
+
+ case 9:
+ // Toggle Transparent Menus
+ vm._transparentMenus = !vm._transparentMenus;
+
+ render(OP_NAMES);
+ vm.saveConfig();
+ break;
+
+ case 10:
+ // Quit
+ banishWindow();
+ ui.doQuitMenu();
+ break;
+
+ default:
+ break;
+ }
+
+ _oldSelector = -1;
+ }
+}
+
+void WidgetOptions::render(OptionRenderMode mode) {
+ TattooEngine &vm = *(TattooEngine *)_vm;
+ Music &music = *_vm->_music;
+ Sound &sound = *_vm->_sound;
+ TattooUserInterface &ui = *(TattooUserInterface *)_vm->_ui;
+ ImageFile &images = *ui._interfaceImages;
+ const char *const OFF_ON[2] = { FIXED(Off), FIXED(On) };
+
+ // Draw the border if necessary
+ if (mode == OP_ALL) {
+ // Set bounds for the dialog
+ Common::String widestString = Common::String::format("%s %s", FIXED(TransparentMenus), FIXED(Off));
+ _bounds = Common::Rect(_surface.stringWidth(widestString) + _surface.widestChar() * 2 + 6,
+ (_surface.fontHeight() + 7) * 11 + 3);
+ _bounds.moveTo(_centerPos.x - _bounds.width() / 2, _centerPos.y - _bounds.height() / 2);
+
+ // Get slider positions
+ _midiSliderX = music._musicVolume * (_bounds.width() - _surface.widestChar() * 2) / 255 + _surface.widestChar();
+ _digiSliderX = sound._soundVolume * (_bounds.width() - _surface.widestChar() * 2) / 255 + _surface.widestChar();
+
+ // Setup the dialog
+ _surface.create(_bounds.width(), _bounds.height());
+ _surface.fill(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);
+
+ yp += _surface.fontHeight() + 7;
+ if (idx == 1)
+ yp += _surface.fontHeight() + 7;
+ else if (idx == 2)
+ yp += (_surface.fontHeight() + 7) * 2;
+ }
+ }
+
+ // Now go through and display all the items that can be highlighted
+ 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);
+ byte color = (idx == _selector) ? COMMAND_HIGHLIGHTED : INFO_TOP;
+ Common::String str;
+
+ switch (idx) {
+ case 0:
+ str = FIXED(LoadGame);
+ break;
+
+ case 1:
+ str = FIXED(SaveGame);
+ break;
+
+ case 2:
+ str = Common::String::format("%s %s", FIXED(Music), OFF_ON[music._musicOn]);
+ break;
+
+ case 3: {
+ int num = (_surface.fontHeight() + 4) & 0xfe;
+ int sliderY = yp + num / 2 - 8;
+
+ _surface.fillRect(Common::Rect(4, sliderY - (num - 6) / 2, _surface.w() - 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.fillRect(Common::Rect(_midiSliderX - 1, sliderY - (num - 6) / 2 + 2,
+ _midiSliderX + 1, sliderY - (num - 6) / 2 + num - 3), INFO_MIDDLE);
+ drawDialogRect(Common::Rect(_midiSliderX - 3, sliderY - (num - 6) / 2,
+ _midiSliderX + 4, sliderY - (num - 6) / 2 + num));
+
+ 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())
+ _surface.fillRect(Common::Rect(_midiSliderX + 4, sliderY, _midiSliderX + 4, sliderY + 4), INFO_BOTTOM);
+ break;
+ }
+
+ case 4:
+ str = Common::String::format("%s %s", FIXED(SoundEffects), OFF_ON[sound._digitized]);
+ break;
+
+ case 5:
+ str = Common::String::format("%s %s", FIXED(Voices), OFF_ON[sound._voices]);
+ 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,
+ 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.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())
+ _surface.fillRect(Common::Rect(_digiSliderX + 4, sliderY, _digiSliderX + 4, sliderY + 4), INFO_BOTTOM);
+ break;
+ }
+
+ case 7:
+ if (!sound._voices) {
+ color = INFO_BOTTOM;
+ str = Common::String::format("%s %s", FIXED(TextWindows), FIXED(On));
+ } else {
+ str = Common::String::format("%s %s", FIXED(TextWindows), OFF_ON[vm._textWindowsOn]);
+ }
+ break;
+
+ case 8:
+ str = FIXED(ChangeFont);
+ break;
+
+ case 9:
+ str = Common::String::format("%s %s", FIXED(TransparentMenus), OFF_ON[vm._transparentMenus]);
+ break;
+
+ case 10:
+ str = FIXED(Quit);
+ break;
+
+ default:
+ break;
+ }
+
+ // 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;
+ _surface.writeString(str, Common::Point(xp, yp), color);
+ }
+ }
+ }
+}
+
+} // End of namespace Tattoo
+
+} // End of namespace Sherlock
diff --git a/engines/sherlock/tattoo/widget_options.h b/engines/sherlock/tattoo/widget_options.h
new file mode 100644
index 0000000000..9be0105ab4
--- /dev/null
+++ b/engines/sherlock/tattoo/widget_options.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 SHERLOCK_TATTOO_WIDGET_OPTIONS_H
+#define SHERLOCK_TATTOO_WIDGET_OPTIONS_H
+
+#include "common/scummsys.h"
+#include "sherlock/tattoo/widget_base.h"
+
+namespace Sherlock {
+
+class SherlockEngine;
+
+namespace Tattoo {
+
+enum OptionRenderMode { OP_ALL = 0, OP_CONTENTS = 1, OP_NAMES = 2};
+
+/**
+ * Handles displaying the options dialog
+ */
+class WidgetOptions : public WidgetBase {
+private:
+ int _midiSliderX, _digiSliderX;
+ int _selector, _oldSelector;
+ Common::Point _centerPos;
+
+ /**
+ * Render the contents of the dialog onto the widget's surface
+ */
+ void render(OptionRenderMode mode = OP_ALL);
+public:
+ WidgetOptions(SherlockEngine *vm);
+ virtual ~WidgetOptions() {}
+
+ /**
+ * Load and then display the options dialog
+ */
+ void load();
+
+ /**
+ * Handle event processing
+ */
+ virtual void handleEvents();
+};
+
+} // End of namespace Tattoo
+
+} // End of namespace Sherlock
+
+#endif
diff --git a/engines/sherlock/tattoo/widget_password.cpp b/engines/sherlock/tattoo/widget_password.cpp
new file mode 100644
index 0000000000..3dd0e308ff
--- /dev/null
+++ b/engines/sherlock/tattoo/widget_password.cpp
@@ -0,0 +1,210 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "sherlock/tattoo/widget_password.h"
+#include "sherlock/tattoo/tattoo.h"
+#include "sherlock/tattoo/tattoo_fixed_text.h"
+#include "sherlock/tattoo/tattoo_user_interface.h"
+
+namespace Sherlock {
+
+namespace Tattoo {
+
+WidgetPassword::WidgetPassword(SherlockEngine *vm) : WidgetBase(vm) {
+ _blinkFlag = false;
+ _blinkCounter = 0;
+ _index = 0;
+ _cursorColor = 192;
+ _insert = true;
+}
+
+void WidgetPassword::show() {
+ TattooUserInterface &ui = *(TattooUserInterface *)_vm->_ui;
+ ImageFile &images = *ui._interfaceImages;
+
+ // Set the up window to be centered on the screen
+ _bounds = Common::Rect(_surface.widestChar() * 20 + 6, (_surface.fontHeight() + 7) * 2 + 3);
+ _bounds.moveTo(SHERLOCK_SCREEN_WIDTH / 2 - _bounds.width() / 2, SHERLOCK_SCREEN_HEIGHT / 2 - _bounds.height() / 2);
+
+ // Create the surface
+ _surface.create(_bounds.width(), _bounds.height());
+ _surface.fill(TRANSPARENCY);
+ makeInfoArea();
+
+ // Draw the header area
+ _surface.writeString(FIXED(EnterPassword), Common::Point((_bounds.width() - _surface.stringWidth(FIXED(EnterPassword))) / 2, 5), INFO_TOP);
+ _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));
+
+ // Set the password entry data
+ _cursorPos = Common::Point(_surface.widestChar(), _surface.fontHeight() + 12);
+ _password = "";
+ _index = 0;
+ _cursorColor = 192;
+ _insert = true;
+
+ // Show the dialog
+ ui._menuMode = PASSWORD_MODE;
+ summonWindow();
+}
+
+void WidgetPassword::handleEvents() {
+ Events &events = *_vm->_events;
+ TattooUserInterface &ui = *(TattooUserInterface *)_vm->_ui;
+ Common::Point mousePos = events.mousePos();
+ const Common::KeyCode &keycode = ui._keyState.keycode;
+ char currentChar = (_index == (int)_password.size()) ? ' ' : _password[_index];
+ int width = _surface.charWidth(currentChar);
+
+ if (!keycode) {
+ // Nothing entered, so keep blinking the cursor
+ if (--_blinkCounter < 0) {
+ _blinkCounter = 3;
+ _blinkFlag = !_blinkFlag;
+
+ byte color, textColor;
+ if (_blinkFlag) {
+ textColor = 236;
+ color = _cursorColor;
+ } else {
+ textColor = COMMAND_HIGHLIGHTED;
+ color = TRANSPARENCY;
+ }
+
+ // Draw the cursor and the character it's over
+ _surface.fillRect(Common::Rect(_cursorPos.x, _cursorPos.y, _cursorPos.x + width, _cursorPos.y + _surface.fontHeight()), color);
+ if (currentChar != ' ')
+ _surface.writeString(Common::String::format("%c", _password[_index]), _cursorPos, textColor);
+ }
+ } else if (keycode == Common::KEYCODE_BACKSPACE && _index) {
+ _cursorPos.x -= _surface.charWidth(_password[_index - 1]);
+
+ if (_insert)
+ _password.deleteChar(_index - 1);
+ else
+ _password.setChar(' ', _index - 1);
+
+ // Redraw the text
+ --_index;
+ _surface.fillRect(Common::Rect(_cursorPos.x, _cursorPos.y, _bounds.width() - 9, _cursorPos.y +
+ _surface.fontHeight() - 1), TRANSPARENCY);
+ _surface.writeString(_password.c_str() + _index, _cursorPos, COMMAND_HIGHLIGHTED);
+ } else if ((keycode == Common::KEYCODE_LEFT && _index > 0)
+ || (keycode == Common::KEYCODE_RIGHT && _index < (int)_password.size() && _cursorPos.x < (_bounds.width() - _surface.widestChar() - 3))
+ || (keycode == Common::KEYCODE_HOME && _index > 0)
+ || (keycode == Common::KEYCODE_END)) {
+ // Restore character the cursor was previously over
+ _surface.fillRect(Common::Rect(_cursorPos.x, _cursorPos.y, _cursorPos.x + width, _cursorPos.y + _surface.fontHeight()), TRANSPARENCY);
+ if (currentChar != ' ')
+ _surface.writeString(Common::String::format("%c", _password[_index]), _cursorPos, COMMAND_HIGHLIGHTED);
+
+ switch (keycode) {
+ case Common::KEYCODE_LEFT:
+ _cursorPos.x -= _surface.charWidth(_password[_index - 1]);
+ --_index;
+ break;
+ case Common::KEYCODE_RIGHT:
+ _cursorPos.x += _surface.charWidth(_password[_index]);
+ ++_index;
+ break;
+ case Common::KEYCODE_HOME:
+ _cursorPos.x = _surface.widestChar();
+ _index = 0;
+ break;
+ case Common::KEYCODE_END:
+ _cursorPos.x = _surface.stringWidth(_password) + _surface.widestChar();
+ _index = _password.size();
+
+ while (_index > 0 && _password[_index - 1] == ' ') {
+ _cursorPos.x -= _surface.charWidth(_password[_index - 1]);
+ --_index;
+ }
+ break;
+ default:
+ break;
+ }
+ } else if (keycode == Common::KEYCODE_INSERT) {
+ _insert = !_insert;
+ _cursorColor = _insert ? 192 : 200;
+ } else if (keycode == Common::KEYCODE_DELETE) {
+ if (_index < (int)_password.size())
+ _password.deleteChar(_index);
+
+ // Redraw the text
+ _surface.fillRect(Common::Rect(_cursorPos.x, _cursorPos.y, _bounds.width() - 9, _cursorPos.y +
+ _surface.fontHeight() - 1), TRANSPARENCY);
+ _surface.writeString(_password.c_str() + _index, _cursorPos, COMMAND_HIGHLIGHTED);
+ } 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)) {
+ if (_cursorPos.x + _surface.charWidth(ui._keyState.ascii) < _bounds.width() - _surface.widestChar() - 3) {
+ if (_insert)
+ _password.insertChar(ui._keyState.ascii, _index);
+ else
+ _password.setChar(ui._keyState.ascii, _index);
+
+ // Redraw the text
+ _surface.fillRect(Common::Rect(_cursorPos.x, _cursorPos.y, _bounds.width() - 9, _cursorPos.y +
+ _surface.fontHeight() - 1), TRANSPARENCY);
+ _surface.writeString(_password.c_str() + _index, _cursorPos, COMMAND_HIGHLIGHTED);
+
+ _cursorPos.x += _surface.charWidth(ui._keyState.ascii);
+ ++_index;
+ }
+ }
+
+ // Also handle clicking outside the window to abort
+ if (events._firstPress && !_bounds.contains(mousePos))
+ _outsideMenu = true;
+
+ if ((events._released || events._rightReleased) && _outsideMenu && !_bounds.contains(mousePos)) {
+ close();
+ }
+}
+
+void WidgetPassword::close() {
+ Talk &talk = *_vm->_talk;
+
+ banishWindow();
+ if (talk._talkToAbort)
+ return;
+
+ // See if they entered the correct password
+ Common::String correct1 = FIXED(CorrectPassword);
+ Common::String correct2 = Common::String::format("%s?", FIXED(CorrectPassword));
+ Common::String correct3 = Common::String::format("%s ?", FIXED(CorrectPassword));
+
+ if (!_password.compareToIgnoreCase(correct1) || !_password.compareToIgnoreCase(correct2)
+ || !_password.compareToIgnoreCase(correct3))
+ // They got it correct
+ _vm->setFlags(149);
+
+ talk.talkTo("LASC52P");
+}
+
+} // End of namespace Tattoo
+
+} // End of namespace Sherlock
diff --git a/engines/sherlock/tattoo/widget_password.h b/engines/sherlock/tattoo/widget_password.h
new file mode 100644
index 0000000000..f7e82c798d
--- /dev/null
+++ b/engines/sherlock/tattoo/widget_password.h
@@ -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.
+ *
+ */
+
+#ifndef SHERLOCK_TATTOO_WIDGET_PASSWORD_H
+#define SHERLOCK_TATTOO_WIDGET_PASSWORD_H
+
+#include "common/scummsys.h"
+#include "sherlock/tattoo/widget_base.h"
+
+namespace Sherlock {
+
+class SherlockEngine;
+
+namespace Tattoo {
+
+class WidgetPassword: public WidgetBase {
+private:
+ Common::Point _cursorPos;
+ Common::String _password;
+ int _index;
+ bool _blinkFlag;
+ int _blinkCounter;
+ byte _cursorColor;
+ bool _insert;
+
+ /**
+ * Close the window and check if the entered password is correct
+ */
+ void close();
+public:
+ WidgetPassword(SherlockEngine *vm);
+ virtual ~WidgetPassword() {}
+
+ /**
+ * Show the password entry window
+ */
+ void show();
+
+ /**
+ * Handle event processing
+ */
+ virtual void handleEvents();
+};
+
+} // End of namespace Tattoo
+
+} // End of namespace Sherlock
+
+#endif
diff --git a/engines/sherlock/tattoo/widget_quit.cpp b/engines/sherlock/tattoo/widget_quit.cpp
new file mode 100644
index 0000000000..f853e7f47f
--- /dev/null
+++ b/engines/sherlock/tattoo/widget_quit.cpp
@@ -0,0 +1,155 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public 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/widget_quit.h"
+#include "sherlock/tattoo/tattoo.h"
+#include "sherlock/tattoo/tattoo_fixed_text.h"
+#include "sherlock/tattoo/tattoo_user_interface.h"
+
+namespace Sherlock {
+
+namespace Tattoo {
+
+WidgetQuit::WidgetQuit(SherlockEngine *vm) : WidgetBase(vm) {
+ _select = _oldSelect = -1;
+}
+
+void WidgetQuit::show() {
+ Events &events = *_vm->_events;
+ TattooUserInterface &ui = *(TattooUserInterface *)_vm->_ui;
+ ImageFile &images = *ui._interfaceImages;
+ Common::Point mousePos = events.mousePos();
+ const char *YES = FIXED(Yes);
+ const char *NO = FIXED(No);
+
+ // Set up the display area
+ _bounds = Common::Rect(_surface.stringWidth(FIXED(AreYouSureYou)) + _surface.widestChar() * 2,
+ (_surface.fontHeight() + 7) * 4);
+ _bounds.moveTo(mousePos.x - _bounds.width() / 2, mousePos.y - _bounds.height() / 2);
+
+ // Create the surface
+ _surface.create(_bounds.width(), _bounds.height());
+ _surface.fill(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.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);
+
+ const char *btn = (idx == 0) ? YES : NO;
+ _surface.writeString(btn, Common::Point((_bounds.width() - _surface.stringWidth(btn)) / 2, yp + 5), INFO_TOP);
+ yp += _surface.fontHeight() + 7;
+ }
+
+ ui._menuMode = QUIT_MODE;
+ summonWindow();
+}
+
+void WidgetQuit::handleEvents() {
+ Events &events = *_vm->_events;
+ Talk &talk = *_vm->_talk;
+ Common::Point mousePos = events.mousePos();
+ Common::Rect yesRect(_bounds.left, _bounds.top + (_surface.fontHeight() + 4) * 2 + 3, _bounds.right,
+ _bounds.top + (_surface.fontHeight() + 4) * 2 + 3 + _surface.fontHeight() + 7);
+ Common::Rect noRect(_bounds.left, _bounds.top + (_surface.fontHeight() + 4) * 2 + _surface.fontHeight() + 10,
+ _bounds.right, _bounds.top + (_surface.fontHeight() + 4) * 2 + 10 + _surface.fontHeight() * 2 + 7);
+
+ if (talk._talkToAbort)
+ return;
+
+ // Determine the highlighted item
+ _select = -1;
+ if (yesRect.contains(mousePos))
+ _select = 1;
+ else if (noRect.contains(mousePos))
+ _select = 0;
+
+ if (events.kbHit()) {
+ Common::KeyState keyState = events.getKey();
+
+ switch (keyState.keycode) {
+ case Common::KEYCODE_TAB:
+ // If the mouse is not over any of the options, move the mouse so that it points to the first option
+ if (_select == -1)
+ events.warpMouse(Common::Point(_bounds.right - 10, _bounds.top + (_surface.fontHeight() + 4) * 2
+ + 3 + _surface.fontHeight() + 1));
+ else if (_select == 1)
+ events.warpMouse(Common::Point(mousePos.x, _bounds.top + (_surface.fontHeight() + 4) * 2
+ + 3 + _surface.fontHeight() * 2 + 11));
+ else
+ events.warpMouse(Common::Point(mousePos.x, _bounds.top + (_surface.fontHeight() + 4) * 2
+ + 3 + _surface.fontHeight() + 1));
+ break;
+
+ case Common::KEYCODE_ESCAPE:
+ case Common::KEYCODE_n:
+ close();
+ return;
+
+ case Common::KEYCODE_y:
+ close();
+ _vm->quitGame();
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ // Check for change of the highlighted item
+ 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);
+
+ 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);
+ }
+ _oldSelect = _select;
+
+ // Flag is they started pressing outside of the menu
+ if (events._firstPress && !_bounds.contains(mousePos))
+ _outsideMenu = true;
+
+ if (events._released || events._rightReleased) {
+ events.clearEvents();
+ close();
+ if (_select == 1)
+ // Yes selected
+ _vm->quitGame();
+ }
+}
+
+} // End of namespace Tattoo
+
+} // End of namespace Sherlock
diff --git a/engines/sherlock/tattoo/widget_quit.h b/engines/sherlock/tattoo/widget_quit.h
new file mode 100644
index 0000000000..b8b640f2d2
--- /dev/null
+++ b/engines/sherlock/tattoo/widget_quit.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 SHERLOCK_TATTOO_WIDGET_QUIT_H
+#define SHERLOCK_TATTOO_WIDGET_QUIT_H
+
+#include "common/scummsys.h"
+#include "sherlock/tattoo/widget_base.h"
+
+namespace Sherlock {
+
+class SherlockEngine;
+
+namespace Tattoo {
+
+class WidgetQuit: public WidgetBase {
+private:
+ int _select, _oldSelect;
+public:
+ WidgetQuit(SherlockEngine *vm);
+ virtual ~WidgetQuit() {}
+
+ /**
+ * Prompt the user whether to quit
+ */
+ void show();
+
+ /**
+ * Handle event processing
+ */
+ virtual void handleEvents();
+};
+
+} // End of namespace Tattoo
+
+} // End of namespace Sherlock
+
+#endif
diff --git a/engines/sherlock/tattoo/widget_talk.cpp b/engines/sherlock/tattoo/widget_talk.cpp
new file mode 100644
index 0000000000..00e8233a95
--- /dev/null
+++ b/engines/sherlock/tattoo/widget_talk.cpp
@@ -0,0 +1,470 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public 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/widget_talk.h"
+#include "sherlock/tattoo/tattoo_fixed_text.h"
+#include "sherlock/tattoo/tattoo_journal.h"
+#include "sherlock/tattoo/tattoo_people.h"
+#include "sherlock/tattoo/tattoo_talk.h"
+#include "sherlock/tattoo/tattoo_scene.h"
+#include "sherlock/tattoo/tattoo_user_interface.h"
+#include "sherlock/tattoo/tattoo.h"
+
+namespace Sherlock {
+
+namespace Tattoo {
+
+#define STATEMENT_NUM_X 6
+#define NUM_VISIBLE_TALK_LINES 6
+
+WidgetTalk::WidgetTalk(SherlockEngine *vm) : WidgetBase(vm) {
+ _talkScrollIndex = 0;
+ _selector = _oldSelector = -1;
+ _talkTextX = 0;
+ _dialogTimer = 0;
+}
+
+void WidgetTalk::getTalkWindowSize() {
+ TattooTalk &talk = *(TattooTalk *)_vm->_talk;
+ int width, height;
+
+ // See how many statements are going to be available
+ int numStatements = 0;
+ for (uint idx = 0; idx < talk._statements.size(); ++idx) {
+ if (talk._statements[idx]._talkMap != -1)
+ ++numStatements;
+ }
+
+ width = SHERLOCK_SCREEN_WIDTH * 2 / 3;
+
+ // Split up the questions into separate strings for each line
+ _bounds = Common::Rect(width, 1);
+ setStatementLines();
+
+ // Make sure that the window does not get too big
+ if (_statementLines.size() < 7) {
+ height = (_surface.fontHeight() + 1) * _statementLines.size() + 9;
+ _scroll = false;
+ } else {
+ // Set up the height to a constrained amount, and add extra width for the scrollbar
+ width += BUTTON_SIZE + 3;
+ height = (_surface.fontHeight() + 1) * 6 + 9;
+ _scroll = true;
+ }
+
+ _bounds = Common::Rect(width, height);
+}
+
+void WidgetTalk::load() {
+ TattooPeople &people = *(TattooPeople *)_vm->_people;
+ TattooScene &scene = *(TattooScene *)_vm->_scene;
+
+ // Figure out the window size
+ getTalkWindowSize();
+
+ // Place the window centered above the player
+ Common::Point pt;
+ int scaleVal = scene.getScaleVal(people[HOLMES]._position);
+ pt.x = people[HOLMES]._position.x / FIXED_INT_MULTIPLIER - _bounds.width() / 2;
+
+ if (scaleVal == SCALE_THRESHOLD) {
+ pt.x += people[0].frameWidth() / 2;
+ pt.y = people[HOLMES]._position.y / FIXED_INT_MULTIPLIER - people[HOLMES].frameHeight()
+ - _bounds.height() - _surface.fontHeight();
+ } else {
+ pt.x += people[HOLMES]._imageFrame->sDrawXSize(scaleVal) / 2;
+ pt.y = people[HOLMES]._position.y / FIXED_INT_MULTIPLIER - people[HOLMES]._imageFrame->sDrawYSize(scaleVal)
+ - _bounds.height() - _surface.fontHeight();
+ }
+
+ _bounds.moveTo(pt);
+
+ // Set up the surface
+ _surface.create(_bounds.width(), _bounds.height());
+ _surface.fill(TRANSPARENCY);
+
+ // Form the background for the new window
+ makeInfoArea();
+}
+
+void WidgetTalk::handleEvents() {
+ Events &events = *_vm->_events;
+ TattooJournal &journal = *(TattooJournal *)_vm->_journal;
+ TattooPeople &people = *(TattooPeople *)_vm->_people;
+ TattooScene &scene = *(TattooScene *)_vm->_scene;
+ Sound &sound = *_vm->_sound;
+ TattooTalk &talk = *(TattooTalk *)_vm->_talk;
+ TattooUserInterface &ui = *(TattooUserInterface *)_vm->_ui;
+ Common::Point mousePos = events.mousePos();
+ Common::KeyCode keycode = ui._keyState.keycode;
+ bool hotkey = false;
+ bool callParrotFile = false;
+
+ // Handle scrollbar events
+ ScrollHighlight oldHighlight = ui._scrollHighlight;
+ handleScrollbarEvents(_talkScrollIndex, NUM_VISIBLE_TALK_LINES, _statementLines.size());
+
+ int oldScrollIndex = _talkScrollIndex;
+ handleScrolling(_talkScrollIndex, NUM_VISIBLE_TALK_LINES, _statementLines.size());
+
+ // Only redraw the window if the the scrollbar position has changed
+ if (ui._scrollHighlight != oldHighlight || oldScrollIndex != _talkScrollIndex)
+ render(HL_NO_HIGHLIGHTING);
+
+ // Flag if they started pressing outside of the window
+ if (events._firstPress && !_bounds.contains(mousePos))
+ _outsideMenu = true;
+
+ // Check for which statement they are pointing at
+ _selector = -1;
+ if (ui._scrollHighlight == SH_NONE) {
+ if (Common::Rect(_bounds.left, _bounds.top + 5, _bounds.right - 3, _bounds.bottom - 5).contains(mousePos)) {
+ if (_scroll) {
+ // Disregard the scrollbar when setting the statement number
+ if (!Common::Rect(_bounds.right - BUTTON_SIZE, _bounds.top, _bounds.right, _bounds.bottom).contains(mousePos))
+ _selector = (mousePos.y - _bounds.top - 5) / (_surface.fontHeight() + 1) + _talkScrollIndex;
+ } else {
+ _selector = (mousePos.y - _bounds.top - 5) / (_surface.fontHeight() + 1);
+ }
+
+ // Now translate the line number of the displayed line into the appropriate
+ // Statement number or set it to 255 to indicate no Statement selected
+ if (_selector >= 0 && _selector < (int)_statementLines.size())
+ _selector = _statementLines[_selector]._num;
+ else
+ _selector = -1;
+ }
+ }
+
+ // Check for the tab keys
+ if (keycode == Common::KEYCODE_TAB && ui._scrollHighlight == SH_NONE) {
+ if (_selector == -1) {
+ _selector = _statementLines[_scroll ? _talkScrollIndex : 0]._num;
+
+ events.warpMouse(Common::Point(_bounds.right - BUTTON_SIZE - 10, _bounds.top + _surface.fontHeight() + 2));
+ } else {
+ if (ui._keyState.flags & Common::KBD_SHIFT) {
+ _selector = (mousePos.y - _bounds.top - 5) / (_surface.fontHeight() + 1) + _talkScrollIndex;
+ if (_statementLines[_selector]._num == _statementLines[_talkScrollIndex]._num) {
+ _selector = (_bounds.height() - 10) / (_surface.fontHeight() + 1) + _talkScrollIndex;
+ } else {
+ int idx = _selector;
+ do {
+ --_selector;
+ } while (_selector > 0 && _statementLines[idx]._num == _statementLines[_selector]._num);
+ }
+
+ int idx = _selector;
+ while ((_statementLines[idx]._num == _statementLines[_selector - 1]._num) && (_selector > _talkScrollIndex))
+ --_selector;
+ } else {
+ _selector = (mousePos.y - _bounds.top - 5) / (_surface.fontHeight() + 1) + _talkScrollIndex;
+ if (_statementLines[_selector]._num == _statementLines[(_bounds.height() - 10) / (_surface.fontHeight() + 1) + _talkScrollIndex]._num) {
+ _selector = _talkScrollIndex;
+ } else {
+ int idx = _selector;
+ do {
+ ++_selector;
+ } while (_selector < (int)_statementLines.size() && _statementLines[idx]._num == _statementLines[_selector]._num);
+ }
+ }
+
+ events.warpMouse(Common::Point(mousePos.x, _bounds.top + _surface.fontHeight() + 2 + (_surface.fontHeight() + 1)
+ * (_selector - _talkScrollIndex)));
+ _selector = _statementLines[_selector]._num;
+ }
+ }
+
+ // Handle selecting a talk entry if a numeric key has been pressed
+ if (keycode >= Common::KEYCODE_1 && keycode <= Common::KEYCODE_9) {
+ int x = 0, t = 0, y = 0;
+
+ do {
+ if (y == (keycode - Common::KEYCODE_1)) {
+ _selector = _statementLines[t]._num;
+ _outsideMenu = false;
+ hotkey = true;
+ break;
+ }
+
+ ++t;
+ if (_statementLines[x]._num != _statementLines[t]._num) {
+ x = t;
+ ++y;
+ }
+ } while (t < (int)_statementLines.size());
+ }
+
+ // Display the selected statement highlighted and reset the last statement.
+ if (_selector != _oldSelector) {
+ render(HL_CHANGED_HIGHLIGHTS);
+ _oldSelector = _selector;
+ }
+
+ if (events._released || events._rightReleased || keycode == Common::KEYCODE_ESCAPE || hotkey) {
+ events.clearEvents();
+ _dialogTimer = 0;
+ ui._scrollHighlight = SH_NONE;
+
+ // See if they want to close the menu (click outside the window or Escape pressed)
+ if ((_outsideMenu && !_bounds.contains(mousePos)) || keycode == Common::KEYCODE_ESCAPE) {
+ if (keycode == Common::KEYCODE_ESCAPE)
+ _selector = -1;
+
+ talk.freeTalkVars();
+ talk.pullSequence();
+
+ for (int idx = 1; idx < MAX_CHARACTERS; ++idx) {
+ if (people[idx]._type == CHARACTER) {
+ while (!people[idx]._pathStack.empty())
+ people[idx].pullNPCPath();
+ }
+ }
+
+ banishWindow();
+ ui._menuMode = scene._labTableScene ? LAB_MODE : STD_MODE;
+
+ if (scene._currentScene == WEARY_PUNT)
+ callParrotFile = true;
+ }
+
+ _outsideMenu = false;
+
+ // See if they have selected a statement to say
+ if (_selector != -1) {
+ if (!talk._talkHistory[talk._converseNum][_selector] && talk._statements[_selector]._journal)
+ journal.record(talk._converseNum, _selector);
+ talk._talkHistory[talk._converseNum][_selector] = true;
+
+ banishWindow();
+ talk._speaker = _vm->readFlags(FLAG_PLAYER_IS_HOLMES) ? HOLMES : WATSON;
+ _scroll = false;
+ const byte *msg = (const byte *)talk._statements[_selector]._statement.c_str();
+ talk.talkInterface(msg);
+
+ if (sound._speechOn)
+ sound._talkSoundFile += Common::String::format("%02dA", _selector + 1);
+
+ int msgLen = MAX((int)talk._statements[_selector]._statement.size(), 160);
+ people.setTalkSequence(talk._speaker);
+
+ talk.waitForMore(msgLen);
+ if (talk._talkToAbort)
+ return;
+
+ people.setListenSequence(talk._speaker);
+
+ do {
+ talk._scriptSelect = _selector;
+ talk._speaker = talk._talkTo;
+
+ // Make a copy of the reply (since talkTo can reload the statements list), and call talkTo
+ Common::String reply = talk._statements[_selector]._reply;
+ talk.doScript(reply);
+
+ // Reset the misc field in case any people changed their sequences
+ for (int idx = 0; idx < MAX_CHARACTERS; ++idx)
+ people[idx]._misc = 0;
+
+ if (!talk._talkToAbort) {
+ if (!talk._statements[_selector]._modified.empty()) {
+ for (uint idx = 0; idx < talk._statements[_selector]._modified.size(); ++idx)
+ _vm->setFlags(talk._statements[_selector]._modified[idx]);
+
+ talk.setTalkMap();
+ }
+
+ // See if there is another talk file linked to this.
+ if (!talk._statements[_selector]._linkFile.empty() && !talk._scriptMoreFlag) {
+ Common::String linkFile = talk._statements[_selector]._linkFile;
+ talk.freeTalkVars();
+ talk.loadTalkFile(linkFile);
+
+ _talkScrollIndex = 0;
+ int select = -1;
+ _selector = _oldSelector = -1;
+
+ // Find the first statement that has all its flags set correctly
+ for (uint idx = 0; idx < talk._statements.size() && select == -1; ++select) {
+ if (!talk._statements[idx]._talkMap)
+ select = idx;
+ }
+
+ if (select == -1) {
+ talk.freeTalkVars();
+ talk.nothingToSay();
+ return;
+ }
+
+ // See is the new statement is in stealth mode
+ talk._talkStealth = (talk._statements[select]._statement.hasPrefix("^")) ? 2 : 0;
+
+ // See if the new file is a standard file, a reply first file, or a Stealth Mode file
+ if (!talk._statements[select]._statement.hasPrefix("*") && !talk._statements[select]._statement.hasPrefix("^")) {
+ load();
+ summonWindow();
+
+ setStatementLines();
+ render(HL_NO_HIGHLIGHTING);
+ break;
+ } else {
+ _selector = select;
+
+ if (!talk._talkHistory[talk._converseNum][_selector] && talk._statements[_selector]._journal)
+ journal.record(talk._converseNum, _selector);
+
+ talk._talkHistory[talk._converseNum][_selector] = true;
+ }
+ } else {
+ talk.freeTalkVars();
+ talk.pullSequence();
+
+ for (int idx = 1; idx < MAX_CHARACTERS; ++idx) {
+ if (people[idx]._type == CHARACTER)
+ while (!people[idx]._pathStack.empty())
+ people[idx].pullNPCPath();
+ }
+
+ if (ui._menuMode != PASSWORD_MODE) {
+ ui.banishWindow();
+ ui._menuMode = scene._labTableScene ? LAB_MODE : STD_MODE;
+ events.setCursor(ARROW);
+ }
+ break;
+ }
+ } else {
+ break;
+ }
+ } while (!_vm->shouldQuit());
+
+ events.clearEvents();
+
+ // Now, if a script was pushed onto the script stack, restore them to allow the previous script to continue.
+ talk.popStack();
+ }
+ }
+
+ if (callParrotFile)
+ talk.talkTo("POUT52A");
+}
+
+void WidgetTalk::render(Highlight highlightMode) {
+ TattooTalk &talk = *(TattooTalk *)_vm->_talk;
+ int yp = 5;
+ int statementNum = 1;
+ byte color;
+
+ if (highlightMode != HL_SCROLLBAR_ONLY) {
+ // Draw all the statements
+ // Check whether scrolling has occurred, and if so, figure out what the starting
+ // number for the first visible statement will be
+ if (_talkScrollIndex) {
+ for (int idx = 1; idx <= _talkScrollIndex; ++idx) {
+ if (_statementLines[idx - 1]._num != _statementLines[idx]._num)
+ ++statementNum;
+ }
+ }
+
+ // Main drawing loop
+ for (uint idx = _talkScrollIndex; idx < _statementLines.size() && yp < (_bounds.height() - _surface.fontHeight()); ++idx) {
+ 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);
+
+ // Different coloring based on whether the option has been previously chosen or not
+ color = (!talk._talkHistory[talk._converseNum][_statementLines[idx]._num]) ?
+ INFO_TOP : INFO_BOTTOM;
+
+ if (_statementLines[idx]._num == _selector && highlightMode == HL_CHANGED_HIGHLIGHTS)
+ color = COMMAND_HIGHLIGHTED;
+
+ // See if it's the start of a new statement, so needs the statement number to be displayed
+ if (!idx || _statementLines[idx]._num != _statementLines[idx - 1]._num) {
+ Common::String numStr = Common::String::format("%d.", statementNum);
+ _surface.writeString(numStr, Common::Point(STATEMENT_NUM_X, yp), color);
+ }
+
+ // Display the statement line
+ _surface.writeString(_statementLines[idx]._line, Common::Point(_talkTextX, yp), color);
+ }
+ yp += _surface.fontHeight() + 1;
+
+ // If the next line starts a new statement, then increment the statement number
+ if (idx == (_statementLines.size() - 1) || _statementLines[idx]._num != _statementLines[idx + 1]._num)
+ ++statementNum;
+ }
+ }
+
+ // See if the scroll bar needs to be drawn
+ if (_scroll && highlightMode != HL_CHANGED_HIGHLIGHTS)
+ drawScrollBar(_talkScrollIndex, NUM_VISIBLE_TALK_LINES, _statementLines.size());
+}
+
+void WidgetTalk::setStatementLines() {
+ TattooTalk &talk = *(TattooTalk *)_vm->_talk;
+ const char *numStr = "19.";
+
+ // See how many statements are going to be available
+ int numStatements = 0;
+ for (uint idx = 0; idx < talk._statements.size(); ++idx) {
+ if (talk._statements[idx]._talkMap != -1)
+ ++numStatements;
+ }
+
+ // If there are more lines than can be displayed in the interface window at one time, adjust the allowed
+ // width to take into account needing a scrollbar
+ int xSize = _scroll ? _bounds.width() - BUTTON_SIZE - 3 : _bounds.width();
+
+ // Also adjust the width to allow room for the statement numbers at the left edge of the display
+ int n = (numStatements < 10) ? 1 : 0;
+ xSize -= _surface.stringWidth(numStr + n) + _surface.widestChar() / 2 + 9;
+ _talkTextX = _surface.stringWidth(numStr + n) + _surface.widestChar() / 4 + 6;
+ _statementLines.clear();
+
+ for (uint statementNum = 0; statementNum < talk._statements.size(); ++statementNum) {
+ // See if this statment meets all of its flag requirements
+ if (talk._statements[statementNum]._talkMap != -1) {
+ // Get the next statement text to process
+ Common::String str = talk._statements[statementNum]._statement;
+
+ Common::StringArray statementLines;
+ splitLines(str, statementLines, xSize, 999);
+
+ // Add the lines in
+ for (uint idx = 0; idx < statementLines.size(); ++idx)
+ _statementLines.push_back(StatementLine(statementLines[idx], statementNum));
+ }
+ }
+}
+
+void WidgetTalk::refresh() {
+ _talkScrollIndex = 0;
+ _selector = _oldSelector = -1;
+
+ setStatementLines();
+ render(HL_NO_HIGHLIGHTING);
+}
+
+} // End of namespace Tattoo
+
+} // End of namespace Sherlock
diff --git a/engines/sherlock/tattoo/widget_talk.h b/engines/sherlock/tattoo/widget_talk.h
new file mode 100644
index 0000000000..f5e939b393
--- /dev/null
+++ b/engines/sherlock/tattoo/widget_talk.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 SHERLOCK_TATTOO_WIDGET_TALK_H
+#define SHERLOCK_TATTOO_WIDGET_TALK_H
+
+#include "common/scummsys.h"
+#include "sherlock/tattoo/widget_base.h"
+
+namespace Sherlock {
+
+class SherlockEngine;
+
+namespace Tattoo {
+
+enum Highlight { HL_NO_HIGHLIGHTING, HL_CHANGED_HIGHLIGHTS, HL_SCROLLBAR_ONLY };
+
+/**
+ * Handles displaying a dialog with conversation options the player can select from
+ */
+class WidgetTalk: public WidgetBase {
+ struct StatementLine {
+ Common::String _line;
+ int _num;
+
+ StatementLine() : _num(0) {}
+ StatementLine(const Common::String &line, int num) : _line(line), _num(num) {}
+ };
+private:
+ int _talkScrollIndex;
+ Common::Array<StatementLine> _statementLines;
+ int _selector, _oldSelector;
+ int _talkTextX;
+ uint32 _dialogTimer;
+
+ /**
+ * Get the needed size for a talk window
+ */
+ void getTalkWindowSize();
+
+ /**
+ * Re-renders the contenst of the window to the widget's surface
+ */
+ void render(Highlight highlightMode);
+
+ /**
+ * This initializes the _statementLines array, which contains the talk options split up line
+ * by line, as well as which statement a particular line is part of.
+ */
+ void setStatementLines();
+public:
+ WidgetTalk(SherlockEngine *vm);
+ virtual ~WidgetTalk() {}
+
+ /**
+ * Figures out how many lines the available talk lines will take up, and opens a text window
+ * of appropriate size
+ */
+ void load();
+
+ /**
+ * Refresh the talk display
+ */
+ void refresh();
+
+ /**
+ * Handle event processing
+ */
+ virtual void handleEvents();
+};
+
+} // End of namespace Tattoo
+
+} // End of namespace Sherlock
+
+#endif
diff --git a/engines/sherlock/tattoo/widget_text.cpp b/engines/sherlock/tattoo/widget_text.cpp
new file mode 100644
index 0000000000..86aa067301
--- /dev/null
+++ b/engines/sherlock/tattoo/widget_text.cpp
@@ -0,0 +1,228 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public 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/widget_text.h"
+#include "sherlock/tattoo/tattoo_people.h"
+#include "sherlock/tattoo/tattoo_scene.h"
+#include "sherlock/tattoo/tattoo_user_interface.h"
+#include "sherlock/tattoo/tattoo.h"
+
+namespace Sherlock {
+
+namespace Tattoo {
+
+WidgetText::WidgetText(SherlockEngine *vm) : WidgetBase(vm) {
+}
+
+void WidgetText::load(const Common::String &str, int speaker) {
+ Screen &screen = *_vm->_screen;
+ Talk &talk = *_vm->_talk;
+ TattooUserInterface &ui = *(TattooUserInterface *)_vm->_ui;
+ Common::StringArray lines;
+
+ int width = SHERLOCK_SCREEN_WIDTH / 3;
+ int height;
+
+ for (;;) {
+ splitLines(str, lines, width - _surface.widestChar() * 2, 100);
+ height = (screen.fontHeight() + 1) * lines.size() + 9;
+
+ if ((width - _surface.widestChar() * 2 > height * 3 / 2) || (width - _surface.widestChar() * 2
+ > SHERLOCK_SCREEN_WIDTH * 3 / 4))
+ break;
+
+ width += (width / 4);
+ }
+
+ // See if it's only a single line long
+ if (height == _surface.fontHeight() + 10) {
+ width = _surface.widestChar() * 2 + 6;
+
+ const char *strP = str.c_str();
+ while (*strP && (*strP < talk._opcodes[OP_SWITCH_SPEAKER] || *strP == talk._opcodes[OP_NULL]))
+ width += _surface.charWidth(*strP++);
+ }
+
+ _bounds = Common::Rect(width, height);
+
+ if (speaker == -1) {
+ // No speaker specified, so center window on look position
+ _bounds.translate(ui._lookPos.x - width / 2, ui._lookPos.y - height / 2);
+ } else {
+ // Speaker specified, so center the window above them
+ centerWindowOnSpeaker(speaker);
+ }
+
+ render(str);
+}
+
+void WidgetText::centerWindowOnSpeaker(int speaker) {
+ TattooPeople &people = *(TattooPeople *)_vm->_people;
+ TattooScene &scene = *(TattooScene *)_vm->_scene;
+ Common::Point pt;
+
+ 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
+ pt.x = people[HOLMES]._position.x / FIXED_INT_MULTIPLIER - _bounds.width() / 2;
+
+ int scaleVal = scene.getScaleVal(people[HOLMES]._position);
+ if (scaleVal == SCALE_THRESHOLD) {
+ pt.x += people[HOLMES].frameWidth() / 2;
+ pt.y = people[HOLMES]._position.y / FIXED_INT_MULTIPLIER - people[HOLMES].frameHeight()
+ - _bounds.height() - _surface.fontHeight();
+ } else {
+ pt.x += people[HOLMES]._imageFrame->sDrawXSize(scaleVal) / 2;
+ pt.y = people[HOLMES]._position.y / FIXED_INT_MULTIPLIER - people[HOLMES]._imageFrame->sDrawYSize(scaleVal)
+ - _bounds.height() - _surface.fontHeight();
+ }
+ } else {
+ pt.y = -1;
+
+ // Check each NPC to see if they are the one that is talking
+ for (int idx = 1; idx < MAX_CHARACTERS; ++idx) {
+ // WORKAROUND: Fixes an original game bug where the positioning for Watson's dialogs
+ // during conversations at the Park Lake lake scene is in the incorrect position
+ if (speaker == 1 && scene._currentScene == 30)
+ continue;
+
+ if (people[idx]._type == CHARACTER) {
+ if (!scumm_strnicmp(people[idx]._npcName.c_str(), people._characters[speaker]._portrait, 4)) {
+ // Place the window above the player
+ pt.x = people[idx]._position.x / FIXED_INT_MULTIPLIER - _bounds.width() / 2;
+
+ int scaleVal = scene.getScaleVal(people[idx]._position);
+ if (scaleVal == SCALE_THRESHOLD) {
+ pt.x += people[idx].frameWidth() / 2;
+ pt.y = people[idx]._position.y / FIXED_INT_MULTIPLIER - people[idx].frameHeight()
+ - _bounds.height() - _surface.fontHeight();
+ }
+ else {
+ pt.x += people[idx]._imageFrame->sDrawXSize(scaleVal) / 2;
+ pt.y = people[idx]._position.y / FIXED_INT_MULTIPLIER - people[idx]._imageFrame->sDrawYSize(scaleVal)
+ - _bounds.height() - _surface.fontHeight();
+ }
+
+ if (pt.y < 0)
+ pt.y = 0;
+ break;
+ }
+ }
+ }
+
+ if (pt.y == -1) {
+ for (uint idx = 0; idx < scene._bgShapes.size(); ++idx) {
+ Object &obj = scene._bgShapes[idx];
+
+ if (obj._type == ACTIVE_BG_SHAPE && !scumm_strnicmp(obj._name.c_str(), people._characters[speaker]._portrait, 4)) {
+ // Place the window centered above the character
+ pt.x = obj._position.x - _bounds.width() / 2;
+ pt.y = obj._position.y - _bounds.height() - _surface.fontHeight();
+ if (pt.y < 0)
+ pt.y = 0;
+ if (obj._scaleVal == SCALE_THRESHOLD)
+ pt.x += obj.frameWidth() / 2;
+ else
+ pt.x += obj._imageFrame->sDrawXSize(obj._scaleVal) / 2;
+
+ break;
+ }
+ }
+ }
+
+ if (pt.y == -1) {
+ pt.x = SHERLOCK_SCREEN_WIDTH / 2 - _bounds.width() / 2;
+ pt.y = SHERLOCK_SCREEN_HEIGHT / 2 - _bounds.height() / 2;
+ }
+ }
+
+ _bounds.moveTo(pt);
+}
+
+void WidgetText::render(const Common::String &str) {
+ Common::StringArray lines;
+ _remainingText = splitLines(str, lines, _bounds.width() - _surface.widestChar() * 2,
+ _bounds.height() / (_surface.fontHeight() + 1));
+
+ // Allocate a surface for the window
+ _surface.create(_bounds.width(), _bounds.height());
+ _surface.fill(TRANSPARENCY);
+
+ // Form the background for the new window
+ makeInfoArea();
+
+ int yp = 5;
+ for (int lineNum = 0; yp < (_bounds.height() - _surface.fontHeight() / 2); ++lineNum) {
+ _surface.writeString(lines[lineNum], Common::Point(_surface.widestChar(), yp), INFO_TOP);
+ yp += _surface.fontHeight() + 1;
+ }
+}
+
+/*----------------------------------------------------------------*/
+
+WidgetMessage::WidgetMessage(SherlockEngine *vm) : WidgetBase(vm) {
+ _menuCounter = 0;
+}
+
+void WidgetMessage::load(const Common::String &str, int time) {
+ Events &events = *_vm->_events;
+ Common::Point mousePos = events.mousePos();
+ _menuCounter = time;
+
+ // Set up the bounds for the dialog to be a single line
+ _bounds = Common::Rect(_surface.stringWidth(str) + _surface.widestChar() * 2 + 6, _surface.fontHeight() + 10);
+ _bounds.moveTo(mousePos.x - _bounds.width() / 2, mousePos.y - _bounds.height() / 2);
+
+ // Allocate a surface for the window
+ _surface.create(_bounds.width(), _bounds.height());
+ _surface.fill(TRANSPARENCY);
+
+ // Form the background for the new window and write the line of text
+ makeInfoArea();
+ _surface.writeString(str, Common::Point(_surface.widestChar() + 3, 5), INFO_TOP);
+}
+
+void WidgetMessage::handleEvents() {
+ Events &events = *_vm->_events;
+ TattooUserInterface &ui = *(TattooUserInterface *)_vm->_ui;
+ WidgetBase::handleEvents();
+
+ --_menuCounter;
+
+ // Check if a mouse or keypress has occurred, or the display counter has expired
+ if (events._pressed || events._released || events._rightPressed || events._rightReleased ||
+ ui._keyState.keycode || !_menuCounter) {
+ // Close the window
+ banishWindow();
+
+ // Reset cursor and switch back to standard mode
+ events.setCursor(ARROW);
+ events.clearEvents();
+ ui._key = -1;
+ ui._oldBgFound = -1;
+ ui._menuMode = STD_MODE;
+ }
+}
+
+} // End of namespace Tattoo
+
+} // End of namespace Sherlock
diff --git a/engines/sherlock/tattoo/widget_text.h b/engines/sherlock/tattoo/widget_text.h
new file mode 100644
index 0000000000..f027bdae9f
--- /dev/null
+++ b/engines/sherlock/tattoo/widget_text.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 SHERLOCK_TATTOO_WIDGET_TEXT_H
+#define SHERLOCK_TATTOO_WIDGET_TEXT_H
+
+#include "common/scummsys.h"
+#include "sherlock/tattoo/widget_base.h"
+
+namespace Sherlock {
+
+class SherlockEngine;
+
+namespace Tattoo {
+
+class WidgetText: public WidgetBase {
+private:
+ /**
+ * Center the area the dialog will be drawn on above a given speaker
+ */
+ void centerWindowOnSpeaker(int speaker);
+
+ /**
+ * Build up the text dialog based on the previously set bounds
+ */
+ void render(const Common::String &str);
+public:
+ Common::String _remainingText;
+public:
+ WidgetText(SherlockEngine *vm);
+ virtual ~WidgetText() {}
+
+ /**
+ * Load the data for the text window
+ */
+ void load(const Common::String &str, int speaker = -1);
+};
+
+class WidgetMessage : public WidgetBase {
+private:
+ int _menuCounter;
+public:
+ WidgetMessage(SherlockEngine *vm);
+ virtual ~WidgetMessage() {}
+
+ /**
+ * Load the data for the text window
+ */
+ void load(const Common::String &str, int time);
+
+ /**
+ * Handle event processing
+ */
+ virtual void handleEvents();
+};
+
+} // End of namespace Tattoo
+
+} // End of namespace Sherlock
+
+#endif
diff --git a/engines/sherlock/tattoo/widget_tooltip.cpp b/engines/sherlock/tattoo/widget_tooltip.cpp
new file mode 100644
index 0000000000..b29f45f531
--- /dev/null
+++ b/engines/sherlock/tattoo/widget_tooltip.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 "sherlock/tattoo/widget_tooltip.h"
+#include "sherlock/tattoo/tattoo_map.h"
+#include "sherlock/tattoo/tattoo_scene.h"
+#include "sherlock/tattoo/tattoo_user_interface.h"
+#include "sherlock/tattoo/tattoo.h"
+
+namespace Sherlock {
+
+namespace Tattoo {
+
+#define MAX_TOOLTIP_WIDTH 150
+
+void WidgetTooltipBase::draw() {
+ Screen &screen = *_vm->_screen;
+
+ // If there was a previously drawn frame in a different position that hasn't yet been erased, then erase it
+ if (_oldBounds.width() > 0 && _oldBounds != _bounds)
+ erase();
+
+ if (_bounds.width() > 0 && !_surface.empty()) {
+ restrictToScreen();
+
+ // Blit the affected area to the screen
+ screen.slamRect(_bounds);
+
+ // 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,
+ _bounds.top - screen._currentScroll.y));
+
+ // Store a copy of the drawn area for later erasing
+ _oldBounds = _bounds;
+ }
+}
+
+void WidgetTooltipBase::erase() {
+ Screen &screen = *_vm->_screen;
+
+ if (_oldBounds.width() > 0) {
+ // Restore the affected area from the back buffer to the screen
+ screen.slamRect(_oldBounds);
+
+ // Reset the old bounds so it won't be erased again
+ _oldBounds = Common::Rect(0, 0, 0, 0);
+ }
+}
+
+/*----------------------------------------------------------------*/
+
+WidgetTooltip::WidgetTooltip(SherlockEngine *vm) : WidgetTooltipBase (vm), _offsetY(0) {
+}
+
+void WidgetTooltip::setText(const Common::String &str) {
+ Events &events = *_vm->_events;
+ Common::Point mousePos = events.mousePos();
+ bool reset = false;
+
+ // Make sure that the description is present
+ if (!str.empty()) {
+ int width = _surface.stringWidth(str) + 2;
+ int height = _surface.stringHeight(str) + 2;
+ Common::String line1 = str, line2 = "";
+
+ // See if we need to split it into two lines
+ if (width > MAX_TOOLTIP_WIDTH) {
+ // Go forward word by word to find out where to split the line
+ const char *s = str.c_str();
+ const char *space = nullptr;
+ int dif = 10000;
+
+ for (;;) {
+ // Find end of next word
+ s = strchr(s + 1, ' ');
+
+ if (s == nullptr) {
+ // Reached end of string
+ if (space != nullptr) {
+ line1 = Common::String(str.c_str(), space);
+ line2 = Common::String(space + 1);
+ height = _surface.stringHeight(line1) + _surface.stringHeight(line2) + 4;
+ }
+ break;
+ }
+
+ // Found space separating words, so see what width the string up to now is
+ Common::String tempLine1 = Common::String(str.c_str(), s);
+ Common::String tempLine2 = Common::String(s + 1);
+ int width1 = _surface.stringWidth(tempLine1);
+ int width2 = _surface.stringWidth(tempLine2);
+
+ // See if we've found a split point that results in a less overall width
+ if (ABS(width1 - width2) < dif) {
+ // Found a better split point
+ dif = ABS(width1 - width2);
+ space = s;
+ line1 = tempLine1;
+ line2 = tempLine2;
+ }
+ }
+ } else {
+ // No line split needed
+ height = _surface.stringHeight(str) + 2;
+ }
+
+ // Reallocate the text surface with the new size
+ _surface.create(width, height);
+ _surface.fill(TRANSPARENCY);
+
+ if (line2.empty()) {
+ // Only a single line
+ _surface.writeFancyString(str, Common::Point(0, 0), BLACK, INFO_TOP);
+ } else {
+ // Two lines to display
+ int xp, yp;
+ xp = (width - _surface.stringWidth(line1) - 2) / 2;
+ _surface.writeFancyString(line1, Common::Point(xp, 0), BLACK, INFO_TOP);
+
+ xp = (width - _surface.stringWidth(line2) - 2) / 2;
+ yp = _surface.stringHeight(line1) + 2;
+ _surface.writeFancyString(line2, Common::Point(xp, yp), BLACK, INFO_TOP);
+ }
+
+ // Set the initial display position for the tooltip text
+ int tagX = mousePos.x - width / 2;
+ int tagY = mousePos.y - height - _offsetY;
+
+ _bounds = Common::Rect(tagX, tagY, tagX + width, tagY + height);
+ } else {
+ reset = true;
+ }
+
+ if (reset && !_surface.empty()) {
+ _surface.free();
+ }
+}
+
+void WidgetTooltip::handleEvents() {
+ Events &events = *_vm->_events;
+ Common::Point mousePos = events.mousePos();
+
+ // Set the new position for the tooltip
+ int xp = mousePos.x - _bounds.width() / 2;
+ int yp = mousePos.y - _bounds.height() - _offsetY;
+
+ _bounds.moveTo(xp, yp);
+}
+
+/*----------------------------------------------------------------*/
+
+void WidgetSceneTooltip::handleEvents() {
+ Events &events = *_vm->_events;
+ People &people = *_vm->_people;
+ Scene &scene = *_vm->_scene;
+ TattooUserInterface &ui = *(TattooUserInterface *)_vm->_ui;
+ Common::Point mousePos = events.mousePos();
+
+ // See if thay are pointing at a different object and we need to regenerate the tooltip text
+ if (ui._bgFound != ui._oldBgFound || (ui._bgFound != -1 && _surface.empty()) ||
+ ui._arrowZone != ui._oldArrowZone || (ui._arrowZone != -1 && _surface.empty())) {
+ // See if there is a new object to display text for
+ if ((ui._bgFound != -1 && (ui._bgFound != ui._oldBgFound || (ui._bgFound != -1 && _surface.empty()))) ||
+ (ui._arrowZone != -1 && (ui._arrowZone != ui._oldArrowZone || (ui._arrowZone != -1 && _surface.empty())))) {
+ Common::String str;
+ if (ui._bgFound != -1) {
+ // Clear the Arrow Zone fields so it won't think we're displaying an Arrow Zone cursor
+ if (scene._currentScene != OVERHEAD_MAP2)
+ ui._arrowZone = ui._oldArrowZone = -1;
+
+ // Get the description string
+ str = (ui._bgFound < 1000) ? scene._bgShapes[ui._bgFound]._description :
+ people[ui._bgFound - 1000]._description;
+
+ // WORKAORUND: On the train ride to Cambridge, don't show any tooltips
+ if (scene._currentScene == TRAIN_RIDE)
+ str = "";
+ } else {
+ // Get the exit zone description
+ str = scene._exits[ui._arrowZone]._dest;
+ }
+
+ setText(str.hasPrefix(" ") ? Common::String() : str);
+ } else if ((ui._bgFound == -1 && ui._oldBgFound != -1) || (ui._arrowZone == -1 && ui._oldArrowZone != -1)) {
+ setText("");
+ }
+
+ ui._oldBgFound = ui._bgFound;
+ } else {
+ // Set the new position for the tooltip
+ int tagX = CLIP(mousePos.x - _bounds.width() / 2, 0, SHERLOCK_SCREEN_WIDTH - _bounds.width());
+ int tagY = MAX(mousePos.y - _bounds.height() - _offsetY, 0);
+ _bounds.moveTo(tagX, tagY);
+ }
+
+ ui._oldArrowZone = ui._arrowZone;
+
+ WidgetTooltip::handleEvents();
+}
+
+} // End of namespace Tattoo
+
+} // End of namespace Sherlock
diff --git a/engines/sherlock/tattoo/widget_tooltip.h b/engines/sherlock/tattoo/widget_tooltip.h
new file mode 100644
index 0000000000..87f5d54f0a
--- /dev/null
+++ b/engines/sherlock/tattoo/widget_tooltip.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 SHERLOCK_TATTOO_WIDGET_TOOLTIP_H
+#define SHERLOCK_TATTOO_WIDGET_TOOLTIP_H
+
+#include "common/scummsys.h"
+#include "common/rect.h"
+#include "sherlock/tattoo/widget_base.h"
+
+namespace Sherlock {
+
+class SherlockEngine;
+
+namespace Tattoo {
+
+class WidgetTooltipBase : public WidgetBase {
+public:
+ WidgetTooltipBase(SherlockEngine *vm) : WidgetBase(vm) {}
+ virtual ~WidgetTooltipBase() {}
+
+ /**
+ * Erase any previous display of the widget on the screen
+ */
+ virtual void erase();
+
+ /**
+ * Update the display of the widget on the screen
+ */
+ virtual void draw();
+};
+
+class WidgetTooltip: public WidgetTooltipBase {
+public:
+ int _offsetY;
+public:
+ WidgetTooltip(SherlockEngine *vm);
+ virtual ~WidgetTooltip() {}
+
+ /**
+ * Set the text for the tooltip
+ */
+ void setText(const Common::String &str);
+
+ /**
+ * Handle updating the tooltip state
+ */
+ virtual void handleEvents();
+};
+
+class WidgetSceneTooltip : public WidgetTooltip {
+public:
+ WidgetSceneTooltip(SherlockEngine *vm) : WidgetTooltip(vm) {}
+
+ /**
+ * Handle updating the tooltip state
+ */
+ virtual void handleEvents();
+};
+
+class WidgetMapTooltip : public WidgetTooltip {
+public:
+ WidgetMapTooltip(SherlockEngine *vm) : WidgetTooltip(vm) {}
+};
+
+} // End of namespace Tattoo
+
+} // End of namespace Sherlock
+
+#endif
diff --git a/engines/sherlock/tattoo/widget_verbs.cpp b/engines/sherlock/tattoo/widget_verbs.cpp
new file mode 100644
index 0000000000..0b523a93e9
--- /dev/null
+++ b/engines/sherlock/tattoo/widget_verbs.cpp
@@ -0,0 +1,314 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public 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/widget_verbs.h"
+#include "sherlock/tattoo/tattoo_fixed_text.h"
+#include "sherlock/tattoo/tattoo_scene.h"
+#include "sherlock/tattoo/tattoo_user_interface.h"
+#include "sherlock/tattoo/tattoo_people.h"
+#include "sherlock/tattoo/tattoo.h"
+
+namespace Sherlock {
+
+namespace Tattoo {
+
+WidgetVerbs::WidgetVerbs(SherlockEngine *vm) : WidgetBase(vm) {
+ _selector = _oldSelector = -1;
+ _outsideMenu = false;
+}
+
+void WidgetVerbs::load(bool objectsOn) {
+ Events &events = *_vm->_events;
+ TattooPeople &people = *(TattooPeople *)_vm->_people;
+ Talk &talk = *_vm->_talk;
+ TattooUserInterface &ui = *(TattooUserInterface *)_vm->_ui;
+ Common::Point mousePos = events.mousePos();
+ bool isWatson = false;
+
+ if (talk._talkToAbort)
+ return;
+
+ ui._activeObj = ui._bgFound;
+ _outsideMenu = false;
+ _verbCommands.clear();
+ _selector = _oldSelector = -1;
+
+ // Check if we need to show options for the highlighted object
+ if (objectsOn) {
+ // Set the verb list accordingly, depending on the target being a
+ // person or an object
+ if (ui._personFound) {
+ TattooPerson &person = people[ui._activeObj - 1000];
+ TattooPerson &npc = people[ui._activeObj - 1001];
+
+ if (!scumm_strnicmp(npc._npcName.c_str(), "WATS", 4))
+ isWatson = true;
+
+
+ if (scumm_strnicmp(person._examine.c_str(), "_EXIT", 5))
+ _verbCommands.push_back(FIXED(Look));
+
+ _verbCommands.push_back(FIXED(Talk));
+
+ // Add any extra active verbs from the NPC's verb list
+ for (int idx = 0; idx < 2; ++idx) {
+ if (!person._use[idx]._verb.empty() && !person._use[idx]._verb.hasPrefix(" ") &&
+ (person._use[idx]._target.empty() || person._use[idx]._target.hasPrefix(" "))) {
+ _verbCommands.push_back(person._use[idx]._verb);
+ }
+ }
+ } else {
+ if (!scumm_strnicmp(ui._bgShape->_name.c_str(), "WATS", 4))
+ // Looking at Watson
+ isWatson = true;
+
+ if (scumm_strnicmp(ui._bgShape->_examine.c_str(), "_EXIT", 5))
+ // It's not an exit, so include Look as an option
+ _verbCommands.push_back(FIXED(Look));
+
+ if (ui._bgShape->_aType == PERSON)
+ _verbCommands.push_back(FIXED(Talk));
+
+ // Add any extra active verbs from the object's verb list
+ for (int idx = 0; idx < 6; ++idx) {
+ UseType &use = ui._bgShape->_use[idx];
+ if (!use._verb.empty() && !use._verb.hasPrefix(" ") && !use._verb.hasPrefix("*") &&
+ (use._target.empty() || use._target.hasPrefix("*") || use._target.hasPrefix(" "))) {
+ _verbCommands.push_back(use._verb);
+ }
+ }
+ }
+ }
+
+ // If clicked on Watson, have Journal as an option
+ if (isWatson)
+ _verbCommands.push_back(FIXED(Journal));
+
+ // Add the system commands
+ _verbCommands.push_back(FIXED(Inventory));
+ _verbCommands.push_back(FIXED(Options));
+
+ // Figure out the needed width to show the commands
+ int width = 0;
+ for (uint idx = 0; idx < _verbCommands.size(); ++idx)
+ width = MAX(width, _surface.stringWidth(_verbCommands[idx]));
+ width += _surface.widestChar() * 2 + 6;
+ int height = (_surface.fontHeight() + 7) * _verbCommands.size() + 3;
+
+ // Set the bounds
+ _bounds = Common::Rect(width, height);
+ _bounds.moveTo(mousePos.x - _bounds.width() / 2, mousePos.y - _bounds.height() / 2);
+
+ // Render the window on the internal surface
+ render();
+}
+
+void WidgetVerbs::render() {
+ TattooUserInterface &ui = *(TattooUserInterface *)_vm->_ui;
+ ImageFile &images = *ui._interfaceImages;
+
+ // Create the drawing surface
+ _surface.create(_bounds.width(), _bounds.height());
+ _surface.fill(TRANSPARENCY);
+
+ // Draw basic background
+ makeInfoArea();
+
+ // Draw the verb commands and the lines separating them
+ for (uint idx = 0; idx < _verbCommands.size(); ++idx) {
+ _surface.writeString(_verbCommands[idx], Common::Point((_bounds.width() - _surface.stringWidth(_verbCommands[idx])) / 2,
+ (_surface.fontHeight() + 7) * idx + 5), INFO_TOP);
+
+ if (idx < (_verbCommands.size() - 1)) {
+ _surface.hLine(3, (_surface.fontHeight() + 7) * (idx + 1), _bounds.width() - 4, INFO_TOP);
+ _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.fontHeight() + 7) * (idx + 1) - 1));
+ }
+ }
+}
+
+void WidgetVerbs::handleEvents() {
+ Events &events = *_vm->_events;
+ FixedText &fixedText = *_vm->_fixedText;
+ People &people = *_vm->_people;
+ TattooScene &scene = *(TattooScene *)_vm->_scene;
+ Talk &talk = *_vm->_talk;
+ TattooUserInterface &ui = *(TattooUserInterface *)_vm->_ui;
+ Common::Point mousePos = events.mousePos();
+ bool noDesc = false;
+
+ Common::String strLook = fixedText.getText(kFixedText_Look);
+ Common::String strTalk = fixedText.getText(kFixedText_Talk);
+ Common::String strJournal = fixedText.getText(kFixedText_Journal);
+
+ checkTabbingKeys(_verbCommands.size());
+
+ // Highlight verb display as necessary
+ highlightVerbControls();
+
+ // Flag if the user has started pressing the button with the cursor outsie the menu
+ if (events._firstPress && !_bounds.contains(mousePos))
+ _outsideMenu = true;
+
+ // See if they released the mouse button
+ if (events._released || events._rightReleased) {
+ // See if they want to close the menu (they clicked outside of the menu)
+ if (!_bounds.contains(mousePos)) {
+ if (_outsideMenu) {
+ if (events._rightReleased) {
+ // Change to the item (if any) that was right-clicked on, and re-draw the verb menu
+ ui._bgFound = scene.findBgShape(mousePos);
+ ui._personFound = ui._bgFound >= 1000;
+ ui._bgShape = ui._personFound || ui._bgFound == -1 ? nullptr : &scene._bgShapes[ui._bgFound];
+
+ if (ui._personFound) {
+ if (people[ui._bgFound - 1000]._description.empty() || people[ui._bgFound - 1000]._description.hasPrefix(" "))
+ noDesc = true;
+ } else if (ui._bgFound != -1) {
+ if (ui._bgShape->_description.empty() || ui._bgShape->_description.hasPrefix(" "))
+ noDesc = true;
+ } else {
+ noDesc = true;
+ }
+
+ // Call the Routine to turn on the Commands for this Object
+ load(!noDesc);
+ } else {
+ // Close the window and clear the events
+ banishWindow();
+ events.clearEvents();
+
+ // Reset the active UI mode
+ ui._menuMode = scene._labTableScene ? LAB_MODE : STD_MODE;
+ }
+ }
+ } else if (_bounds.contains(mousePos) && _selector != -1) {
+ // Mouse is within the menu
+ // Erase the menu
+ banishWindow();
+ events.clearEvents();
+
+ // See if they are activating the Look Command
+ if (!_verbCommands[_selector].compareToIgnoreCase(strLook)) {
+ ui._bgFound = ui._activeObj;
+ if (ui._activeObj >= 1000) {
+ ui._personFound = true;
+ } else {
+ ui._personFound = false;
+ ui._bgShape = &scene._bgShapes[ui._activeObj];
+ }
+
+ ui.lookAtObject();
+
+ } else if (!_verbCommands[_selector].compareToIgnoreCase(strTalk)) {
+ // Talk command is being activated
+ talk.initTalk(ui._activeObj);
+ ui._activeObj = -1;
+
+ } else if (!_verbCommands[_selector].compareToIgnoreCase(strJournal)) {
+ ui.doJournal();
+
+ // See if we're in a Lab Table scene
+ ui._menuMode = scene._labTableScene ? LAB_MODE : STD_MODE;
+ } else if (_selector >= ((int)_verbCommands.size() - 2)) {
+ switch (_selector - (int)_verbCommands.size() + 2) {
+ case 0:
+ // Inventory
+ ui.doInventory(2);
+ break;
+
+ case 1:
+ // Options
+ ui.doControls();
+ break;
+
+ default:
+ ui._menuMode = scene._labTableScene ? LAB_MODE : STD_MODE;
+ break;
+ }
+ } else {
+ // If they have selected anything else, process it
+ people[HOLMES].gotoStand();
+
+ if (ui._activeObj < 1000) {
+ for (int idx = 0; idx < 6; ++idx) {
+ if (!_verbCommands[_selector].compareToIgnoreCase(scene._bgShapes[ui._activeObj]._use[idx]._verb)) {
+ // See if they are Picking this object up
+ if (!scene._bgShapes[ui._activeObj]._use[idx]._target.compareToIgnoreCase("*PICKUP"))
+ ui.pickUpObject(ui._activeObj);
+ else
+ ui.checkAction(scene._bgShapes[ui._activeObj]._use[idx], ui._activeObj);
+ }
+ }
+ } else {
+ for (int idx = 0; idx < 2; ++idx) {
+ if (!_verbCommands[_selector].compareToIgnoreCase(people[ui._activeObj - 1000]._use[idx]._verb))
+ ui.checkAction(people[ui._activeObj - 1000]._use[idx], ui._activeObj);
+ }
+ }
+
+ ui._activeObj = -1;
+ if (ui._menuMode != MESSAGE_MODE) {
+ // See if we're in a Lab Table Room
+ ui._menuMode = scene._labTableScene ? LAB_MODE : STD_MODE;
+ }
+ }
+ }
+ } else if (ui._keyState.keycode == Common::KEYCODE_ESCAPE) {
+ // User closing the menu with the ESC key
+ banishWindow();
+ ui._menuMode = scene._labTableScene ? LAB_MODE : STD_MODE;
+ }
+}
+
+void WidgetVerbs::highlightVerbControls() {
+ Events &events = *_vm->_events;
+ Screen &screen = *_vm->_screen;
+ Common::Point mousePos = events.mousePos();
+
+ // Get highlighted verb
+ _selector = -1;
+ Common::Rect bounds = _bounds;
+ bounds.grow(-3);
+ if (bounds.contains(mousePos))
+ _selector = (mousePos.y - bounds.top) / (screen.fontHeight() + 7);
+
+ // See if a new verb is being pointed at
+ if (_selector != _oldSelector) {
+ // Redraw the verb list
+ for (int idx = 0; idx < (int)_verbCommands.size(); ++idx) {
+ byte color = (idx == _selector) ? (byte)COMMAND_HIGHLIGHTED : (byte)INFO_TOP;
+ _surface.writeString(_verbCommands[idx], Common::Point((_bounds.width() - screen.stringWidth(_verbCommands[idx])) / 2,
+ (screen.fontHeight() + 7) * idx + 5), color);
+ }
+
+ _oldSelector = _selector;
+ }
+}
+
+} // End of namespace Tattoo
+
+} // End of namespace Sherlock
diff --git a/engines/sherlock/tattoo/widget_verbs.h b/engines/sherlock/tattoo/widget_verbs.h
new file mode 100644
index 0000000000..ce67842409
--- /dev/null
+++ b/engines/sherlock/tattoo/widget_verbs.h
@@ -0,0 +1,72 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public 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_WIDGET_VERBS_H
+#define SHERLOCK_TATTOO_WIDGET_VERBS_H
+
+#include "common/scummsys.h"
+#include "common/rect.h"
+#include "common/str-array.h"
+#include "sherlock/tattoo/widget_base.h"
+
+namespace Sherlock {
+
+class SherlockEngine;
+
+namespace Tattoo {
+
+class WidgetVerbs: public WidgetBase {
+private:
+ int _selector, _oldSelector;
+ bool _outsideMenu;
+
+ /**
+ * Highlights the controls for the verb list
+ */
+ void highlightVerbControls();
+
+ /**
+ * Renders the window on an internal surface for later drawing on-screen
+ */
+ void render();
+public:
+ Common::StringArray _verbCommands;
+public:
+ WidgetVerbs(SherlockEngine *vm);
+ virtual ~WidgetVerbs() {}
+
+ /**
+ * Turns on the menu with all the verbs that are available for the given object
+ */
+ void load(bool objectsOn);
+
+ /**
+ * Process input for the dialog
+ */
+ virtual void handleEvents();
+};
+
+} // End of namespace Tattoo
+
+} // End of namespace Sherlock
+
+#endif
diff --git a/engines/sherlock/user_interface.cpp b/engines/sherlock/user_interface.cpp
index 9fff7cc999..bb0667d66a 100644
--- a/engines/sherlock/user_interface.cpp
+++ b/engines/sherlock/user_interface.cpp
@@ -21,8 +21,9 @@
*/
#include "sherlock/user_interface.h"
-#include "sherlock/sherlock.h"
+#include "sherlock/scalpel/scalpel.h"
#include "sherlock/scalpel/scalpel_user_interface.h"
+#include "sherlock/tattoo/tattoo.h"
#include "sherlock/tattoo/tattoo_user_interface.h"
namespace Sherlock {
@@ -45,7 +46,9 @@ UserInterface::UserInterface(SherlockEngine *vm) : _vm(vm) {
_helpStyle = false;
_windowBounds = Common::Rect(0, CONTROLS_Y1, SHERLOCK_SCREEN_WIDTH - 1, SHERLOCK_SCREEN_HEIGHT - 1);
_lookScriptFlag = false;
+ _exitZone = -1;
+ _bgFound = _oldBgFound = -1;
_key = _oldKey = '\0';
_selector = _oldSelector = -1;
_temp = _oldTemp = 0;
@@ -53,4 +56,154 @@ UserInterface::UserInterface(SherlockEngine *vm) : _vm(vm) {
_lookHelp = 0;
}
+void UserInterface::checkAction(ActionType &action, int objNum, FixedTextActionId fixedTextActionId) {
+ Events &events = *_vm->_events;
+ FixedText &fixedText = *_vm->_fixedText;
+ People &people = *_vm->_people;
+ Scene &scene = *_vm->_scene;
+ Screen &screen = *_vm->_screen;
+ Talk &talk = *_vm->_talk;
+ Point32 pt(-1, -1);
+
+ if (action._useFlag)
+ // Automatically set the given flag
+ _vm->setFlags(action._useFlag);
+
+ if (IS_SERRATED_SCALPEL && objNum >= 1000)
+ // Ignore actions done on characters
+ return;
+
+ if (IS_SERRATED_SCALPEL && !action._cAnimSpeed) {
+ // Invalid action, to print error message
+ _infoFlag = true;
+ clearInfo();
+ Common::String errorMessage = fixedText.getActionMessage(fixedTextActionId, action._cAnimNum);
+ screen.print(Common::Point(0, INFO_LINE + 1), COL_INFO_FOREGROUND, "%s", errorMessage.c_str());
+ _infoFlag = true;
+
+ // Set how long to show the message
+ _menuCounter = 30;
+ } else {
+ BaseObject *obj;
+ if (objNum >= 1000)
+ obj = &people[objNum - 1000];
+ else
+ obj = &scene._bgShapes[objNum];
+
+ int cAnimNum;
+ if (action._cAnimNum == 0)
+ // Really a 10
+ cAnimNum = 9;
+ else
+ cAnimNum = action._cAnimNum - 1;
+
+ int dir = -1;
+ if (action._cAnimNum != 99) {
+ CAnim &anim = scene._cAnim[cAnimNum];
+
+ if (action._cAnimNum != 99) {
+ if (action._cAnimSpeed & REVERSE_DIRECTION) {
+ pt = anim._teleport[0];
+ dir = anim._teleport[0]._facing;
+ } else {
+ pt = anim._goto[0];
+ dir = anim._goto[0]._facing;
+ }
+ }
+ } else {
+ pt = Point32(-1, -1);
+ dir = -1;
+ }
+
+ // Has a value, so do action
+ // Show wait cursor whilst walking to object and doing action
+ events.setCursor(WAIT);
+ bool printed = false;
+
+ for (int nameIdx = 0; nameIdx < NAMES_COUNT; ++nameIdx) {
+ if (action._names[nameIdx].hasPrefix("*") && action._names[nameIdx].size() >= 2
+ && toupper(action._names[nameIdx][1]) == 'W') {
+ if (obj->checkNameForCodes(Common::String(action._names[nameIdx].c_str() + 2), fixedTextActionId)) {
+ if (!talk._talkToAbort)
+ printed = true;
+ }
+ }
+ }
+
+ bool doCAnim = true;
+ for (int nameIdx = 0; nameIdx < NAMES_COUNT; ++nameIdx) {
+ if (action._names[nameIdx].hasPrefix("*") && action._names[nameIdx].size() >= 2) {
+ char ch = toupper(action._names[nameIdx][1]);
+
+ if (ch == 'T' || ch == 'B') {
+ printed = true;
+ if (pt.x != -1)
+ // Holmes needs to walk to object before the action is done
+ people[HOLMES].walkToCoords(pt, dir);
+
+ if (!talk._talkToAbort) {
+ // Ensure Holmes is on the exact intended location
+ people[HOLMES]._position = pt;
+ people[HOLMES]._sequenceNumber = dir;
+ people[HOLMES].gotoStand();
+
+ talk.talkTo(action._names[nameIdx].c_str() + 2);
+ if (ch == 'T')
+ doCAnim = false;
+ }
+ }
+ }
+ }
+
+ if (doCAnim && !talk._talkToAbort) {
+ if (pt.x != -1)
+ // Holmes needs to walk to object before the action is done
+ people[HOLMES].walkToCoords(pt, dir);
+ }
+
+ for (int nameIdx = 0; nameIdx < NAMES_COUNT; ++nameIdx) {
+ if (action._names[nameIdx].hasPrefix("*") && action._names[nameIdx].size() >= 2
+ && toupper(action._names[nameIdx][1]) == 'F') {
+ if (obj->checkNameForCodes(action._names[nameIdx].c_str() + 2, fixedTextActionId)) {
+ if (!talk._talkToAbort)
+ printed = true;
+ }
+ }
+ }
+
+ if (doCAnim && !talk._talkToAbort && action._cAnimNum != 99)
+ scene.startCAnim(cAnimNum, action._cAnimSpeed);
+
+ if (!talk._talkToAbort) {
+ for (int nameIdx = 0; nameIdx < NAMES_COUNT && !talk._talkToAbort; ++nameIdx) {
+ if (obj->checkNameForCodes(action._names[nameIdx], fixedTextActionId)) {
+ if (!talk._talkToAbort)
+ printed = true;
+ }
+ }
+
+ // Unless we're leaving the scene, print a "Done" message unless the printed flag has been set
+ if (IS_SERRATED_SCALPEL && scene._goToScene != 1 && !printed && !talk._talkToAbort) {
+ _infoFlag = true;
+ clearInfo();
+ screen.print(Common::Point(0, INFO_LINE + 1), COL_INFO_FOREGROUND, "Done...");
+
+ // Set how long to show the message
+ _menuCounter = 30;
+ }
+ }
+ }
+
+ // Reset cursor back to arrow
+ events.setCursor(ARROW);
+}
+
+void UserInterface::reset() {
+ _bgFound = _oldBgFound = -1;
+ _oldKey = -1;
+ _oldTemp = _temp = -1;
+ _exitZone = -1;
+}
+
+
} // End of namespace Sherlock
diff --git a/engines/sherlock/user_interface.h b/engines/sherlock/user_interface.h
index 042997a3e2..c16c9f5d11 100644
--- a/engines/sherlock/user_interface.h
+++ b/engines/sherlock/user_interface.h
@@ -28,6 +28,7 @@
#include "sherlock/surface.h"
#include "sherlock/objects.h"
#include "sherlock/resources.h"
+#include "sherlock/fixed_text.h"
namespace Sherlock {
@@ -47,7 +48,16 @@ enum MenuMode {
GIVE_MODE = 9,
JOURNAL_MODE = 10,
FILES_MODE = 11,
- SETUP_MODE = 12
+ SETUP_MODE = 12,
+
+ // Rose Tattoo specific
+ LAB_MODE = 20,
+ MESSAGE_MODE = 21,
+ VERB_MODE = 22,
+ OPTION_MODE = 23,
+ QUIT_MODE = 24,
+ FOOLSCAP_MODE = 25,
+ PASSWORD_MODE = 26
};
class UserInterface {
@@ -66,10 +76,12 @@ public:
bool _helpStyle;
Common::Rect _windowBounds;
bool _lookScriptFlag;
+ int _bgFound, _oldBgFound;
+ int _exitZone;
// TODO: Not so sure these should be in the base class. May want to refactor them to SherlockEngine, or refactor
// various Scalpel dialogs to keep their own private state of key/selections
- char _key, _oldKey;
+ signed char _key, _oldKey;
int _selector, _oldSelector;
int _temp, _oldTemp;
int _temp1;
@@ -79,9 +91,14 @@ public:
virtual ~UserInterface() {}
/**
+ * Called for OPEN, CLOSE, and MOVE actions are being done
+ */
+ void checkAction(ActionType &action, int objNum, FixedTextActionId fixedTextActionId = kFixedTextAction_Invalid);
+public:
+ /**
* Resets the user interface
*/
- virtual void reset() {}
+ virtual void reset();
/**
* Draw the user interface onto the screen's back buffers
@@ -118,11 +135,6 @@ public:
* Clear any active text window
*/
virtual void clearWindow() {}
-
- /**
- * Print the previously selected object's decription
- */
- virtual void printObjectDesc() {}
};
} // End of namespace Sherlock
diff --git a/engines/sky/music/adlibchannel.cpp b/engines/sky/music/adlibchannel.cpp
index 8400fef6eb..c7acb9b6c1 100644
--- a/engines/sky/music/adlibchannel.cpp
+++ b/engines/sky/music/adlibchannel.cpp
@@ -29,7 +29,7 @@
namespace Sky {
-AdLibChannel::AdLibChannel(FM_OPL *opl, uint8 *pMusicData, uint16 startOfData) {
+AdLibChannel::AdLibChannel(OPL::OPL *opl, uint8 *pMusicData, uint16 startOfData) {
_opl = opl;
_musicData = pMusicData;
_channelData.loopPoint = startOfData;
@@ -45,6 +45,8 @@ AdLibChannel::AdLibChannel(FM_OPL *opl, uint8 *pMusicData, uint16 startOfData) {
_channelData.frequency = 0;
_channelData.instrumentData = NULL;
+ _musicVolume = 128;
+
uint16 instrumentDataLoc;
if (SkyEngine::_systemVars.gameVersion == 109) {
@@ -86,7 +88,7 @@ bool AdLibChannel::isActive() {
}
void AdLibChannel::updateVolume(uint16 pVolume) {
- // Do nothing. The mixer handles the music volume for us.
+ _musicVolume = pVolume;
}
/* This class uses the same area for the register mirror as the original
@@ -95,7 +97,7 @@ void AdLibChannel::updateVolume(uint16 pVolume) {
*/
void AdLibChannel::setRegister(uint8 regNum, uint8 value) {
if (_adlibRegMirror[regNum] != value) {
- OPLWriteReg (_opl, regNum, value);
+ _opl->writeReg(regNum, value);
_adlibRegMirror[regNum] = value;
}
}
@@ -208,6 +210,8 @@ void AdLibChannel::setupChannelVolume(uint8 volume) {
uint32 resVol = ((volume + 1) * (_channelData.instrumentData->totOutLev_Op2 + 1)) << 1;
resVol &= 0xFFFF;
resVol *= (_channelData.channelVolume + 1) << 1;
+ resVol >>= 8;
+ resVol *= _musicVolume << 1;
resVol >>= 16;
assert(resVol < 0x81);
resultOp = ((_channelData.instrumentData->scalingLevel << 6) & 0xC0) | _opOutputTable[resVol];
@@ -216,6 +220,8 @@ void AdLibChannel::setupChannelVolume(uint8 volume) {
resVol = ((volume + 1) * (_channelData.instrumentData->totOutLev_Op1 + 1)) << 1;
resVol &= 0xFFFF;
resVol *= (_channelData.channelVolume + 1) << 1;
+ resVol >>= 8;
+ resVol *= _musicVolume << 1;
resVol >>= 16;
} else
resVol = _channelData.instrumentData->totOutLev_Op1;
diff --git a/engines/sky/music/adlibchannel.h b/engines/sky/music/adlibchannel.h
index 80dae93b2c..4504e3b570 100644
--- a/engines/sky/music/adlibchannel.h
+++ b/engines/sky/music/adlibchannel.h
@@ -60,14 +60,15 @@ typedef struct {
class AdLibChannel : public ChannelBase {
public:
- AdLibChannel (FM_OPL *opl, uint8 *pMusicData, uint16 startOfData);
+ AdLibChannel (OPL::OPL *opl, uint8 *pMusicData, uint16 startOfData);
virtual ~AdLibChannel();
virtual uint8 process(uint16 aktTime);
virtual void updateVolume(uint16 pVolume);
virtual bool isActive();
private:
- FM_OPL *_opl;
+ OPL::OPL *_opl;
uint8 *_musicData;
+ uint16 _musicVolume;
AdLibChannelType _channelData;
InstrumentStruct *_instruments;
diff --git a/engines/sky/music/adlibmusic.cpp b/engines/sky/music/adlibmusic.cpp
index dd64c5bc81..be5e7b2353 100644
--- a/engines/sky/music/adlibmusic.cpp
+++ b/engines/sky/music/adlibmusic.cpp
@@ -22,6 +22,7 @@
#include "common/endian.h"
+#include "common/textconsole.h"
#include "sky/music/adlibmusic.h"
#include "sky/music/adlibchannel.h"
@@ -32,44 +33,21 @@ namespace Sky {
AdLibMusic::AdLibMusic(Audio::Mixer *pMixer, Disk *pDisk) : MusicBase(pMixer, pDisk) {
_driverFileBase = 60202;
- _sampleRate = pMixer->getOutputRate();
- _opl = makeAdLibOPL(_sampleRate);
+ _opl = OPL::Config::create();
+ if (!_opl || !_opl->init())
+ error("Failed to create OPL");
- _mixer->playStream(Audio::Mixer::kMusicSoundType, &_soundHandle, this, -1, Audio::Mixer::kMaxChannelVolume, 0, DisposeAfterUse::NO, true);
+ _opl->start(new Common::Functor0Mem<void, AdLibMusic>(this, &AdLibMusic::onTimer), 50);
}
AdLibMusic::~AdLibMusic() {
- OPLDestroy(_opl);
- _mixer->stopHandle(_soundHandle);
+ delete _opl;
}
-int AdLibMusic::readBuffer(int16 *data, const int numSamples) {
- if (_musicData == NULL) {
- // no music loaded
- memset(data, 0, numSamples * sizeof(int16));
- } else if ((_currentMusic == 0) || (_numberOfChannels == 0)) {
- // music loaded but not played as of yet
- memset(data, 0, numSamples * sizeof(int16));
- // poll anyways as pollMusic() can activate the music
+void AdLibMusic::onTimer() {
+ if (_musicData != NULL)
pollMusic();
- _nextMusicPoll = _sampleRate / 50;
- } else {
- uint32 render;
- uint remaining = numSamples;
- while (remaining) {
- render = (remaining > _nextMusicPoll) ? _nextMusicPoll : remaining;
- remaining -= render;
- _nextMusicPoll -= render;
- YM3812UpdateOne(_opl, data, render);
- data += render;
- if (_nextMusicPoll == 0) {
- pollMusic();
- _nextMusicPoll = _sampleRate / 50;
- }
- }
- }
- return numSamples;
}
void AdLibMusic::setupPointers() {
@@ -87,7 +65,6 @@ void AdLibMusic::setupPointers() {
_musicDataLoc = READ_LE_UINT16(_musicData + 0x1201);
_initSequence = _musicData + 0xE91;
}
- _nextMusicPoll = 0;
}
void AdLibMusic::setupChannels(uint8 *channelData) {
@@ -102,26 +79,15 @@ void AdLibMusic::setupChannels(uint8 *channelData) {
void AdLibMusic::startDriver() {
uint16 cnt = 0;
while (_initSequence[cnt] || _initSequence[cnt + 1]) {
- OPLWriteReg (_opl, _initSequence[cnt], _initSequence[cnt + 1]);
+ _opl->writeReg(_initSequence[cnt], _initSequence[cnt + 1]);
cnt += 2;
}
}
void AdLibMusic::setVolume(uint16 param) {
_musicVolume = param;
- _mixer->setVolumeForSoundType(Audio::Mixer::kMusicSoundType, 2 * param);
-}
-
-bool AdLibMusic::isStereo() const {
- return false;
-}
-
-bool AdLibMusic::endOfData() const {
- return false;
-}
-
-int AdLibMusic::getRate() const {
- return _sampleRate;
+ for (uint8 cnt = 0; cnt < _numberOfChannels; cnt++)
+ _channels[cnt]->updateVolume(_musicVolume);
}
} // End of namespace Sky
diff --git a/engines/sky/music/adlibmusic.h b/engines/sky/music/adlibmusic.h
index 886eef026e..7b51f2d3a0 100644
--- a/engines/sky/music/adlibmusic.h
+++ b/engines/sky/music/adlibmusic.h
@@ -25,32 +25,32 @@
#include "sky/music/musicbase.h"
#include "audio/audiostream.h"
-#include "audio/fmopl.h"
+
+namespace OPL {
+class OPL;
+}
namespace Sky {
-class AdLibMusic : public Audio::AudioStream, public MusicBase {
+class AdLibMusic : public MusicBase {
public:
AdLibMusic(Audio::Mixer *pMixer, Disk *pDisk);
~AdLibMusic();
// AudioStream API
- int readBuffer(int16 *buffer, const int numSamples);
- bool isStereo() const;
- bool endOfData() const;
- int getRate() const;
virtual void setVolume(uint16 param);
private:
- FM_OPL *_opl;
- Audio::SoundHandle _soundHandle;
+ OPL::OPL *_opl;
uint8 *_initSequence;
- uint32 _sampleRate, _nextMusicPoll;
+ uint32 _sampleRate;
virtual void setupPointers();
virtual void setupChannels(uint8 *channelData);
virtual void startDriver();
void premixerCall(int16 *buf, uint len);
+
+ void onTimer();
};
} // End of namespace Sky
diff --git a/engines/sword25/fmv/movieplayer.cpp b/engines/sword25/fmv/movieplayer.cpp
index 5d7dcf2506..eb0f0390dc 100644
--- a/engines/sword25/fmv/movieplayer.cpp
+++ b/engines/sword25/fmv/movieplayer.cpp
@@ -123,7 +123,7 @@ void MoviePlayer::update() {
if (_decoder.endOfVideo()) {
// Movie complete, so unload the movie
unloadMovie();
- } else {
+ } else if (_decoder.needsUpdate()) {
const Graphics::Surface *s = _decoder.decodeNextFrame();
if (s) {
// Transfer the next frame
diff --git a/engines/tinsel/music.cpp b/engines/tinsel/music.cpp
index 8a7305f63b..9b4e2494e0 100644
--- a/engines/tinsel/music.cpp
+++ b/engines/tinsel/music.cpp
@@ -27,6 +27,8 @@
#include "audio/audiostream.h"
#include "audio/mididrv.h"
#include "audio/midiparser.h"
+// Miles Audio for Discworld 1
+#include "audio/miles.h"
#include "audio/decoders/adpcm.h"
#include "backends/audiocd/audiocd.h"
@@ -373,8 +375,78 @@ void DeleteMidiBuffer() {
g_midiBuffer.pDat = NULL;
}
-MidiMusicPlayer::MidiMusicPlayer() {
- MidiPlayer::createDriver();
+MidiMusicPlayer::MidiMusicPlayer(TinselEngine *vm) {
+ _driver = NULL;
+ _milesAudioMode = false;
+ bool milesAudioEnabled = false;
+
+ if (vm->getPlatform() == Common::kPlatformDOS) {
+ // Enable Miles Audio for DOS only
+ milesAudioEnabled = true;
+ }
+
+ if ((vm->getGameId() == GID_DW1) && (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:
+ // Has SAMPLE.AD for AdLib and SAMPLE.OPL for OPL-3
+ // Timbre files are inside a subdirectory of the CD called "/drivers". Main game files are in
+ // another subdirectory, which means the user has to copy those files over.
+ // Installer script copies all drivers directly to harddrive without name changes
+ //
+ // Version 2:
+ // Has FAT.OPL only (gets copied by the installer into MIDPAK.AD or MIDPAK.OPL)
+ // Timbre file is inside subdirectory "drivers" right in the main game directory.
+ // Installer copies FAT.OPL to MIDPAK.AD all the time, even when user selected AWE32
+ //
+ // Neither have timbre data for MT32
+
+ ::MidiDriver::DeviceHandle dev = ::MidiDriver::detectDevice(MDT_MIDI | MDT_ADLIB | MDT_PREFER_GM);
+ ::MusicType musicType = ::MidiDriver::getMusicType(dev);
+ Common::File fileClass;
+
+ switch (musicType) {
+ case MT_ADLIB:
+ if (fileClass.exists("FAT.OPL")) {
+ // Version 2: fat.opl, may be in drivers-subdirectory
+ _driver = Audio::MidiDriver_Miles_AdLib_create("", "FAT.OPL");
+ } else {
+ if (fileClass.exists("MIDPAK.AD")) {
+ // 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");
+ }
+ }
+ break;
+ case MT_MT32:
+ // Discworld 1 doesn't have a MT32 timbre file
+ _driver = Audio::MidiDriver_Miles_MT32_create("");
+ break;
+ case MT_GM:
+ if (ConfMan.getBool("native_mt32")) {
+ _driver = Audio::MidiDriver_Miles_MT32_create("");
+ musicType = MT_MT32;
+ }
+ break;
+ default:
+ break;
+ }
+ if (!_driver) {
+ // nothing got created yet? -> create default driver
+ MidiPlayer::createDriver();
+ } else {
+ _milesAudioMode = true;
+ }
+
+ } else {
+ MidiPlayer::createDriver();
+ }
int ret = _driver->open();
if (ret == 0) {
@@ -394,6 +466,11 @@ void MidiMusicPlayer::setVolume(int volume) {
}
void MidiMusicPlayer::send(uint32 b) {
+ if (_milesAudioMode) {
+ _driver->send(b);
+ return;
+ }
+
Audio::MidiPlayer::send(b);
byte channel = (byte)(b & 0x0F);
diff --git a/engines/tinsel/music.h b/engines/tinsel/music.h
index 0a78c39a76..422d80ae30 100644
--- a/engines/tinsel/music.h
+++ b/engines/tinsel/music.h
@@ -60,7 +60,7 @@ void dumpMusic();
class MidiMusicPlayer : public Audio::MidiPlayer {
public:
- MidiMusicPlayer();
+ MidiMusicPlayer(TinselEngine *vm);
virtual void setVolume(int volume);
@@ -77,6 +77,8 @@ public:
// means. The default is 120.
uint32 getBaseTempo() { return _driver ? (109 * _driver->getBaseTempo()) / 120 : 0; }
+ bool _milesAudioMode;
+
private:
void playXMIDI(uint32 size, bool loop);
void playSEQ(uint32 size, bool loop);
diff --git a/engines/tinsel/tinsel.cpp b/engines/tinsel/tinsel.cpp
index 57d8432f0e..6dc8e3bb35 100644
--- a/engines/tinsel/tinsel.cpp
+++ b/engines/tinsel/tinsel.cpp
@@ -885,12 +885,15 @@ void TinselEngine::initializePath(const Common::FSNode &gamePath) {
} else {
// Add DW2 subfolder to search path in case user is running directly from the CDs
SearchMan.addSubDirectoryMatching(gamePath, "dw2");
+
+ // Location of Miles audio files (sample.ad and sample.opl) in Discworld 1
+ SearchMan.addSubDirectoryMatching(gamePath, "drivers");
Engine::initializePath(gamePath);
}
}
Common::Error TinselEngine::run() {
- _midiMusic = new MidiMusicPlayer();
+ _midiMusic = new MidiMusicPlayer(this);
_pcmMusic = new PCMMusicPlayer();
_sound = new SoundManager(this);
_bmv = new BMVPlayer();
diff --git a/engines/toltecs/music.cpp b/engines/toltecs/music.cpp
index e4e067de39..97d8b1aea2 100644
--- a/engines/toltecs/music.cpp
+++ b/engines/toltecs/music.cpp
@@ -21,6 +21,7 @@
*/
#include "audio/midiparser.h"
+#include "audio/miles.h"
#include "common/textconsole.h"
#include "toltecs/toltecs.h"
@@ -30,20 +31,47 @@
namespace Toltecs {
MusicPlayer::MusicPlayer(bool isGM) : _isGM(isGM), _buffer(NULL) {
- MidiPlayer::createDriver();
+ MidiDriver::DeviceHandle dev = MidiDriver::detectDevice(MDT_MIDI | MDT_ADLIB | MDT_PREFER_GM);
+ MusicType musicType = MidiDriver::getMusicType(dev);
+
+ switch (musicType) {
+ case MT_ADLIB:
+ _milesAudioMode = true;
+ _driver = Audio::MidiDriver_Miles_AdLib_create("SAMPLE.AD", "SAMPLE.OPL");
+ break;
+ case MT_MT32:
+ // Not recommended since it sounds awful, but apparently the
+ // original sounded just as bad. I guess MT-32 support was
+ // added by default, not because anyone actually put any work
+ // into it.
+ _milesAudioMode = true;
+ _driver = Audio::MidiDriver_Miles_MT32_create("");
+ break;
+ default:
+ _milesAudioMode = false;
+ MidiPlayer::createDriver();
+ break;
+ }
int ret = _driver->open();
if (ret == 0) {
- if (_nativeMT32)
- _driver->sendMT32Reset();
- else
- _driver->sendGMReset();
+ if (musicType != MT_ADLIB) {
+ if (musicType == MT_MT32 || _nativeMT32)
+ _driver->sendMT32Reset();
+ else
+ _driver->sendGMReset();
+ }
_driver->setTimerCallback(this, &timerCallback);
}
}
void MusicPlayer::send(uint32 b) {
+ if (_milesAudioMode) {
+ _driver->send(b);
+ return;
+ }
+
if ((b & 0xF0) == 0xC0 && !_isGM && !_nativeMT32) {
b = (b & 0xFFFF00FF) | MidiDriver::_mt32ToGm[(b >> 8) & 0xFF] << 8;
}
diff --git a/engines/toltecs/music.h b/engines/toltecs/music.h
index e6dc3dd146..25d67e9334 100644
--- a/engines/toltecs/music.h
+++ b/engines/toltecs/music.h
@@ -47,6 +47,7 @@ protected:
private:
byte *_buffer;
+ bool _milesAudioMode;
};
class Music : public MusicPlayer {
diff --git a/engines/tony/window.cpp b/engines/tony/window.cpp
index 3b3687419b..d312d58091 100644
--- a/engines/tony/window.cpp
+++ b/engines/tony/window.cpp
@@ -28,7 +28,7 @@
#include "common/scummsys.h"
#include "graphics/surface.h"
-#include "util.h"
+#include "engines/util.h"
#include "tony/window.h"
#include "tony/game.h"
#include "tony/tony.h"
diff --git a/engines/tsage/detection_tables.h b/engines/tsage/detection_tables.h
index 1dfc3e6fd2..109ac353e6 100644
--- a/engines/tsage/detection_tables.h
+++ b/engines/tsage/detection_tables.h
@@ -185,7 +185,7 @@ static const tSageGameDescription gameDescriptions[] = {
GType_Ringworld2,
GF_CD | GF_ALT_REGIONS | GF_DEMO
},
-
+#ifdef TSAGE_SHERLOCK_ENABLED
// The Lost Files of Sherlock Holmes - The Case of the Serrated Scalpel (Logo)
{
{
@@ -200,6 +200,7 @@ static const tSageGameDescription gameDescriptions[] = {
GType_Sherlock1,
GF_FLOPPY
},
+#endif
{ AD_TABLE_END_MARKER, 0, 0 }
};
diff --git a/engines/tsage/globals.cpp b/engines/tsage/globals.cpp
index 1be3e2b6da..b880f35007 100644
--- a/engines/tsage/globals.cpp
+++ b/engines/tsage/globals.cpp
@@ -157,12 +157,15 @@ Globals::Globals() : _dialogCenter(160, 140), _gfxManagerInstance(_screenSurface
_game = new Ringworld2::Ringworld2Game();
_sceneHandler = new Ringworld2::SceneHandlerExt();
break;
-
+#ifdef TSAGE_SHERLOCK_ENABLED
case GType_Sherlock1:
_inventory = nullptr;
_sceneHandler = new Sherlock::SherlockSceneHandler();
_game = new Sherlock::SherlockLogo();
break;
+#endif
+ default:
+ break;
}
}
diff --git a/engines/tsage/sherlock/sherlock_logo.cpp b/engines/tsage/sherlock/sherlock_logo.cpp
index 437fdc6d94..e27ce76576 100644
--- a/engines/tsage/sherlock/sherlock_logo.cpp
+++ b/engines/tsage/sherlock/sherlock_logo.cpp
@@ -20,6 +20,7 @@
*
*/
+#ifdef TSAGE_SHERLOCK_ENABLED
#include "tsage/sherlock/sherlock_logo.h"
#include "tsage/scenes.h"
#include "tsage/tsage.h"
@@ -148,7 +149,7 @@ void SherlockLogoScene::Action1::signal() {
scene._object1.changeZoom(100);
scene._object1.setPosition(Common::Point(170, 142));
scene._object1._numFrames = 7;
- scene._object1.animate(ANIM_MODE_5, nullptr);
+ scene._object1.animate(ANIM_MODE_5, (const void *)nullptr);
ADD_MOVER(scene._object1, 158, 71);
break;
@@ -164,7 +165,7 @@ void SherlockLogoScene::Action1::signal() {
scene._object2._frame = 1;
scene._object2.setPosition(Common::Point(152, 98));
scene._object2.changeZoom(100);
- scene._object2.animate(ANIM_MODE_NONE, nullptr);
+ scene._object2.animate(ANIM_MODE_NONE, (const void *)nullptr);
setDelay(120);
break;
@@ -176,7 +177,7 @@ void SherlockLogoScene::Action1::signal() {
scene._object3._frame = 1;
scene._object3.setPosition(Common::Point(33, 91));
scene._object3.changeZoom(100);
- scene._object3.animate(ANIM_MODE_NONE, nullptr);
+ scene._object3.animate(ANIM_MODE_NONE, (const void *)nullptr);
setDelay(5);
break;
@@ -341,7 +342,7 @@ void SherlockLogoScene::postInit(SceneObjectList *OwnerList) {
_object4._frame = 1;
_object4.setPosition(Common::Point(155, 94));
_object4.changeZoom(100);
- _object4.animate(ANIM_MODE_NONE, nullptr);
+ _object4.animate(ANIM_MODE_NONE, (const void *)nullptr);
_object4.hide();
setAction(&_action1);
@@ -354,3 +355,5 @@ void SherlockLogoScene::finish() {
} // End of namespace Sherlock
} // End of namespace TsAGE
+
+#endif
diff --git a/engines/tsage/sherlock/sherlock_logo.h b/engines/tsage/sherlock/sherlock_logo.h
index 95fc0e272f..01b5b7f75f 100644
--- a/engines/tsage/sherlock/sherlock_logo.h
+++ b/engines/tsage/sherlock/sherlock_logo.h
@@ -20,6 +20,7 @@
*
*/
+#ifdef TSAGE_SHERLOCK_ENABLED
#ifndef TSAGE_SHERLOCK_LOGO_H
#define TSAGE_SHERLOCK_LOGO_H
@@ -76,3 +77,4 @@ public:
} // End of namespace TsAGE
#endif
+#endif
diff --git a/engines/tsage/sound.cpp b/engines/tsage/sound.cpp
index b95b614f09..0d3fb55dd3 100644
--- a/engines/tsage/sound.cpp
+++ b/engines/tsage/sound.cpp
@@ -20,9 +20,9 @@
*
*/
+#include "audio/fmopl.h"
#include "audio/decoders/raw.h"
#include "common/config-manager.h"
-#include "audio/decoders/raw.h"
#include "audio/audiostream.h"
#include "tsage/core.h"
#include "tsage/globals.h"
@@ -2743,17 +2743,9 @@ AdlibSoundDriver::AdlibSoundDriver(): SoundDriver() {
_groupData._pData = &adlib_group_data[0];
_mixer = g_vm->_mixer;
- _sampleRate = _mixer->getOutputRate();
_opl = OPL::Config::create();
assert(_opl);
- _opl->init(_sampleRate);
-
- _samplesTillCallback = 0;
- _samplesTillCallbackRemainder = 0;
- _samplesPerCallback = getRate() / CALLBACKS_PER_SECOND;
- _samplesPerCallbackRemainder = getRate() % CALLBACKS_PER_SECOND;
-
- _mixer->playStream(Audio::Mixer::kPlainSoundType, &_soundHandle, this, -1, Audio::Mixer::kMaxChannelVolume, 0, DisposeAfterUse::NO, true);
+ _opl->init();
Common::fill(_channelVoiced, _channelVoiced + ADLIB_CHANNEL_COUNT, false);
memset(_channelVolume, 0, ADLIB_CHANNEL_COUNT * sizeof(int));
@@ -2772,11 +2764,12 @@ AdlibSoundDriver::AdlibSoundDriver(): SoundDriver() {
_channelVoiced[i] = false;
_pitchBlend[i] = 0;
}
+
+ _opl->start(new Common::Functor0Mem<void, AdlibSoundDriver>(this, &AdlibSoundDriver::onTimer), CALLBACKS_PER_SECOND);
}
AdlibSoundDriver::~AdlibSoundDriver() {
DEALLOCATE(_patchData);
- _mixer->stopHandle(_soundHandle);
delete _opl;
}
@@ -3019,33 +3012,12 @@ void AdlibSoundDriver::setFrequency(int channel) {
((dataWord >> 8) & 3) | (var2 << 2));
}
-int AdlibSoundDriver::readBuffer(int16 *buffer, const int numSamples) {
+void AdlibSoundDriver::onTimer() {
Common::StackLock slock1(SoundManager::sfManager()._serverDisabledMutex);
Common::StackLock slock2(SoundManager::sfManager()._serverSuspendedMutex);
- int32 samplesLeft = numSamples;
- memset(buffer, 0, sizeof(int16) * numSamples);
- while (samplesLeft) {
- if (!_samplesTillCallback) {
- SoundManager::sfUpdateCallback(NULL);
- flush();
-
- _samplesTillCallback = _samplesPerCallback;
- _samplesTillCallbackRemainder += _samplesPerCallbackRemainder;
- if (_samplesTillCallbackRemainder >= CALLBACKS_PER_SECOND) {
- _samplesTillCallback++;
- _samplesTillCallbackRemainder -= CALLBACKS_PER_SECOND;
- }
- }
-
- int32 render = MIN<int>(samplesLeft, _samplesTillCallback);
- samplesLeft -= render;
- _samplesTillCallback -= render;
-
- _opl->readBuffer(buffer, render);
- buffer += render;
- }
- return numSamples;
+ SoundManager::sfUpdateCallback(NULL);
+ flush();
}
/*--------------------------------------------------------------------------*/
diff --git a/engines/tsage/sound.h b/engines/tsage/sound.h
index 49558b4bca..68755a48c8 100644
--- a/engines/tsage/sound.h
+++ b/engines/tsage/sound.h
@@ -27,12 +27,15 @@
#include "common/mutex.h"
#include "common/queue.h"
#include "audio/audiostream.h"
-#include "audio/fmopl.h"
#include "audio/mixer.h"
#include "common/list.h"
#include "tsage/saveload.h"
#include "tsage/core.h"
+namespace OPL {
+class OPL;
+}
+
namespace TsAGE {
class Sound;
@@ -446,21 +449,15 @@ public:
#define ADLIB_CHANNEL_COUNT 9
-class AdlibSoundDriver: public SoundDriver, Audio::AudioStream {
+class AdlibSoundDriver: public SoundDriver {
private:
GroupData _groupData;
Audio::Mixer *_mixer;
- FM_OPL *_opl;
- Audio::SoundHandle _soundHandle;
- int _sampleRate;
+ OPL::OPL *_opl;
byte _portContents[256];
const byte *_patchData;
int _masterVolume;
Common::Queue<RegisterValue> _queue;
- int _samplesTillCallback;
- int _samplesTillCallbackRemainder;
- int _samplesPerCallback;
- int _samplesPerCallbackRemainder;
bool _channelVoiced[ADLIB_CHANNEL_COUNT];
int _channelVolume[ADLIB_CHANNEL_COUNT];
@@ -495,13 +492,8 @@ public:
virtual void proc38(int channel, int cmd, int value);
virtual void setPitch(int channel, int pitchBlend);
- // AudioStream interface
- virtual int readBuffer(int16 *buffer, const int numSamples);
- virtual bool isStereo() const { return false; }
- virtual bool endOfData() const { return false; }
- virtual int getRate() const { return _sampleRate; }
-
- void update(int16 *buf, int len);
+private:
+ void onTimer();
};
class SoundBlasterDriver: public SoundDriver {
diff --git a/engines/tsage/tsage.cpp b/engines/tsage/tsage.cpp
index 4412d0670f..b94b82f423 100644
--- a/engines/tsage/tsage.cpp
+++ b/engines/tsage/tsage.cpp
@@ -112,10 +112,12 @@ void TSageEngine::initialize() {
// Reset all global variables
R2_GLOBALS.reset();
} else if (g_vm->getGameID() == GType_Sherlock1) {
+#ifdef TSAGE_SHERLOCK_ENABLED
g_resourceManager->addLib("SF3.RLB");
g_globals = new Globals();
return;
+#endif
}
g_globals->gfxManager().setDefaults();
diff --git a/engines/wintermute/base/base_script_holder.cpp b/engines/wintermute/base/base_script_holder.cpp
index 8383657239..5b1c961479 100644
--- a/engines/wintermute/base/base_script_holder.cpp
+++ b/engines/wintermute/base/base_script_holder.cpp
@@ -302,7 +302,7 @@ bool BaseScriptHolder::addScript(const char *filename) {
for (uint32 i = 0; i < _scripts.size(); i++) {
if (scumm_stricmp(_scripts[i]->_filename, filename) == 0) {
if (_scripts[i]->_state != SCRIPT_FINISHED) {
- BaseEngine::LOG(0, "BaseScriptHolder::AddScript - trying to add script '%s' mutiple times (obj: '%s')", filename, getName());
+ BaseEngine::LOG(0, "BaseScriptHolder::AddScript - trying to add script '%s' multiple times (obj: '%s')", filename, getName());
return STATUS_OK;
}
}
diff --git a/engines/zvision/configure.engine b/engines/zvision/configure.engine
index 38a5959995..226870c3fd 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 "ZVision" yes "" "" "freetype2 16bit"
+add_engine zvision "Z-Vision" yes "" "" "freetype2 16bit"
diff --git a/engines/zvision/core/clock.h b/engines/zvision/core/clock.h
index cbf52be560..ae8c968111 100644
--- a/engines/zvision/core/clock.h
+++ b/engines/zvision/core/clock.h
@@ -67,14 +67,14 @@ public:
}
/**
- * Pause the clock. Any future delta times will take this pause into account.
- * Has no effect if the clock is already paused.
- */
+ * Un-pause the clock.
+ * Has no effect if the clock is already un-paused.
+ */
void start();
/**
- * Un-pause the clock.
- * Has no effect if the clock is already un-paused.
+ * Pause the clock. Any future delta times will take this pause into account.
+ * Has no effect if the clock is already paused.
*/
void stop();
};
diff --git a/engines/zvision/core/console.cpp b/engines/zvision/core/console.cpp
index f5cacb582c..336541d82a 100644
--- a/engines/zvision/core/console.cpp
+++ b/engines/zvision/core/console.cpp
@@ -275,7 +275,7 @@ bool Console::cmdDumpFiles(int argc, const char **argv) {
bool Console::cmdDumpImage(int argc, const char **argv) {
if (argc != 2) {
- debugPrintf("Use %s <TGA/TGZ name> to dump a ZVision TGA/TGZ image into a regular BMP image\n", argv[0]);
+ debugPrintf("Use %s <TGA/TGZ name> to dump a Z-Vision TGA/TGZ image into a regular BMP image\n", argv[0]);
return true;
}
diff --git a/engines/zvision/detection.cpp b/engines/zvision/detection.cpp
index c817cbf3e9..f44e653c2a 100644
--- a/engines/zvision/detection.cpp
+++ b/engines/zvision/detection.cpp
@@ -24,8 +24,9 @@
#include "base/plugins.h"
+#include "engines/advancedDetector.h"
+
#include "zvision/zvision.h"
-#include "zvision/detection.h"
#include "zvision/file/save_manager.h"
#include "zvision/scripting/script_manager.h"
@@ -36,277 +37,39 @@
namespace ZVision {
-uint32 ZVision::getFeatures() const {
- return _gameDescription->desc.flags;
-}
+struct ZVisionGameDescription {
+ ADGameDescription desc;
+ ZVisionGameId gameId;
+};
+ZVisionGameId ZVision::getGameId() const {
+ return _gameDescription->gameId;
+}
Common::Language ZVision::getLanguage() const {
return _gameDescription->desc.language;
}
+uint32 ZVision::getFeatures() const {
+ return _gameDescription->desc.flags;
+}
} // End of namespace ZVision
-static const PlainGameDescriptor zVisionGames[] = {
- {"zvision", "ZVision Game"},
- {"znemesis", "Zork Nemesis: The Forbidden Lands"},
- {"zgi", "Zork: Grand Inquisitor"},
- {0, 0}
-};
-
-namespace ZVision {
-
-#define GAMEOPTION_ORIGINAL_SAVELOAD GUIO_GAMEOPTIONS1
-#define GAMEOPTION_DOUBLE_FPS GUIO_GAMEOPTIONS2
-#define GAMEOPTION_ENABLE_VENUS GUIO_GAMEOPTIONS3
-#define GAMEOPTION_DISABLE_ANIM_WHILE_TURNING GUIO_GAMEOPTIONS4
-#define GAMEOPTION_USE_HIRES_MPEG_MOVIES GUIO_GAMEOPTIONS5
-
-static const ZVisionGameDescription gameDescriptions[] = {
-
- {
- // Zork Nemesis English version
- {
- "znemesis",
- 0,
- AD_ENTRY1s("CSCR.ZFS", "88226e51a205d2e50c67a5237f3bd5f2", 2397741),
- Common::EN_ANY,
- Common::kPlatformDOS,
- ADGF_NO_FLAGS,
- GUIO4(GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_DOUBLE_FPS, GAMEOPTION_ENABLE_VENUS, GAMEOPTION_DISABLE_ANIM_WHILE_TURNING)
- },
- GID_NEMESIS
- },
-
- {
- // Zork Nemesis French version
- {
- "znemesis",
- 0,
- {{"CSCR.ZFS", 0, "f04113357b4748c13efcb58b4629887c", 2577873},
- {"NEMESIS.STR", 0, "333bcb17bbb7f57cae742fbbe44f56f3", 9219},
- AD_LISTEND
- },
- Common::FR_FRA,
- Common::kPlatformDOS,
- ADGF_NO_FLAGS,
- GUIO4(GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_DOUBLE_FPS, GAMEOPTION_ENABLE_VENUS, GAMEOPTION_DISABLE_ANIM_WHILE_TURNING)
- },
- GID_NEMESIS
- },
-
- {
- // Zork Nemesis German version
- {
- "znemesis",
- 0,
- {{"CSCR.ZFS", 0, "f04113357b4748c13efcb58b4629887c", 2577873},
- {"NEMESIS.STR", 0, "3d1a12b907751653866cffc6d4dfb331", 9505},
- AD_LISTEND
- },
- Common::DE_DEU,
- Common::kPlatformDOS,
- ADGF_NO_FLAGS,
- GUIO4(GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_DOUBLE_FPS, GAMEOPTION_ENABLE_VENUS, GAMEOPTION_DISABLE_ANIM_WHILE_TURNING)
- },
- GID_NEMESIS
- },
-
- {
- // Zork Nemesis Italian version
- {
- "znemesis",
- 0,
- {{"CSCR.ZFS", 0, "f04113357b4748c13efcb58b4629887c", 2577873},
- {"NEMESIS.STR", 0, "7c568feca8d9f9ae855c47183612c305", 9061},
- AD_LISTEND
- },
- Common::IT_ITA,
- Common::kPlatformDOS,
- ADGF_NO_FLAGS,
- GUIO4(GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_DOUBLE_FPS, GAMEOPTION_ENABLE_VENUS, GAMEOPTION_DISABLE_ANIM_WHILE_TURNING)
- },
- GID_NEMESIS
- },
-
- {
- // Zork Nemesis English demo version
- {
- "znemesis",
- "Demo",
- AD_ENTRY1s("SCRIPTS.ZFS", "64f1e881394e9462305104f99513c833", 380539),
- Common::EN_ANY,
- Common::kPlatformWindows,
- ADGF_DEMO,
- GUIO4(GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_DOUBLE_FPS, GAMEOPTION_ENABLE_VENUS, GAMEOPTION_DISABLE_ANIM_WHILE_TURNING)
- },
- GID_NEMESIS
- },
-
- {
- // Zork Grand Inquisitor English CD version
- {
- "zgi",
- "CD",
- AD_ENTRY1s("SCRIPTS.ZFS", "81efd40ecc3d22531e211368b779f17f", 8336944),
- Common::EN_ANY,
- Common::kPlatformWindows,
- ADGF_NO_FLAGS,
- GUIO3(GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_DOUBLE_FPS, GAMEOPTION_DISABLE_ANIM_WHILE_TURNING)
- },
- GID_GRANDINQUISITOR
- },
-
- {
- // Zork Grand Inquisitor French CD version, reported by ulrichh on IRC
- {
- "zgi",
- "CD",
- AD_ENTRY1s("SCRIPTS.ZFS", "4d1ec4ade7ecc9ee9ec591d43ca3d213", 8338133),
- Common::FR_FRA,
- Common::kPlatformWindows,
- ADGF_NO_FLAGS,
- GUIO3(GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_DOUBLE_FPS, GAMEOPTION_DISABLE_ANIM_WHILE_TURNING)
- },
- GID_GRANDINQUISITOR
- },
-
- {
- // Zork Grand Inquisitor German CD version, reported by breit in bug #6760
- {
- "zgi",
- "CD",
- AD_ENTRY1s("SCRIPTS.ZFS", "b7ac7e331b9b7f884590b0b325b560c8", 8338133),
- Common::DE_DEU,
- Common::kPlatformWindows,
- ADGF_NO_FLAGS,
- GUIO3(GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_DOUBLE_FPS, GAMEOPTION_DISABLE_ANIM_WHILE_TURNING)
- },
- GID_GRANDINQUISITOR
- },
-
- {
- // Zork Grand Inquisitor Spanish CD version, reported by dianiu in bug #6764
- {
- "zgi",
- "CD",
- AD_ENTRY1s("SCRIPTS.ZFS", "5cdc4b99c1134053af135aae71326fd1", 8338141),
- Common::ES_ESP,
- Common::kPlatformWindows,
- ADGF_NO_FLAGS,
- GUIO3(GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_DOUBLE_FPS, GAMEOPTION_DISABLE_ANIM_WHILE_TURNING)
- },
- GID_GRANDINQUISITOR
- },
-
- {
- // Zork Grand Inquisitor English DVD version
- {
- "zgi",
- "DVD",
- AD_ENTRY1s("SCRIPTS.ZFS", "03157a3399513bfaaf8dc6d5ab798b36", 8433326),
- Common::EN_ANY,
- Common::kPlatformWindows,
- ADGF_NO_FLAGS,
- GUIO4(GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_DOUBLE_FPS, GAMEOPTION_DISABLE_ANIM_WHILE_TURNING, GAMEOPTION_USE_HIRES_MPEG_MOVIES)
- },
- GID_GRANDINQUISITOR
- },
-
- {
- // Zork Grand Inquisitor English demo version
- {
- "zgi",
- "Demo",
- AD_ENTRY1s("SCRIPTS.ZFS", "71a2494fd2fb999347deb13401e9b998", 304239),
- Common::EN_ANY,
- Common::kPlatformWindows,
- ADGF_DEMO,
- GUIO3(GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_DOUBLE_FPS, GAMEOPTION_DISABLE_ANIM_WHILE_TURNING)
- },
- GID_GRANDINQUISITOR
- },
-
- {
- AD_TABLE_END_MARKER,
- GID_NONE
- }
-};
-
-} // End of namespace ZVision
-
-static const char *directoryGlobs[] = {
- "znemscr",
- 0
-};
-
-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
- }
- },
-
- {
- GAMEOPTION_DOUBLE_FPS,
- {
- _s("Double FPS"),
- _s("Increase game FPS from 30 to 60"),
- "doublefps",
- false
- }
- },
-
- {
- GAMEOPTION_ENABLE_VENUS,
- {
- _s("Enable Venus"),
- _s("Enable the Venus help system"),
- "venusenabled",
- true
- }
- },
-
- {
- GAMEOPTION_DISABLE_ANIM_WHILE_TURNING,
- {
- _s("Disable animation while turning"),
- _s("Disable animation while turning in panoramic mode"),
- "noanimwhileturning",
- false
- }
- },
-
- {
- GAMEOPTION_USE_HIRES_MPEG_MOVIES,
- {
- _s("Use the hires MPEG movies"),
- _s("Use the hires MPEG movies of the DVD version, instead of the lowres AVI ones"),
- "mpegmovies",
- true
- }
- },
-
- AD_EXTRA_GUI_OPTIONS_TERMINATOR
-};
+#include "zvision/detection_tables.h"
class ZVisionMetaEngine : public AdvancedMetaEngine {
public:
- ZVisionMetaEngine() : AdvancedMetaEngine(ZVision::gameDescriptions, sizeof(ZVision::ZVisionGameDescription), zVisionGames, optionsList) {
+ ZVisionMetaEngine() : AdvancedMetaEngine(ZVision::gameDescriptions, sizeof(ZVision::ZVisionGameDescription), ZVision::zVisionGames, ZVision::optionsList) {
_maxScanDepth = 2;
- _directoryGlobs = directoryGlobs;
+ _directoryGlobs = ZVision::directoryGlobs;
_singleid = "zvision";
}
virtual const char *getName() const {
- return "ZVision";
+ return "Z-Vision";
}
virtual const char *getOriginalCopyright() const {
- return "ZVision Activision (C) 1996";
+ return "Z-Vision (C) 1996 Activision";
}
virtual bool hasFeature(MetaEngineFeature f) const;
diff --git a/engines/zvision/detection_tables.h b/engines/zvision/detection_tables.h
new file mode 100644
index 0000000000..06bc58ee7f
--- /dev/null
+++ b/engines/zvision/detection_tables.h
@@ -0,0 +1,277 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public 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 ZVISION_DETECTION_TABLES_H
+#define ZVISION_DETECTION_TABLES_H
+
+namespace ZVision {
+
+static const PlainGameDescriptor zVisionGames[] = {
+ { "zvision", "Z-Vision Game" },
+ { "znemesis", "Zork Nemesis: The Forbidden Lands" },
+ { "zgi", "Zork: Grand Inquisitor" },
+ { 0, 0 }
+};
+
+static const char *directoryGlobs[] = {
+ "znemscr",
+ 0
+};
+
+#define GAMEOPTION_ORIGINAL_SAVELOAD GUIO_GAMEOPTIONS1
+#define GAMEOPTION_DOUBLE_FPS GUIO_GAMEOPTIONS2
+#define GAMEOPTION_ENABLE_VENUS GUIO_GAMEOPTIONS3
+#define GAMEOPTION_DISABLE_ANIM_WHILE_TURNING GUIO_GAMEOPTIONS4
+#define GAMEOPTION_USE_HIRES_MPEG_MOVIES GUIO_GAMEOPTIONS5
+
+static const ADExtraGuiOptionsMap optionsList[] = {
+
+ {
+ GAMEOPTION_ORIGINAL_SAVELOAD,
+ {
+ _s("Use original save/load screens"),
+ _s("Use the original save/load screens instead of the ScummVM interface"),
+ "originalsaveload",
+ false
+ }
+ },
+
+ {
+ GAMEOPTION_DOUBLE_FPS,
+ {
+ _s("Double FPS"),
+ _s("Increase framerate from 30 to 60 FPS"),
+ "doublefps",
+ false
+ }
+ },
+
+ {
+ GAMEOPTION_ENABLE_VENUS,
+ {
+ _s("Enable Venus"),
+ _s("Enable the Venus help system"),
+ "venusenabled",
+ true
+ }
+ },
+
+ {
+ GAMEOPTION_DISABLE_ANIM_WHILE_TURNING,
+ {
+ _s("Disable animation while turning"),
+ _s("Disable animation while turning in panorama mode"),
+ "noanimwhileturning",
+ false
+ }
+ },
+
+ {
+ GAMEOPTION_USE_HIRES_MPEG_MOVIES,
+ {
+ _s("Use high resolution MPEG video"),
+ _s("Use MPEG video from the DVD version, instead of lower resolution AVI"),
+ "mpegmovies",
+ true
+ }
+ },
+
+ AD_EXTRA_GUI_OPTIONS_TERMINATOR
+};
+
+static const ZVisionGameDescription gameDescriptions[] = {
+
+ {
+ // Zork Nemesis English version
+ {
+ "znemesis",
+ 0,
+ AD_ENTRY1s("CSCR.ZFS", "88226e51a205d2e50c67a5237f3bd5f2", 2397741),
+ Common::EN_ANY,
+ Common::kPlatformDOS,
+ ADGF_NO_FLAGS,
+ GUIO4(GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_DOUBLE_FPS, GAMEOPTION_ENABLE_VENUS, GAMEOPTION_DISABLE_ANIM_WHILE_TURNING)
+ },
+ GID_NEMESIS
+ },
+
+ {
+ // Zork Nemesis French version
+ {
+ "znemesis",
+ 0,
+ {
+ { "CSCR.ZFS", 0, "f04113357b4748c13efcb58b4629887c", 2577873 },
+ { "NEMESIS.STR", 0, "333bcb17bbb7f57cae742fbbe44f56f3", 9219 },
+ AD_LISTEND
+ },
+ Common::FR_FRA,
+ Common::kPlatformDOS,
+ ADGF_NO_FLAGS,
+ GUIO4(GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_DOUBLE_FPS, GAMEOPTION_ENABLE_VENUS, GAMEOPTION_DISABLE_ANIM_WHILE_TURNING)
+ },
+ GID_NEMESIS
+ },
+
+ {
+ // Zork Nemesis German version
+ {
+ "znemesis",
+ 0,
+ {
+ { "CSCR.ZFS", 0, "f04113357b4748c13efcb58b4629887c", 2577873 },
+ { "NEMESIS.STR", 0, "3d1a12b907751653866cffc6d4dfb331", 9505 },
+ AD_LISTEND
+ },
+ Common::DE_DEU,
+ Common::kPlatformDOS,
+ ADGF_NO_FLAGS,
+ GUIO4(GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_DOUBLE_FPS, GAMEOPTION_ENABLE_VENUS, GAMEOPTION_DISABLE_ANIM_WHILE_TURNING)
+ },
+ GID_NEMESIS
+ },
+
+ {
+ // Zork Nemesis Italian version
+ {
+ "znemesis",
+ 0,
+ {
+ { "CSCR.ZFS", 0, "f04113357b4748c13efcb58b4629887c", 2577873 },
+ { "NEMESIS.STR", 0, "7c568feca8d9f9ae855c47183612c305", 9061 },
+ AD_LISTEND
+ },
+ Common::IT_ITA,
+ Common::kPlatformDOS,
+ ADGF_NO_FLAGS,
+ GUIO4(GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_DOUBLE_FPS, GAMEOPTION_ENABLE_VENUS, GAMEOPTION_DISABLE_ANIM_WHILE_TURNING)
+ },
+ GID_NEMESIS
+ },
+
+ {
+ // Zork Nemesis English demo version
+ {
+ "znemesis",
+ "Demo",
+ AD_ENTRY1s("SCRIPTS.ZFS", "64f1e881394e9462305104f99513c833", 380539),
+ Common::EN_ANY,
+ Common::kPlatformWindows,
+ ADGF_DEMO,
+ GUIO4(GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_DOUBLE_FPS, GAMEOPTION_ENABLE_VENUS, GAMEOPTION_DISABLE_ANIM_WHILE_TURNING)
+ },
+ GID_NEMESIS
+ },
+
+ {
+ // Zork Grand Inquisitor English CD version
+ {
+ "zgi",
+ "CD",
+ AD_ENTRY1s("SCRIPTS.ZFS", "81efd40ecc3d22531e211368b779f17f", 8336944),
+ Common::EN_ANY,
+ Common::kPlatformWindows,
+ ADGF_NO_FLAGS,
+ GUIO3(GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_DOUBLE_FPS, GAMEOPTION_DISABLE_ANIM_WHILE_TURNING)
+ },
+ GID_GRANDINQUISITOR
+ },
+
+ {
+ // Zork Grand Inquisitor French CD version, reported by ulrichh on IRC
+ {
+ "zgi",
+ "CD",
+ AD_ENTRY1s("SCRIPTS.ZFS", "4d1ec4ade7ecc9ee9ec591d43ca3d213", 8338133),
+ Common::FR_FRA,
+ Common::kPlatformWindows,
+ ADGF_NO_FLAGS,
+ GUIO3(GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_DOUBLE_FPS, GAMEOPTION_DISABLE_ANIM_WHILE_TURNING)
+ },
+ GID_GRANDINQUISITOR
+ },
+
+ {
+ // Zork Grand Inquisitor German CD version, reported by breit in bug #6760
+ {
+ "zgi",
+ "CD",
+ AD_ENTRY1s("SCRIPTS.ZFS", "b7ac7e331b9b7f884590b0b325b560c8", 8338133),
+ Common::DE_DEU,
+ Common::kPlatformWindows,
+ ADGF_NO_FLAGS,
+ GUIO3(GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_DOUBLE_FPS, GAMEOPTION_DISABLE_ANIM_WHILE_TURNING)
+ },
+ GID_GRANDINQUISITOR
+ },
+
+ {
+ // Zork Grand Inquisitor Spanish CD version, reported by dianiu in bug #6764
+ {
+ "zgi",
+ "CD",
+ AD_ENTRY1s("SCRIPTS.ZFS", "5cdc4b99c1134053af135aae71326fd1", 8338141),
+ Common::ES_ESP,
+ Common::kPlatformWindows,
+ ADGF_NO_FLAGS,
+ GUIO3(GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_DOUBLE_FPS, GAMEOPTION_DISABLE_ANIM_WHILE_TURNING)
+ },
+ GID_GRANDINQUISITOR
+ },
+
+ {
+ // Zork Grand Inquisitor English DVD version
+ {
+ "zgi",
+ "DVD",
+ AD_ENTRY1s("SCRIPTS.ZFS", "03157a3399513bfaaf8dc6d5ab798b36", 8433326),
+ Common::EN_ANY,
+ Common::kPlatformWindows,
+ ADGF_NO_FLAGS,
+ GUIO4(GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_DOUBLE_FPS, GAMEOPTION_DISABLE_ANIM_WHILE_TURNING, GAMEOPTION_USE_HIRES_MPEG_MOVIES)
+ },
+ GID_GRANDINQUISITOR
+ },
+
+ {
+ // Zork Grand Inquisitor English demo version
+ {
+ "zgi",
+ "Demo",
+ AD_ENTRY1s("SCRIPTS.ZFS", "71a2494fd2fb999347deb13401e9b998", 304239),
+ Common::EN_ANY,
+ Common::kPlatformWindows,
+ ADGF_DEMO,
+ GUIO3(GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_DOUBLE_FPS, GAMEOPTION_DISABLE_ANIM_WHILE_TURNING)
+ },
+ GID_GRANDINQUISITOR
+ },
+
+ {
+ AD_TABLE_END_MARKER,
+ GID_NONE
+ }
+};
+
+} // End of namespace ZVision
+
+#endif
diff --git a/engines/zvision/file/save_manager.cpp b/engines/zvision/file/save_manager.cpp
index 63b54269de..d169679e28 100644
--- a/engines/zvision/file/save_manager.cpp
+++ b/engines/zvision/file/save_manager.cpp
@@ -205,7 +205,7 @@ bool SaveManager::readSaveGameHeader(Common::InSaveFile *in, SaveGameHeader &hea
return true;
}
if (tag != SAVEGAME_ID) {
- warning("File is not a ZVision save file. Aborting load");
+ warning("File is not a Z-Vision save file. Aborting load");
return false;
}
diff --git a/engines/zvision/graphics/render_manager.cpp b/engines/zvision/graphics/render_manager.cpp
index ce0a02a1ad..f978ef7844 100644
--- a/engines/zvision/graphics/render_manager.cpp
+++ b/engines/zvision/graphics/render_manager.cpp
@@ -196,7 +196,7 @@ void RenderManager::readImageToSurface(const Common::String &fileName, Graphics:
uint32 imageHeight;
Image::TGADecoder tga;
uint16 *buffer;
- // All ZVision images are in RGB 555
+ // All Z-Vision images are in RGB 555
destination.format = _engine->_resourcePixelFormat;
bool isTGZ;
diff --git a/engines/zvision/scripting/actions.cpp b/engines/zvision/scripting/actions.cpp
index 9a8b734e0c..e1380b0eb2 100644
--- a/engines/zvision/scripting/actions.cpp
+++ b/engines/zvision/scripting/actions.cpp
@@ -47,15 +47,18 @@
namespace ZVision {
-ResultAction::ResultAction(ZVision *engine, int32 slotkey) : _engine(engine), _slotKey(slotkey), _scriptManager(engine->getScriptManager()) {
+ResultAction::ResultAction(ZVision *engine, int32 slotKey) :
+ _engine(engine),
+ _slotKey(slotKey),
+ _scriptManager(engine->getScriptManager()) {
}
//////////////////////////////////////////////////////////////////////////////
// ActionAdd
//////////////////////////////////////////////////////////////////////////////
-ActionAdd::ActionAdd(ZVision *engine, int32 slotkey, const Common::String &line) :
- ResultAction(engine, slotkey) {
+ActionAdd::ActionAdd(ZVision *engine, int32 slotKey, const Common::String &line) :
+ ResultAction(engine, slotKey) {
_key = 0;
_value = 0;
@@ -71,8 +74,8 @@ bool ActionAdd::execute() {
// ActionAssign
//////////////////////////////////////////////////////////////////////////////
-ActionAssign::ActionAssign(ZVision *engine, int32 slotkey, const Common::String &line) :
- ResultAction(engine, slotkey) {
+ActionAssign::ActionAssign(ZVision *engine, int32 slotKey, const Common::String &line) :
+ ResultAction(engine, slotKey) {
_key = 0;
char buf[64];
@@ -94,8 +97,8 @@ bool ActionAssign::execute() {
// ActionAttenuate
//////////////////////////////////////////////////////////////////////////////
-ActionAttenuate::ActionAttenuate(ZVision *engine, int32 slotkey, const Common::String &line) :
- ResultAction(engine, slotkey) {
+ActionAttenuate::ActionAttenuate(ZVision *engine, int32 slotKey, const Common::String &line) :
+ ResultAction(engine, slotKey) {
_key = 0;
_attenuation = 0;
@@ -115,8 +118,8 @@ bool ActionAttenuate::execute() {
// ActionChangeLocation
//////////////////////////////////////////////////////////////////////////////
-ActionChangeLocation::ActionChangeLocation(ZVision *engine, int32 slotkey, const Common::String &line) :
- ResultAction(engine, slotkey) {
+ActionChangeLocation::ActionChangeLocation(ZVision *engine, int32 slotKey, const Common::String &line) :
+ ResultAction(engine, slotKey) {
_world = 'g';
_room = 'a';
_node = 'r';
@@ -137,8 +140,8 @@ bool ActionChangeLocation::execute() {
// ActionCrossfade
//////////////////////////////////////////////////////////////////////////////
-ActionCrossfade::ActionCrossfade(ZVision *engine, int32 slotkey, const Common::String &line) :
- ResultAction(engine, slotkey) {
+ActionCrossfade::ActionCrossfade(ZVision *engine, int32 slotKey, const Common::String &line) :
+ ResultAction(engine, slotKey) {
_keyOne = 0;
_keyTwo = 0;
_oneStartVolume = 0;
@@ -181,8 +184,8 @@ bool ActionCrossfade::execute() {
// ActionCursor
//////////////////////////////////////////////////////////////////////////////
-ActionCursor::ActionCursor(ZVision *engine, int32 slotkey, const Common::String &line) :
- ResultAction(engine, slotkey) {
+ActionCursor::ActionCursor(ZVision *engine, int32 slotKey, const Common::String &line) :
+ ResultAction(engine, slotKey) {
Common::String up = line;
up.toUppercase();
_action = 0;
@@ -213,8 +216,8 @@ bool ActionCursor::execute() {
// ActionDelayRender
//////////////////////////////////////////////////////////////////////////////
-ActionDelayRender::ActionDelayRender(ZVision *engine, int32 slotkey, const Common::String &line) :
- ResultAction(engine, slotkey) {
+ActionDelayRender::ActionDelayRender(ZVision *engine, int32 slotKey, const Common::String &line) :
+ ResultAction(engine, slotKey) {
_framesToDelay = 0;
sscanf(line.c_str(), "%u", &_framesToDelay);
// Limit to 10 frames maximum. This fixes the script bug in ZGI scene px10
@@ -231,8 +234,8 @@ bool ActionDelayRender::execute() {
// ActionDisableControl
//////////////////////////////////////////////////////////////////////////////
-ActionDisableControl::ActionDisableControl(ZVision *engine, int32 slotkey, const Common::String &line) :
- ResultAction(engine, slotkey) {
+ActionDisableControl::ActionDisableControl(ZVision *engine, int32 slotKey, const Common::String &line) :
+ ResultAction(engine, slotKey) {
_key = 0;
sscanf(line.c_str(), "%u", &_key);
@@ -247,8 +250,8 @@ bool ActionDisableControl::execute() {
// ActionDisplayMessage
//////////////////////////////////////////////////////////////////////////////
-ActionDisplayMessage::ActionDisplayMessage(ZVision *engine, int32 slotkey, const Common::String &line) :
- ResultAction(engine, slotkey) {
+ActionDisplayMessage::ActionDisplayMessage(ZVision *engine, int32 slotKey, const Common::String &line) :
+ ResultAction(engine, slotKey) {
_control = 0;
_msgid = 0;
@@ -282,8 +285,8 @@ bool ActionDissolve::execute() {
// ActionDistort - only used by Zork: Nemesis for the "treatment" puzzle in the Sanitarium (aj30)
//////////////////////////////////////////////////////////////////////////////
-ActionDistort::ActionDistort(ZVision *engine, int32 slotkey, const Common::String &line) :
- ResultAction(engine, slotkey) {
+ActionDistort::ActionDistort(ZVision *engine, int32 slotKey, const Common::String &line) :
+ ResultAction(engine, slotKey) {
_distSlot = 0;
_speed = 0;
_startAngle = 60.0;
@@ -311,8 +314,8 @@ bool ActionDistort::execute() {
// ActionEnableControl
//////////////////////////////////////////////////////////////////////////////
-ActionEnableControl::ActionEnableControl(ZVision *engine, int32 slotkey, const Common::String &line) :
- ResultAction(engine, slotkey) {
+ActionEnableControl::ActionEnableControl(ZVision *engine, int32 slotKey, const Common::String &line) :
+ ResultAction(engine, slotKey) {
_key = 0;
sscanf(line.c_str(), "%u", &_key);
@@ -327,8 +330,8 @@ bool ActionEnableControl::execute() {
// ActionFlushMouseEvents
//////////////////////////////////////////////////////////////////////////////
-ActionFlushMouseEvents::ActionFlushMouseEvents(ZVision *engine, int32 slotkey) :
- ResultAction(engine, slotkey) {
+ActionFlushMouseEvents::ActionFlushMouseEvents(ZVision *engine, int32 slotKey) :
+ ResultAction(engine, slotKey) {
}
bool ActionFlushMouseEvents::execute() {
@@ -341,8 +344,8 @@ bool ActionFlushMouseEvents::execute() {
// ActionInventory
//////////////////////////////////////////////////////////////////////////////
-ActionInventory::ActionInventory(ZVision *engine, int32 slotkey, const Common::String &line) :
- ResultAction(engine, slotkey) {
+ActionInventory::ActionInventory(ZVision *engine, int32 slotKey, const Common::String &line) :
+ ResultAction(engine, slotKey) {
_type = -1;
_key = 0;
@@ -393,8 +396,8 @@ bool ActionInventory::execute() {
// ActionKill - only used by ZGI
//////////////////////////////////////////////////////////////////////////////
-ActionKill::ActionKill(ZVision *engine, int32 slotkey, const Common::String &line) :
- ResultAction(engine, slotkey) {
+ActionKill::ActionKill(ZVision *engine, int32 slotKey, const Common::String &line) :
+ ResultAction(engine, slotKey) {
_key = 0;
_type = 0;
char keytype[25];
@@ -432,8 +435,8 @@ bool ActionKill::execute() {
// ActionMenuBarEnable
//////////////////////////////////////////////////////////////////////////////
-ActionMenuBarEnable::ActionMenuBarEnable(ZVision *engine, int32 slotkey, const Common::String &line) :
- ResultAction(engine, slotkey) {
+ActionMenuBarEnable::ActionMenuBarEnable(ZVision *engine, int32 slotKey, const Common::String &line) :
+ ResultAction(engine, slotKey) {
_menus = 0xFFFF;
sscanf(line.c_str(), "%hu", &_menus);
@@ -448,8 +451,8 @@ bool ActionMenuBarEnable::execute() {
// ActionMusic
//////////////////////////////////////////////////////////////////////////////
-ActionMusic::ActionMusic(ZVision *engine, int32 slotkey, const Common::String &line, bool global) :
- ResultAction(engine, slotkey),
+ActionMusic::ActionMusic(ZVision *engine, int32 slotKey, const Common::String &line, bool global) :
+ ResultAction(engine, slotKey),
_note(0),
_prog(0),
_universe(global) {
@@ -527,8 +530,8 @@ bool ActionMusic::execute() {
// ActionPanTrack
//////////////////////////////////////////////////////////////////////////////
-ActionPanTrack::ActionPanTrack(ZVision *engine, int32 slotkey, const Common::String &line) :
- ResultAction(engine, slotkey),
+ActionPanTrack::ActionPanTrack(ZVision *engine, int32 slotKey, const Common::String &line) :
+ ResultAction(engine, slotKey),
_pos(0),
_musicSlot(0) {
@@ -552,8 +555,8 @@ bool ActionPanTrack::execute() {
// ActionPreferences
//////////////////////////////////////////////////////////////////////////////
-ActionPreferences::ActionPreferences(ZVision *engine, int32 slotkey, const Common::String &line) :
- ResultAction(engine, slotkey) {
+ActionPreferences::ActionPreferences(ZVision *engine, int32 slotKey, const Common::String &line) :
+ ResultAction(engine, slotKey) {
if (line.compareToIgnoreCase("save") == 0)
_save = true;
else
@@ -573,8 +576,8 @@ bool ActionPreferences::execute() {
// ActionPreloadAnimation
//////////////////////////////////////////////////////////////////////////////
-ActionPreloadAnimation::ActionPreloadAnimation(ZVision *engine, int32 slotkey, const Common::String &line) :
- ResultAction(engine, slotkey) {
+ActionPreloadAnimation::ActionPreloadAnimation(ZVision *engine, int32 slotKey, const Common::String &line) :
+ ResultAction(engine, slotKey) {
_mask = 0;
_framerate = 0;
@@ -612,8 +615,8 @@ bool ActionPreloadAnimation::execute() {
// ActionUnloadAnimation
//////////////////////////////////////////////////////////////////////////////
-ActionUnloadAnimation::ActionUnloadAnimation(ZVision *engine, int32 slotkey, const Common::String &line) :
- ResultAction(engine, slotkey) {
+ActionUnloadAnimation::ActionUnloadAnimation(ZVision *engine, int32 slotKey, const Common::String &line) :
+ ResultAction(engine, slotKey) {
_key = 0;
sscanf(line.c_str(), "%u", &_key);
@@ -632,8 +635,8 @@ bool ActionUnloadAnimation::execute() {
// ActionPlayAnimation
//////////////////////////////////////////////////////////////////////////////
-ActionPlayAnimation::ActionPlayAnimation(ZVision *engine, int32 slotkey, const Common::String &line) :
- ResultAction(engine, slotkey) {
+ActionPlayAnimation::ActionPlayAnimation(ZVision *engine, int32 slotKey, const Common::String &line) :
+ ResultAction(engine, slotKey) {
_x = 0;
_y = 0;
_x2 = 0;
@@ -690,8 +693,8 @@ bool ActionPlayAnimation::execute() {
// ActionPlayPreloadAnimation
//////////////////////////////////////////////////////////////////////////////
-ActionPlayPreloadAnimation::ActionPlayPreloadAnimation(ZVision *engine, int32 slotkey, const Common::String &line) :
- ResultAction(engine, slotkey) {
+ActionPlayPreloadAnimation::ActionPlayPreloadAnimation(ZVision *engine, int32 slotKey, const Common::String &line) :
+ ResultAction(engine, slotKey) {
_controlKey = 0;
_x1 = 0;
_y1 = 0;
@@ -729,8 +732,8 @@ bool ActionQuit::execute() {
// ActionRegion - only used by Zork: Nemesis
//////////////////////////////////////////////////////////////////////////////
-ActionRegion::ActionRegion(ZVision *engine, int32 slotkey, const Common::String &line) :
- ResultAction(engine, slotkey) {
+ActionRegion::ActionRegion(ZVision *engine, int32 slotKey, const Common::String &line) :
+ ResultAction(engine, slotKey) {
_delay = 0;
_type = 0;
_unk1 = 0;
@@ -808,8 +811,8 @@ bool ActionRegion::execute() {
// ActionRandom
//////////////////////////////////////////////////////////////////////////////
-ActionRandom::ActionRandom(ZVision *engine, int32 slotkey, const Common::String &line) :
- ResultAction(engine, slotkey) {
+ActionRandom::ActionRandom(ZVision *engine, int32 slotKey, const Common::String &line) :
+ ResultAction(engine, slotKey) {
char maxBuffer[64];
memset(maxBuffer, 0, 64);
sscanf(line.c_str(), "%s", maxBuffer);
@@ -830,8 +833,8 @@ bool ActionRandom::execute() {
// ActionRestoreGame
//////////////////////////////////////////////////////////////////////////////
-ActionRestoreGame::ActionRestoreGame(ZVision *engine, int32 slotkey, const Common::String &line) :
- ResultAction(engine, slotkey) {
+ActionRestoreGame::ActionRestoreGame(ZVision *engine, int32 slotKey, const Common::String &line) :
+ ResultAction(engine, slotKey) {
char buf[128];
sscanf(line.c_str(), "%s", buf);
_fileName = Common::String(buf);
@@ -846,8 +849,8 @@ bool ActionRestoreGame::execute() {
// ActionRotateTo
//////////////////////////////////////////////////////////////////////////////
-ActionRotateTo::ActionRotateTo(ZVision *engine, int32 slotkey, const Common::String &line) :
- ResultAction(engine, slotkey) {
+ActionRotateTo::ActionRotateTo(ZVision *engine, int32 slotKey, const Common::String &line) :
+ ResultAction(engine, slotKey) {
_time = 0;
_toPos = 0;
@@ -864,8 +867,8 @@ bool ActionRotateTo::execute() {
// ActionSetPartialScreen
//////////////////////////////////////////////////////////////////////////////
-ActionSetPartialScreen::ActionSetPartialScreen(ZVision *engine, int32 slotkey, const Common::String &line) :
- ResultAction(engine, slotkey) {
+ActionSetPartialScreen::ActionSetPartialScreen(ZVision *engine, int32 slotKey, const Common::String &line) :
+ ResultAction(engine, slotKey) {
_x = 0;
_y = 0;
@@ -904,8 +907,8 @@ bool ActionSetPartialScreen::execute() {
// ActionSetScreen
//////////////////////////////////////////////////////////////////////////////
-ActionSetScreen::ActionSetScreen(ZVision *engine, int32 slotkey, const Common::String &line) :
- ResultAction(engine, slotkey) {
+ActionSetScreen::ActionSetScreen(ZVision *engine, int32 slotKey, const Common::String &line) :
+ ResultAction(engine, slotKey) {
char fileName[25];
sscanf(line.c_str(), "%24s", fileName);
@@ -922,8 +925,8 @@ bool ActionSetScreen::execute() {
// ActionStop
//////////////////////////////////////////////////////////////////////////////
-ActionStop::ActionStop(ZVision *engine, int32 slotkey, const Common::String &line) :
- ResultAction(engine, slotkey) {
+ActionStop::ActionStop(ZVision *engine, int32 slotKey, const Common::String &line) :
+ ResultAction(engine, slotKey) {
_key = 0;
sscanf(line.c_str(), "%u", &_key);
}
@@ -937,8 +940,8 @@ bool ActionStop::execute() {
// ActionStreamVideo
//////////////////////////////////////////////////////////////////////////////
-ActionStreamVideo::ActionStreamVideo(ZVision *engine, int32 slotkey, const Common::String &line) :
- ResultAction(engine, slotkey) {
+ActionStreamVideo::ActionStreamVideo(ZVision *engine, int32 slotKey, const Common::String &line) :
+ ResultAction(engine, slotKey) {
_x1 = 0;
_x2 = 0;
_y1 = 0;
@@ -1019,8 +1022,8 @@ bool ActionStreamVideo::execute() {
// ActionSyncSound
//////////////////////////////////////////////////////////////////////////////
-ActionSyncSound::ActionSyncSound(ZVision *engine, int32 slotkey, const Common::String &line) :
- ResultAction(engine, slotkey) {
+ActionSyncSound::ActionSyncSound(ZVision *engine, int32 slotKey, const Common::String &line) :
+ ResultAction(engine, slotKey) {
_syncto = 0;
char fileName[25];
@@ -1047,8 +1050,8 @@ bool ActionSyncSound::execute() {
// ActionTimer
//////////////////////////////////////////////////////////////////////////////
-ActionTimer::ActionTimer(ZVision *engine, int32 slotkey, const Common::String &line) :
- ResultAction(engine, slotkey) {
+ActionTimer::ActionTimer(ZVision *engine, int32 slotKey, const Common::String &line) :
+ ResultAction(engine, slotKey) {
char timeBuffer[64];
memset(timeBuffer, 0, 64);
sscanf(line.c_str(), "%s", timeBuffer);
@@ -1071,8 +1074,8 @@ bool ActionTimer::execute() {
// ActionTtyText
//////////////////////////////////////////////////////////////////////////////
-ActionTtyText::ActionTtyText(ZVision *engine, int32 slotkey, const Common::String &line) :
- ResultAction(engine, slotkey) {
+ActionTtyText::ActionTtyText(ZVision *engine, int32 slotKey, const Common::String &line) :
+ ResultAction(engine, slotKey) {
_delay = 0;
char filename[64];
diff --git a/engines/zvision/scripting/actions.h b/engines/zvision/scripting/actions.h
index ff19fc54fc..bde1baa291 100644
--- a/engines/zvision/scripting/actions.h
+++ b/engines/zvision/scripting/actions.h
@@ -269,7 +269,6 @@ public:
bool execute();
private:
- uint32 _animationKey;
uint32 _controlKey;
uint32 _x1;
uint32 _y1;
diff --git a/engines/zvision/scripting/controls/input_control.cpp b/engines/zvision/scripting/controls/input_control.cpp
index df0c77ba96..9525333ef0 100644
--- a/engines/zvision/scripting/controls/input_control.cpp
+++ b/engines/zvision/scripting/controls/input_control.cpp
@@ -43,7 +43,6 @@ InputControl::InputControl(ZVision *engine, uint32 key, Common::SeekableReadStre
_nextTabstop(0),
_focused(false),
_textChanged(false),
- _cursorOffset(0),
_enterPressed(false),
_readOnly(false),
_txtWidth(0),
diff --git a/engines/zvision/scripting/controls/input_control.h b/engines/zvision/scripting/controls/input_control.h
index 9b48514e16..6abdb3c692 100644
--- a/engines/zvision/scripting/controls/input_control.h
+++ b/engines/zvision/scripting/controls/input_control.h
@@ -51,15 +51,12 @@ private:
Common::String _currentInputText;
bool _textChanged;
- uint _cursorOffset;
bool _enterPressed;
bool _readOnly;
int16 _txtWidth;
int16 _maxTxtWidth;
Video::VideoDecoder *_animation;
- int32 _frameDelay;
- int16 _frame;
public:
void focus() {
diff --git a/engines/zvision/scripting/menu.cpp b/engines/zvision/scripting/menu.cpp
index e7775cbe3f..064bd1b57d 100644
--- a/engines/zvision/scripting/menu.cpp
+++ b/engines/zvision/scripting/menu.cpp
@@ -46,7 +46,7 @@ MenuHandler::MenuHandler(ZVision *engine) {
MenuZGI::MenuZGI(ZVision *engine) :
MenuHandler(engine) {
menuMouseFocus = -1;
- inmenu = false;
+ inMenu = false;
scrolled[0] = false;
scrolled[1] = false;
scrolled[2] = false;
@@ -60,15 +60,15 @@ MenuZGI::MenuZGI(ZVision *engine) :
char buf[24];
for (int i = 1; i < 4; i++) {
sprintf(buf, "gmzau%2.2x1.tga", i);
- _engine->getRenderManager()->readImageToSurface(buf, menuback[i - 1][0], false);
+ _engine->getRenderManager()->readImageToSurface(buf, menuBack[i - 1][0], false);
sprintf(buf, "gmzau%2.2x1.tga", i + 0x10);
- _engine->getRenderManager()->readImageToSurface(buf, menuback[i - 1][1], false);
+ _engine->getRenderManager()->readImageToSurface(buf, menuBack[i - 1][1], false);
}
for (int i = 0; i < 4; i++) {
sprintf(buf, "gmzmu%2.2x1.tga", i);
- _engine->getRenderManager()->readImageToSurface(buf, menubar[i][0], false);
+ _engine->getRenderManager()->readImageToSurface(buf, menuBar[i][0], false);
sprintf(buf, "gmznu%2.2x1.tga", i);
- _engine->getRenderManager()->readImageToSurface(buf, menubar[i][1], false);
+ _engine->getRenderManager()->readImageToSurface(buf, menuBar[i][1], false);
}
for (int i = 0; i < 50; i++) {
@@ -86,12 +86,12 @@ MenuZGI::MenuZGI(ZVision *engine) :
MenuZGI::~MenuZGI() {
for (int i = 0; i < 3; i++) {
- menuback[i][0].free();
- menuback[i][1].free();
+ menuBack[i][0].free();
+ menuBack[i][1].free();
}
for (int i = 0; i < 4; i++) {
- menubar[i][0].free();
- menubar[i][1].free();
+ menuBar[i][0].free();
+ menuBar[i][1].free();
}
for (int i = 0; i < 50; i++) {
if (items[i][0]) {
@@ -208,9 +208,9 @@ void MenuZGI::onMouseUp(const Common::Point &Pos) {
void MenuZGI::onMouseMove(const Common::Point &Pos) {
if (Pos.y < 40) {
- if (!inmenu)
+ if (!inMenu)
redraw = true;
- inmenu = true;
+ inMenu = true;
switch (menuMouseFocus) {
case kMenuItem:
if (menuBarFlag & kMenubarItems) {
@@ -311,7 +311,7 @@ void MenuZGI::onMouseMove(const Common::Point &Pos) {
if (Common::Rect(64, 0, 64 + 512, 8).contains(Pos)) { // Main
menuMouseFocus = kMenuMain;
scrolled[kMenuMain] = false;
- scrollPos[kMenuMain] = menuback[kMenuMain][1].h - menuback[kMenuMain][0].h;
+ scrollPos[kMenuMain] = menuBack[kMenuMain][1].h - menuBack[kMenuMain][0].h;
_engine->getScriptManager()->setStateValue(StateKey_MenuState, 2);
}
@@ -337,9 +337,9 @@ void MenuZGI::onMouseMove(const Common::Point &Pos) {
break;
}
} else {
- if (inmenu)
+ if (inMenu)
clean = true;
- inmenu = false;
+ inMenu = false;
if (_engine->getScriptManager()->getStateValue(StateKey_MenuState) != 0)
_engine->getScriptManager()->setStateValue(StateKey_MenuState, 0);
menuMouseFocus = -1;
@@ -369,7 +369,7 @@ void MenuZGI::process(uint32 deltatime) {
}
}
if (redraw) {
- _engine->getRenderManager()->blitSurfaceToMenu(menuback[kMenuItem][0], scrollPos[kMenuItem], 0);
+ _engine->getRenderManager()->blitSurfaceToMenu(menuBack[kMenuItem][0], scrollPos[kMenuItem], 0);
int itemCount = _engine->getScriptManager()->getStateValue(StateKey_Inv_TotalSlots);
if (itemCount == 0)
@@ -438,7 +438,7 @@ void MenuZGI::process(uint32 deltatime) {
}
}
if (redraw) {
- _engine->getRenderManager()->blitSurfaceToMenu(menuback[kMenuMagic][0], 640 - scrollPos[kMenuMagic], 0);
+ _engine->getRenderManager()->blitSurfaceToMenu(menuBack[kMenuMagic][0], 640 - scrollPos[kMenuMagic], 0);
for (int i = 0; i < 12; i++) {
bool inrect = false;
@@ -503,45 +503,45 @@ void MenuZGI::process(uint32 deltatime) {
}
}
if (redraw) {
- _engine->getRenderManager()->blitSurfaceToMenu(menuback[kMenuMain][0], 30, scrollPos[kMenuMain]);
+ _engine->getRenderManager()->blitSurfaceToMenu(menuBack[kMenuMain][0], 30, scrollPos[kMenuMain]);
if (menuBarFlag & kMenubarExit) {
if (mouseOnItem == kMainMenuExit)
- _engine->getRenderManager()->blitSurfaceToMenu(menubar[kMainMenuExit][1], 320 + 135, scrollPos[kMenuMain]);
+ _engine->getRenderManager()->blitSurfaceToMenu(menuBar[kMainMenuExit][1], 320 + 135, scrollPos[kMenuMain]);
else
- _engine->getRenderManager()->blitSurfaceToMenu(menubar[kMainMenuExit][0], 320 + 135, scrollPos[kMenuMain]);
+ _engine->getRenderManager()->blitSurfaceToMenu(menuBar[kMainMenuExit][0], 320 + 135, scrollPos[kMenuMain]);
}
if (menuBarFlag & kMenubarSettings) {
if (mouseOnItem == kMainMenuPrefs)
- _engine->getRenderManager()->blitSurfaceToMenu(menubar[kMainMenuPrefs][1], 320, scrollPos[kMenuMain]);
+ _engine->getRenderManager()->blitSurfaceToMenu(menuBar[kMainMenuPrefs][1], 320, scrollPos[kMenuMain]);
else
- _engine->getRenderManager()->blitSurfaceToMenu(menubar[kMainMenuPrefs][0], 320, scrollPos[kMenuMain]);
+ _engine->getRenderManager()->blitSurfaceToMenu(menuBar[kMainMenuPrefs][0], 320, scrollPos[kMenuMain]);
}
if (menuBarFlag & kMenubarRestore) {
if (mouseOnItem == kMainMenuLoad)
- _engine->getRenderManager()->blitSurfaceToMenu(menubar[kMainMenuLoad][1], 320 - 135, scrollPos[kMenuMain]);
+ _engine->getRenderManager()->blitSurfaceToMenu(menuBar[kMainMenuLoad][1], 320 - 135, scrollPos[kMenuMain]);
else
- _engine->getRenderManager()->blitSurfaceToMenu(menubar[kMainMenuLoad][0], 320 - 135, scrollPos[kMenuMain]);
+ _engine->getRenderManager()->blitSurfaceToMenu(menuBar[kMainMenuLoad][0], 320 - 135, scrollPos[kMenuMain]);
}
if (menuBarFlag & kMenubarSave) {
if (mouseOnItem == kMainMenuSave)
- _engine->getRenderManager()->blitSurfaceToMenu(menubar[kMainMenuSave][1], 320 - 135 * 2, scrollPos[kMenuMain]);
+ _engine->getRenderManager()->blitSurfaceToMenu(menuBar[kMainMenuSave][1], 320 - 135 * 2, scrollPos[kMenuMain]);
else
- _engine->getRenderManager()->blitSurfaceToMenu(menubar[kMainMenuSave][0], 320 - 135 * 2, scrollPos[kMenuMain]);
+ _engine->getRenderManager()->blitSurfaceToMenu(menuBar[kMainMenuSave][0], 320 - 135 * 2, scrollPos[kMenuMain]);
}
redraw = false;
}
break;
default:
if (redraw) {
- if (inmenu) {
- _engine->getRenderManager()->blitSurfaceToMenu(menuback[kMenuMain][1], 30, 0);
+ if (inMenu) {
+ _engine->getRenderManager()->blitSurfaceToMenu(menuBack[kMenuMain][1], 30, 0);
if (menuBarFlag & kMenubarItems)
- _engine->getRenderManager()->blitSurfaceToMenu(menuback[kMenuItem][1], 0, 0);
+ _engine->getRenderManager()->blitSurfaceToMenu(menuBack[kMenuItem][1], 0, 0);
if (menuBarFlag & kMenubarMagic)
- _engine->getRenderManager()->blitSurfaceToMenu(menuback[kMenuMagic][1], 640 - 28, 0);
+ _engine->getRenderManager()->blitSurfaceToMenu(menuBack[kMenuMagic][1], 640 - 28, 0);
}
redraw = false;
}
@@ -551,7 +551,7 @@ void MenuZGI::process(uint32 deltatime) {
MenuNemesis::MenuNemesis(ZVision *engine) :
MenuHandler(engine) {
- inmenu = false;
+ inMenu = false;
scrolled = false;
scrollPos = 0;
mouseOnItem = -1;
@@ -565,7 +565,7 @@ MenuNemesis::MenuNemesis(ZVision *engine) :
_engine->getRenderManager()->readImageToSurface(buf, but[i][j], false);
}
- _engine->getRenderManager()->readImageToSurface("bar.tga", menubar, false);
+ _engine->getRenderManager()->readImageToSurface("bar.tga", menuBar, false);
frm = 0;
}
@@ -575,7 +575,7 @@ MenuNemesis::~MenuNemesis() {
for (int j = 0; j < 6; j++)
but[i][j].free();
- menubar.free();
+ menuBar.free();
}
static const int16 buts[4][2] = { {120 , 64}, {144, 184}, {128, 328}, {120, 456} };
@@ -631,7 +631,7 @@ void MenuNemesis::onMouseUp(const Common::Point &Pos) {
void MenuNemesis::onMouseMove(const Common::Point &Pos) {
if (Pos.y < 40) {
- inmenu = true;
+ inMenu = true;
if (_engine->getScriptManager()->getStateValue(StateKey_MenuState) != 2)
_engine->getScriptManager()->setStateValue(StateKey_MenuState, 2);
@@ -681,7 +681,7 @@ void MenuNemesis::onMouseMove(const Common::Point &Pos) {
delay = 200;
}
} else {
- inmenu = false;
+ inMenu = false;
if (_engine->getScriptManager()->getStateValue(StateKey_MenuState) != 0)
_engine->getScriptManager()->setStateValue(StateKey_MenuState, 0);
mouseOnItem = -1;
@@ -689,7 +689,7 @@ void MenuNemesis::onMouseMove(const Common::Point &Pos) {
}
void MenuNemesis::process(uint32 deltatime) {
- if (inmenu) {
+ if (inMenu) {
if (!scrolled) {
float scrl = 32.0 * 2.0 * (deltatime / 1000.0);
@@ -715,7 +715,7 @@ void MenuNemesis::process(uint32 deltatime) {
}
if (redraw) {
- _engine->getRenderManager()->blitSurfaceToMenu(menubar, 64, scrollPos);
+ _engine->getRenderManager()->blitSurfaceToMenu(menuBar, 64, scrollPos);
if (menuBarFlag & kMenubarExit)
if (mouseOnItem == kMainMenuExit)
@@ -752,7 +752,7 @@ void MenuNemesis::process(uint32 deltatime) {
scrollPos = -32;
if (redraw) {
- _engine->getRenderManager()->blitSurfaceToMenu(menubar, 64, scrollPos);
+ _engine->getRenderManager()->blitSurfaceToMenu(menuBar, 64, scrollPos);
redraw = false;
}
}
diff --git a/engines/zvision/scripting/menu.h b/engines/zvision/scripting/menu.h
index a88587966f..f6b21b9c97 100644
--- a/engines/zvision/scripting/menu.h
+++ b/engines/zvision/scripting/menu.h
@@ -68,8 +68,8 @@ public:
void onMouseUp(const Common::Point &Pos);
void process(uint32 deltaTimeInMillis);
private:
- Graphics::Surface menuback[3][2];
- Graphics::Surface menubar[4][2];
+ Graphics::Surface menuBack[3][2];
+ Graphics::Surface menuBar[4][2];
Graphics::Surface *items[50][2];
uint itemId[50];
@@ -77,11 +77,11 @@ private:
uint magicId[12];
int menuMouseFocus;
- bool inmenu;
+ bool inMenu;
int mouseOnItem;
- bool scrolled[3];
+ bool scrolled[3];
int16 scrollPos[3];
bool clean;
@@ -98,13 +98,13 @@ public:
void process(uint32 deltaTimeInMillis);
private:
Graphics::Surface but[4][6];
- Graphics::Surface menubar;
+ Graphics::Surface menuBar;
- bool inmenu;
+ bool inMenu;
int mouseOnItem;
- bool scrolled;
+ bool scrolled;
int16 scrollPos;
bool redraw;
@@ -114,6 +114,6 @@ private:
};
-}
+} // End of namespace ZVision
#endif
diff --git a/engines/zvision/sound/zork_raw.cpp b/engines/zvision/sound/zork_raw.cpp
index 7bdd4875fc..124235e0e0 100644
--- a/engines/zvision/sound/zork_raw.cpp
+++ b/engines/zvision/sound/zork_raw.cpp
@@ -33,7 +33,6 @@
#include "zvision/sound/zork_raw.h"
#include "zvision/zvision.h"
-#include "zvision/detection.h"
namespace ZVision {
@@ -136,7 +135,8 @@ int RawChunkStream::readBuffer(int16 *buffer, Common::SeekableReadStream *stream
return bytesRead;
}
-const SoundParams RawZorkStream::_zNemSoundParamLookupTable[32] = {{'0', 0x1F40, false, false, false},
+const SoundParams RawZorkStream::_zNemSoundParamLookupTable[32] = {
+ {'0', 0x1F40, false, false, false},
{'1', 0x1F40, true, false, false},
{'2', 0x1F40, false, false, true},
{'3', 0x1F40, true, false, true},
@@ -170,7 +170,8 @@ const SoundParams RawZorkStream::_zNemSoundParamLookupTable[32] = {{'0', 0x1F40,
{'x', 0xAC44, true, true, true}
};
-const SoundParams RawZorkStream::_zgiSoundParamLookupTable[24] = {{'4', 0x2B11, false, false, false},
+const SoundParams RawZorkStream::_zgiSoundParamLookupTable[24] = {
+ {'4', 0x2B11, false, false, false},
{'5', 0x2B11, true, false, false},
{'6', 0x2B11, false, false, true},
{'7', 0x2B11, true, false, true},
diff --git a/engines/zvision/text/string_manager.h b/engines/zvision/text/string_manager.h
index f4564ee1ec..2c31cf7afe 100644
--- a/engines/zvision/text/string_manager.h
+++ b/engines/zvision/text/string_manager.h
@@ -23,7 +23,6 @@
#ifndef ZVISION_STRING_MANAGER_H
#define ZVISION_STRING_MANAGER_H
-#include "zvision/detection.h"
#include "zvision/text/truetype_font.h"
namespace Graphics {
diff --git a/engines/zvision/text/text.h b/engines/zvision/text/text.h
index d35b90499d..5dd872a440 100644
--- a/engines/zvision/text/text.h
+++ b/engines/zvision/text/text.h
@@ -24,7 +24,6 @@
#ifndef ZVISION_TEXT_H
#define ZVISION_TEXT_H
-#include "zvision/detection.h"
#include "zvision/text/truetype_font.h"
#include "zvision/zvision.h"
@@ -59,7 +58,7 @@ public:
public:
Common::String _fontname;
- TextJustification _justification; // 0 - center, 1-left, 2-right
+ TextJustification _justification;
int16 _size;
uint8 _red; // 0-255
uint8 _green; // 0-255
diff --git a/engines/zvision/zvision.cpp b/engines/zvision/zvision.cpp
index da80ff9d02..779fdc4464 100644
--- a/engines/zvision/zvision.cpp
+++ b/engines/zvision/zvision.cpp
@@ -29,7 +29,6 @@
#include "zvision/graphics/cursors/cursor_manager.h"
#include "zvision/file/save_manager.h"
#include "zvision/text/string_manager.h"
-#include "zvision/detection.h"
#include "zvision/scripting/menu.h"
#include "zvision/file/search_manager.h"
#include "zvision/text/text.h"
@@ -184,10 +183,10 @@ void ZVision::initialize() {
_searchManager->addDir("FONTS");
_searchManager->addDir("addon");
- if (_gameDescription->gameId == GID_GRANDINQUISITOR) {
+ if (getGameId() == GID_GRANDINQUISITOR) {
if (!_searchManager->loadZix("INQUIS.ZIX"))
error("Unable to load file INQUIS.ZIX");
- } else if (_gameDescription->gameId == GID_NEMESIS) {
+ } else if (getGameId() == GID_NEMESIS) {
if (!_searchManager->loadZix("NEMESIS.ZIX")) {
// The game might not be installed, try MEDIUM.ZIX instead
if (!_searchManager->loadZix("ZNEMSCR/MEDIUM.ZIX"))
@@ -209,7 +208,7 @@ void ZVision::initialize() {
_textRenderer = new TextRenderer(this);
_midiManager = new MidiManager();
- if (_gameDescription->gameId == GID_GRANDINQUISITOR)
+ if (getGameId() == GID_GRANDINQUISITOR)
_menu = new MenuZGI(this);
else
_menu = new MenuNemesis(this);
@@ -217,7 +216,7 @@ void ZVision::initialize() {
// Initialize the managers
_cursorManager->initialize();
_scriptManager->initialize();
- _stringManager->initialize(_gameDescription->gameId);
+ _stringManager->initialize(getGameId());
registerDefaultSettings();
@@ -396,8 +395,8 @@ void ZVision::fpsTimer() {
}
void ZVision::initScreen() {
- uint16 workingWindowWidth = (_gameDescription->gameId == GID_NEMESIS) ? ZNM_WORKING_WINDOW_WIDTH : ZGI_WORKING_WINDOW_WIDTH;
- uint16 workingWindowHeight = (_gameDescription->gameId == GID_NEMESIS) ? ZNM_WORKING_WINDOW_HEIGHT : ZGI_WORKING_WINDOW_HEIGHT;
+ uint16 workingWindowWidth = (getGameId() == GID_NEMESIS) ? ZNM_WORKING_WINDOW_WIDTH : ZGI_WORKING_WINDOW_WIDTH;
+ uint16 workingWindowHeight = (getGameId() == GID_NEMESIS) ? ZNM_WORKING_WINDOW_HEIGHT : ZGI_WORKING_WINDOW_HEIGHT;
_workingWindow = Common::Rect(
(WINDOW_WIDTH - workingWindowWidth) / 2,
(WINDOW_HEIGHT - workingWindowHeight) / 2,
diff --git a/engines/zvision/zvision.h b/engines/zvision/zvision.h
index 854cd77bb8..4c948faaa4 100644
--- a/engines/zvision/zvision.h
+++ b/engines/zvision/zvision.h
@@ -24,7 +24,6 @@
#ifndef ZVISION_ZVISION_H
#define ZVISION_ZVISION_H
-#include "zvision/detection.h"
#include "zvision/core/clock.h"
#include "zvision/file/search_manager.h"
@@ -51,7 +50,6 @@ class VideoDecoder;
* - Zork: Grand Inquisitor
*
*/
-
namespace ZVision {
struct ZVisionGameDescription;
@@ -74,12 +72,12 @@ enum {
HIRES_WINDOW_WIDTH = 800,
HIRES_WINDOW_HEIGHT = 600,
- // Zork nemesis working window sizes
- ZNM_WORKING_WINDOW_WIDTH = 512,
+ // Zork Nemesis working window sizes
+ ZNM_WORKING_WINDOW_WIDTH = 512,
ZNM_WORKING_WINDOW_HEIGHT = 320,
// ZGI working window sizes
- ZGI_WORKING_WINDOW_WIDTH = 640,
+ ZGI_WORKING_WINDOW_WIDTH = 640,
ZGI_WORKING_WINDOW_HEIGHT = 344,
ROTATION_SCREEN_EDGE_OFFSET = 60,
@@ -88,6 +86,12 @@ enum {
KEYBUF_SIZE = 20
};
+enum ZVisionGameId {
+ GID_NONE = 0,
+ GID_NEMESIS = 1,
+ GID_GRANDINQUISITOR = 2
+};
+
class ZVision : public Engine {
public:
ZVision(OSystem *syst, const ZVisionGameDescription *gameDesc);
@@ -116,12 +120,12 @@ private:
ScriptManager *_scriptManager;
RenderManager *_renderManager;
CursorManager *_cursorManager;
- SaveManager *_saveManager;
StringManager *_stringManager;
- MenuHandler *_menu;
SearchManager *_searchManager;
TextRenderer *_textRenderer;
MidiManager *_midiManager;
+ SaveManager *_saveManager;
+ MenuHandler *_menu;
// Clock
Clock _clock;
@@ -141,12 +145,15 @@ private:
bool _videoIsPlaying;
uint8 _cheatBuffer[KEYBUF_SIZE];
+
public:
- uint32 getFeatures() const;
- Common::Language getLanguage() const;
Common::Error run();
void pauseEngineIntern(bool pause);
+ ZVisionGameId getGameId() const;
+ Common::Language getLanguage() const;
+ uint32 getFeatures() const;
+
ScriptManager *getScriptManager() const {
return _scriptManager;
}
@@ -174,12 +181,10 @@ public:
MenuHandler *getMenuHandler() const {
return _menu;
}
+
Common::RandomSource *getRandomSource() const {
return _rnd;
}
- ZVisionGameId getGameId() const {
- return _gameDescription->gameId;
- }
int16 getKeyboardVelocity() const {
return _keyboardVelocity;
}
@@ -236,6 +241,7 @@ public:
bool canSaveGameStateCurrently();
Common::Error loadGameState(int slot);
Common::Error saveGameState(int slot, const Common::String &desc);
+
private:
void initialize();
void initFonts();
diff --git a/gui/credits.h b/gui/credits.h
index 12e75b01fc..7ae12bf599 100644
--- a/gui/credits.h
+++ b/gui/credits.h
@@ -322,7 +322,7 @@ static const char *credits[] = {
"C0""Einar Johan T. S\370m\345en",
"C0""Tobia Tesan",
"",
-"C1""ZVision",
+"C1""Z-Vision",
"C0""Adrian Astley",
"C0""Filippos Karapetis",
"C0""Anton Yarcev",
@@ -582,7 +582,6 @@ static const char *credits[] = {
"C1""German",
"C0""Simon Sawatzki",
"C0""Lothar Serra Mari",
-"C2""(retired)",
"",
"C1""Hungarian",
"C0""Alex Bevilacqua",
@@ -846,7 +845,7 @@ static const char *credits[] = {
"C0""James Woodcock",
"C2""Soundtrack enhancements",
"C0""Anton Yartsev",
-"C2""For the original re-implementation of the ZVision engine",
+"C2""For the original re-implementation of the Z-Vision engine",
"C0""Tony Warriner and everyone at Revolution Software Ltd. for sharing with us the source of some of their brilliant games, allowing us to release Beneath a Steel Sky as freeware... and generally being supportive above and beyond the call of duty.",
"C0""",
"C0""John Passfield and Steve Stamatiadis for sharing the source of their classic title, Flight of the Amazon Queen and also being incredibly supportive.",
diff --git a/gui/debugger.cpp b/gui/debugger.cpp
index 466681e89d..c9b435963d 100644
--- a/gui/debugger.cpp
+++ b/gui/debugger.cpp
@@ -87,6 +87,19 @@ Debugger::~Debugger() {
// Initialisation Functions
+int Debugger::getCharsPerLine() {
+#ifndef USE_TEXT_CONSOLE_FOR_DEBUGGER
+ const int charsPerLine = _debuggerDialog->getCharsPerLine();
+#elif defined(USE_READLINE)
+ int charsPerLine, rows;
+ rl_get_screen_size(&rows, &charsPerLine);
+#else
+ // Can we do better?
+ const int charsPerLine = 80;
+#endif
+ return charsPerLine;
+}
+
int Debugger::debugPrintf(const char *format, ...) {
va_list argptr;
@@ -101,6 +114,37 @@ int Debugger::debugPrintf(const char *format, ...) {
return count;
}
+void Debugger::debugPrintColumns(const Common::StringArray &list) {
+ uint maxLength = 0;
+ uint i, j;
+
+ for (i = 0; i < list.size(); i++) {
+ if (list[i].size() > maxLength)
+ maxLength = list[i].size();
+ }
+
+ uint charsPerLine = getCharsPerLine();
+ uint columnWidth = maxLength + 2;
+ uint columns = charsPerLine / columnWidth;
+
+ uint lines = list.size() / columns;
+
+ if (list.size() % columns)
+ lines++;
+
+ // This won't always use all available columns, but even if it did the
+ // number of lines should be the same so that's good enough.
+ for (i = 0; i < lines; i++) {
+ for (j = 0; j < columns; j++) {
+ uint pos = i + j * lines;
+ if (pos < list.size()) {
+ debugPrintf("%*s", -columnWidth, list[pos].c_str());
+ }
+ }
+ debugPrintf("\n");
+ }
+}
+
void Debugger::preEnter() {
g_engine->pauseEngine(true);
}
@@ -447,15 +491,7 @@ bool Debugger::cmdExit(int argc, const char **argv) {
// Print a list of all registered commands (and variables, if any),
// nicely word-wrapped.
bool Debugger::cmdHelp(int argc, const char **argv) {
-#ifndef USE_TEXT_CONSOLE_FOR_DEBUGGER
- const int charsPerLine = _debuggerDialog->getCharsPerLine();
-#elif defined(USE_READLINE)
- int charsPerLine, rows;
- rl_get_screen_size(&rows, &charsPerLine);
-#else
- // Can we do better?
- const int charsPerLine = 80;
-#endif
+ const int charsPerLine = getCharsPerLine();
int width, size;
uint i;
diff --git a/gui/debugger.h b/gui/debugger.h
index ef6f900974..bc9306c1de 100644
--- a/gui/debugger.h
+++ b/gui/debugger.h
@@ -28,6 +28,7 @@
#include "common/hashmap.h"
#include "common/hash-str.h"
#include "common/array.h"
+#include "common/str-array.h"
namespace GUI {
@@ -40,8 +41,12 @@ public:
Debugger();
virtual ~Debugger();
+ int getCharsPerLine();
+
int debugPrintf(const char *format, ...) GCC_PRINTF(2, 3);
+ void debugPrintColumns(const Common::StringArray &list);
+
/**
* The onFrame() method should be invoked by the engine at regular
* intervals (usually once per main loop iteration) whenever the
diff --git a/gui/launcher.cpp b/gui/launcher.cpp
index 4496c11a3d..5abf0aba26 100644
--- a/gui/launcher.cpp
+++ b/gui/launcher.cpp
@@ -1156,9 +1156,9 @@ void LauncherDialog::updateButtons() {
_loadButton->setEnabled(en);
_loadButton->draw();
}
- switchButtonsText(_addButton, "~A~dd Game...", "Mass Add...");
+ switchButtonsText(_addButton, "~A~dd Game...", _s("Mass Add..."));
#ifdef ENABLE_EVENTRECORDER
- switchButtonsText(_loadButton, "~L~oad...", "Record...");
+ switchButtonsText(_loadButton, "~L~oad...", _s("Record..."));
#endif
}
diff --git a/gui/options.cpp b/gui/options.cpp
index 726b89d437..ba247e5f15 100644
--- a/gui/options.cpp
+++ b/gui/options.cpp
@@ -445,11 +445,9 @@ void OptionsDialog::close() {
if (_oplPopUp) {
if (_enableAudioSettings) {
- const OPL::Config::EmulatorDescription *ed = OPL::Config::getAvailable();
- while (ed->name && ed->id != (int)_oplPopUp->getSelectedTag())
- ++ed;
+ const OPL::Config::EmulatorDescription *ed = OPL::Config::findDriver(_oplPopUp->getSelectedTag());
- if (ed->name)
+ if (ed)
ConfMan.set("opl_driver", ed->name, _domain);
else
ConfMan.removeKey("opl_driver", _domain);
diff --git a/gui/themes/translations.dat b/gui/themes/translations.dat
index bfa33d4feb..4f83477c13 100644
--- a/gui/themes/translations.dat
+++ b/gui/themes/translations.dat
Binary files differ
diff --git a/image/codecs/cinepak.cpp b/image/codecs/cinepak.cpp
index 32f6be2cd5..4e858921ee 100644
--- a/image/codecs/cinepak.cpp
+++ b/image/codecs/cinepak.cpp
@@ -433,9 +433,11 @@ const Graphics::Surface *CinepakDecoder::decodeFrame(Common::SeekableReadStream
for (uint16 j = 0; j < 256; j++) {
_curFrame.strips[i].v1_codebook[j] = _curFrame.strips[i - 1].v1_codebook[j];
_curFrame.strips[i].v4_codebook[j] = _curFrame.strips[i - 1].v4_codebook[j];
- memcpy(_curFrame.strips[i].v1_dither, _curFrame.strips[i - 1].v1_dither, 256 * 4 * 4 * 4);
- memcpy(_curFrame.strips[i].v4_dither, _curFrame.strips[i - 1].v4_dither, 256 * 4 * 4 * 4);
}
+
+ // Copy the QuickTime dither tables
+ memcpy(_curFrame.strips[i].v1_dither, _curFrame.strips[i - 1].v1_dither, 256 * 4 * 4 * 4);
+ memcpy(_curFrame.strips[i].v4_dither, _curFrame.strips[i - 1].v4_dither, 256 * 4 * 4 * 4);
}
_curFrame.strips[i].id = stream.readUint16BE();
diff --git a/image/codecs/cinepak.h b/image/codecs/cinepak.h
index dc8172ea0f..4efb1191cc 100644
--- a/image/codecs/cinepak.h
+++ b/image/codecs/cinepak.h
@@ -64,6 +64,9 @@ struct CinepakFrame {
* Cinepak decoder.
*
* Used by BMP/AVI and PICT/QuickTime.
+ *
+ * Used in engines:
+ * - sherlock
*/
class CinepakDecoder : public Codec {
public:
@@ -88,7 +91,6 @@ private:
byte *_ditherPalette;
bool _dirtyPalette;
- byte *_rgbLookup;
byte *_colorMap;
DitherType _ditherType;
diff --git a/po/POTFILES b/po/POTFILES
index a33c8e3a83..6a865060fc 100644
--- a/po/POTFILES
+++ b/po/POTFILES
@@ -10,6 +10,7 @@ gui/KeysDialog.cpp
gui/launcher.cpp
gui/massadd.cpp
gui/options.cpp
+gui/recorderdialog.cpp
gui/saveload-dialog.cpp
gui/themebrowser.cpp
gui/ThemeEngine.cpp
diff --git a/po/be_BY.po b/po/be_BY.po
index 1403a8a052..37090afb42 100644
--- a/po/be_BY.po
+++ b/po/be_BY.po
@@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: ScummVM 1.7.0git\n"
"Report-Msgid-Bugs-To: scummvm-devel@lists.sf.net\n"
-"POT-Creation-Date: 2014-10-04 00:58+0100\n"
+"POT-Creation-Date: 2015-06-30 20:57+0100\n"
"PO-Revision-Date: 2014-07-02 17:22+0300\n"
"Last-Translator: Ivan Lukyanov <greencis@mail.ru>\n"
"Language-Team: Ivan Lukyanov <greencis@mail.ru>\n"
@@ -55,10 +55,11 @@ msgstr "Уверх"
#: gui/browser.cpp:75 gui/chooser.cpp:46 gui/KeysDialog.cpp:43
#: gui/launcher.cpp:351 gui/massadd.cpp:95 gui/options.cpp:1239
+#: gui/recorderdialog.cpp:70 gui/recorderdialog.cpp:156
#: gui/saveload-dialog.cpp:216 gui/saveload-dialog.cpp:276
-#: gui/saveload-dialog.cpp:547 gui/saveload-dialog.cpp:922
+#: gui/saveload-dialog.cpp:547 gui/saveload-dialog.cpp:931
#: gui/themebrowser.cpp:55 gui/fluidsynth-dialog.cpp:152
-#: engines/engine.cpp:452 backends/platform/wii/options.cpp:48
+#: engines/engine.cpp:483 backends/platform/wii/options.cpp:48
#: backends/events/default/default-events.cpp:196
#: backends/events/default/default-events.cpp:218
#: engines/drascula/saveload.cpp:49 engines/parallaction/saveload.cpp:274
@@ -71,9 +72,9 @@ msgid "Choose"
msgstr "Абраць"
#: gui/gui-manager.cpp:117 backends/keymapper/remap-dialog.cpp:53
-#: 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
+#: 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 "Закрыць"
@@ -89,7 +90,7 @@ msgstr "Паказаць клавіятуру"
msgid "Remap keys"
msgstr "Перапрызначыць клавішы"
-#: gui/gui-manager.cpp:131 base/main.cpp:326 engines/scumm/help.cpp:86
+#: gui/gui-manager.cpp:131 base/main.cpp:326 engines/scumm/help.cpp:87
msgid "Toggle fullscreen"
msgstr "Пераключэнне на ўвесь экран"
@@ -103,13 +104,13 @@ msgstr "Прызначыць"
#: gui/KeysDialog.cpp:42 gui/launcher.cpp:352 gui/launcher.cpp:1048
#: gui/launcher.cpp:1052 gui/massadd.cpp:92 gui/options.cpp:1240
-#: gui/saveload-dialog.cpp:923 gui/fluidsynth-dialog.cpp:153
-#: engines/engine.cpp:371 engines/engine.cpp:382
+#: 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:399 engines/parallaction/saveload.cpp:274
-#: engines/scumm/dialogs.cpp:193 engines/scumm/scumm.cpp:1825
+#: 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
@@ -479,7 +480,7 @@ msgstr ""
#: gui/launcher.cpp:793 gui/launcher.cpp:941 gui/launcher.cpp:1000
#: gui/fluidsynth-dialog.cpp:217
-#: backends/events/symbiansdl/symbiansdl-events.cpp:184
+#: 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
@@ -489,7 +490,7 @@ msgstr "Так"
#: gui/launcher.cpp:793 gui/launcher.cpp:941 gui/launcher.cpp:1000
#: gui/fluidsynth-dialog.cpp:217
-#: backends/events/symbiansdl/symbiansdl-events.cpp:184
+#: 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
@@ -525,6 +526,14 @@ msgstr "Гэтая гульня не падтрымлівае загрузку захаванняў праз галоўнае меню."
msgid "ScummVM could not find any engine capable of running the selected game!"
msgstr "ScummVM не змог знайсці рухавічок для запуску абранай гульні!"
+#: gui/launcher.cpp:1159
+msgid "Mass Add..."
+msgstr "Шмат гульняў..."
+
+#: gui/launcher.cpp:1161
+msgid "Record..."
+msgstr ""
+
#: gui/massadd.cpp:79 gui/massadd.cpp:82
msgid "... progress ..."
msgstr "... шукаю ..."
@@ -623,7 +632,7 @@ msgid "Special dithering modes supported by some games"
msgstr "Спецыяльныя рэжымы рэндэрынгу, падтрымоўваныя некаторымі гульнямі"
#: gui/options.cpp:760
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2249
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2298
msgid "Fullscreen mode"
msgstr "Поўнаэкранны рэжым"
@@ -943,6 +952,43 @@ msgstr ""
"Тэма, абраная вамі, не падтрымлівае бягучую мову. Калі вы жадаеце "
"выкарыстоўваць гэтую тэму, вам неабходна спачатку пераключыцца на іншую мову."
+#: gui/recorderdialog.cpp:64
+msgid "Recorder or Playback Gameplay"
+msgstr ""
+
+#: gui/recorderdialog.cpp:69 gui/recorderdialog.cpp:156
+#: gui/saveload-dialog.cpp:220 gui/saveload-dialog.cpp:276
+msgid "Delete"
+msgstr "Выдаліць"
+
+#: gui/recorderdialog.cpp:71
+msgid "Record"
+msgstr ""
+
+#: gui/recorderdialog.cpp:72
+#, fuzzy
+msgid "Playback"
+msgstr "Гуляць"
+
+#: gui/recorderdialog.cpp:74
+msgid "Edit"
+msgstr ""
+
+#: gui/recorderdialog.cpp:86 gui/recorderdialog.cpp:243
+#: gui/recorderdialog.cpp:253
+msgid "Author: "
+msgstr ""
+
+#: gui/recorderdialog.cpp:87 gui/recorderdialog.cpp:244
+#: gui/recorderdialog.cpp:254
+msgid "Notes: "
+msgstr ""
+
+#: gui/recorderdialog.cpp:155
+#, fuzzy
+msgid "Do you really want to delete this record?"
+msgstr "Вы сапраўды жадаеце выдаліць гэта захаванне?"
+
#: gui/saveload-dialog.cpp:167
msgid "List view"
msgstr "Выгляд спісу"
@@ -963,23 +1009,19 @@ msgstr "Час не запісаны"
msgid "No playtime saved"
msgstr "Час гульні не запісаны"
-#: gui/saveload-dialog.cpp:220 gui/saveload-dialog.cpp:276
-msgid "Delete"
-msgstr "Выдаліць"
-
#: gui/saveload-dialog.cpp:275
msgid "Do you really want to delete this saved game?"
msgstr "Вы сапраўды жадаеце выдаліць гэта захаванне?"
-#: gui/saveload-dialog.cpp:385 gui/saveload-dialog.cpp:875
+#: gui/saveload-dialog.cpp:385 gui/saveload-dialog.cpp:884
msgid "Date: "
msgstr "Дата: "
-#: gui/saveload-dialog.cpp:389 gui/saveload-dialog.cpp:881
+#: gui/saveload-dialog.cpp:389 gui/saveload-dialog.cpp:890
msgid "Time: "
msgstr "Час: "
-#: gui/saveload-dialog.cpp:395 gui/saveload-dialog.cpp:889
+#: gui/saveload-dialog.cpp:395 gui/saveload-dialog.cpp:898
msgid "Playtime: "
msgstr "Час гульні: "
@@ -995,19 +1037,19 @@ msgstr "Наступны"
msgid "Prev"
msgstr "Папярэдні"
-#: gui/saveload-dialog.cpp:739
+#: gui/saveload-dialog.cpp:748
msgid "New Save"
msgstr "Новае захаванне"
-#: gui/saveload-dialog.cpp:739
+#: gui/saveload-dialog.cpp:748
msgid "Create a new save game"
msgstr "Стварыць новы запіс гульні"
-#: gui/saveload-dialog.cpp:868
+#: gui/saveload-dialog.cpp:877
msgid "Name: "
msgstr "Назва: "
-#: gui/saveload-dialog.cpp:940
+#: gui/saveload-dialog.cpp:949
#, c-format
msgid "Enter a description for slot %d:"
msgstr "Увядзіце апісанне слота %d:"
@@ -1158,7 +1200,7 @@ msgstr "Прапусціць радок"
msgid "Error running game:"
msgstr "Памылка запуску гульні:"
-#: base/main.cpp:536
+#: base/main.cpp:554
msgid "Could not find any engine capable of running the selected game"
msgstr "Не магу знайсці рухавічок для запуску абранай гульні"
@@ -1276,7 +1318,7 @@ 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:758
+#: engines/pegasus/pegasus.cpp:377 engines/sci/engine/kfile.cpp:759
#: engines/toltecs/menu.cpp:281 engines/tsage/scenes.cpp:598
msgid "Save game:"
msgstr "Захаваць гульню:"
@@ -1289,7 +1331,7 @@ msgstr "Захаваць гульню:"
#: 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:758 engines/scumm/dialogs.cpp:188
+#: engines/sci/engine/kfile.cpp:759 engines/scumm/dialogs.cpp:188
#: engines/toltecs/menu.cpp:281 engines/tsage/scenes.cpp:598
msgid "Save"
msgstr "Захаваць"
@@ -1328,23 +1370,23 @@ msgstr "~А~дмена"
msgid "~K~eys"
msgstr "~К~лавішы"
-#: engines/engine.cpp:245
+#: engines/engine.cpp:276
msgid "Could not initialize color format."
msgstr "Не магу ініцыялізаваць фармат колеру."
-#: engines/engine.cpp:253
+#: engines/engine.cpp:284
msgid "Could not switch to video mode: '"
msgstr "Не атрымалася пераключыць відэарэжым: '"
-#: engines/engine.cpp:262
+#: engines/engine.cpp:293
msgid "Could not apply aspect ratio setting."
msgstr "Не атрымалася выкарыстаць карэкцыю суадносін бакоў."
-#: engines/engine.cpp:267
+#: engines/engine.cpp:298
msgid "Could not apply fullscreen setting."
msgstr "Не магу ўжыць поўнаэкранны рэжым."
-#: engines/engine.cpp:367
+#: engines/engine.cpp:398
msgid ""
"You appear to be playing this game directly\n"
"from the CD. This is known to cause problems,\n"
@@ -1358,7 +1400,7 @@ msgstr ""
"на жорсткі дыск. Падрабязнасці можна знайсці ў\n"
"файле README."
-#: engines/engine.cpp:378
+#: engines/engine.cpp:409
msgid ""
"This game has audio tracks in its disk. These\n"
"tracks need to be ripped from the disk using\n"
@@ -1373,7 +1415,7 @@ msgstr ""
"з'явіцца музыка. Падрабязнасці можна знайсці ў\n"
"файле README."
-#: engines/engine.cpp:436
+#: engines/engine.cpp:467
#, c-format
msgid ""
"Gamestate load failed (%s)! Please consult the README for basic information, "
@@ -1383,7 +1425,7 @@ msgstr ""
"README за базавай інфармацыяй, а таксама інструкцыямі пра тое, як атрымаць "
"далейшую дапамогу."
-#: engines/engine.cpp:449
+#: engines/engine.cpp:480
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 "
@@ -1393,7 +1435,7 @@ msgstr ""
"ScummVM цалкам. Яна, хутчэй за ўсё, не будзе працаваць стабільна, і "
"захаванні гульняў могуць не працаваць у будучых версіях ScummVM."
-#: engines/engine.cpp:452
+#: engines/engine.cpp:483
msgid "Start anyway"
msgstr "Усё адно запусціць"
@@ -1603,11 +1645,11 @@ msgstr "Рэжым тачпада ўключаны."
msgid "Touchpad mode disabled."
msgstr "Рэжым тачпада выключаны."
-#: backends/platform/maemo/maemo.cpp:209
+#: backends/platform/maemo/maemo.cpp:208
msgid "Click Mode"
msgstr "Рэжым пстрычкі"
-#: backends/platform/maemo/maemo.cpp:215
+#: backends/platform/maemo/maemo.cpp:214
#: backends/platform/symbian/src/SymbianActions.cpp:42
#: backends/platform/wince/CEActionsPocket.cpp:60
#: backends/platform/wince/CEActionsSmartphone.cpp:43
@@ -1615,11 +1657,11 @@ msgstr "Рэжым пстрычкі"
msgid "Left Click"
msgstr "Левая пстрычка"
-#: backends/platform/maemo/maemo.cpp:218
+#: backends/platform/maemo/maemo.cpp:217
msgid "Middle Click"
msgstr "Сярэдняя пстрычка"
-#: backends/platform/maemo/maemo.cpp:221
+#: 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
@@ -1656,19 +1698,19 @@ msgctxt "lowres"
msgid "Normal (no scaling)"
msgstr "Без павелічэння"
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2148
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2197
msgid "Enabled aspect ratio correction"
msgstr "Карэкцыя суадносін бакоў уключана"
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2154
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2203
msgid "Disabled aspect ratio correction"
msgstr "Карэкцыя суадносін бакоў выключана"
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2209
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2258
msgid "Active graphics filter:"
msgstr "Актыўны графічны фільтр:"
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2251
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2300
msgid "Windowed mode"
msgstr "Аконны рэжым"
@@ -1727,8 +1769,8 @@ msgstr "Хуткі рэжым"
#: 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:82
-#: engines/scumm/help.cpp:84
+#: engines/scumm/dialogs.cpp:192 engines/scumm/help.cpp:83
+#: engines/scumm/help.cpp:85
msgid "Quit"
msgstr "Выхад"
@@ -1748,7 +1790,7 @@ msgstr "Віртуальная клавіятура"
msgid "Key mapper"
msgstr "Прызначэнне клавіш"
-#: backends/events/symbiansdl/symbiansdl-events.cpp:184
+#: backends/events/symbiansdl/symbiansdl-events.cpp:186
msgid "Do you want to quit ?"
msgstr "Вы сапраўды жадаеце выйсці?"
@@ -2083,35 +2125,56 @@ msgstr "Пстрычкі ўключаны"
msgid "Clicking Disabled"
msgstr "Пстрычкі выключаны"
-#: engines/agi/detection.cpp:142 engines/drascula/detection.cpp:302
+#: 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.cpp:103
+#: engines/zvision/detection.cpp:246
msgid "Use original save/load screens"
msgstr "Выкарыстоўваць арыгінальныя экраны запісу/чытанні гульні"
-#: engines/agi/detection.cpp:143 engines/drascula/detection.cpp:303
+#: 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/zvision/detection.cpp:104
+#: engines/zvision/detection.cpp:247
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 версіі гульні)"
+
+#: engines/agi/detection.cpp:158
+msgid ""
+"Use an alternative palette, common for all Amiga games. This was the old "
+"behavior"
+msgstr ""
+
+#: engines/agi/detection.cpp:167
+#, fuzzy
+msgid "Mouse support"
+msgstr "Падтрымка пропускаў"
+
+#: 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:857 engines/toltecs/menu.cpp:256
+#: engines/sci/engine/kfile.cpp:858 engines/toltecs/menu.cpp:256
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:857 engines/toltecs/menu.cpp:256
+#: engines/sci/engine/kfile.cpp:858 engines/toltecs/menu.cpp:256
msgid "Restore"
msgstr "Узнавіць"
-#: engines/agos/saveload.cpp:160 engines/scumm/scumm.cpp:2368
+#: engines/agos/saveload.cpp:160 engines/scumm/scumm.cpp:2377
#, c-format
msgid ""
"Failed to load game state from file:\n"
@@ -2122,7 +2185,7 @@ msgstr ""
"\n"
"%s"
-#: engines/agos/saveload.cpp:195 engines/scumm/scumm.cpp:2361
+#: engines/agos/saveload.cpp:195 engines/scumm/scumm.cpp:2370
#, c-format
msgid ""
"Failed to save game state to file:\n"
@@ -2133,7 +2196,7 @@ msgstr ""
"\n"
"%s"
-#: engines/agos/saveload.cpp:203 engines/scumm/scumm.cpp:2379
+#: engines/agos/saveload.cpp:203 engines/scumm/scumm.cpp:2388
#, c-format
msgid ""
"Successfully saved game state in file:\n"
@@ -2149,12 +2212,12 @@ msgstr ""
msgid "Cutscene file '%s' not found!"
msgstr "Файл застаўкі '%s' не знойдзены!"
-#: engines/cge/detection.cpp:105 engines/cge2/detection.cpp:81
+#: engines/cge/detection.cpp:105 engines/cge2/detection.cpp:101
#, fuzzy
msgid "Color Blind Mode"
msgstr "Рэжым пстрычкі"
-#: engines/cge/detection.cpp:106 engines/cge2/detection.cpp:82
+#: engines/cge/detection.cpp:106 engines/cge2/detection.cpp:102
msgid "Enable Color Blind Mode by default"
msgstr ""
@@ -2205,7 +2268,7 @@ msgstr "Хуткі рэжым відэа"
msgid "Play movies at an increased speed"
msgstr "Прайгравае відэа на павялічанай хуткасці"
-#: engines/groovie/script.cpp:399
+#: engines/groovie/script.cpp:408
msgid "Failed to save game"
msgstr "Не атрымалася захаваць гульню"
@@ -2503,12 +2566,12 @@ msgid "Use an alternative game intro (CD version only)"
msgstr "Выкарыстоўваць альтэрнатыўны ўступ (толькі для CD версіі гульні)"
#: engines/sci/detection.cpp:374
-msgid "EGA undithering"
-msgstr "EGA без растру"
+msgid "Skip EGA dithering pass (full color backgrounds)"
+msgstr ""
#: engines/sci/detection.cpp:375
-msgid "Enable undithering in EGA games"
-msgstr "Уключае рэжым без растравання ў EGA гульнях"
+msgid "Skip dithering pass in EGA games, graphics are shown with full colors"
+msgstr ""
#: engines/sci/detection.cpp:384
msgid "Prefer digital sound effects"
@@ -2584,12 +2647,14 @@ msgstr "Гульня спынена. Націсніце прабел, каб працягнуць."
#. "Moechten Sie wirklich neu starten? (J/N)J"
#. Will react to J as 'Yes'
#: engines/scumm/dialogs.cpp:183
-msgid "Are you sure you want to restart? (Y/N)"
+#, fuzzy
+msgid "Are you sure you want to restart? (Y/N)Y"
msgstr "Вы ўпэўнены, што жадаеце пачаць ізноў? (Y/N)"
#. I18N: you may specify 'Yes' symbol at the end of the line. See previous comment
#: engines/scumm/dialogs.cpp:185
-msgid "Are you sure you want to quit? (Y/N)"
+#, fuzzy
+msgid "Are you sure you want to quit? (Y/N)Y"
msgstr "Вы ўпэўнены, што жадаеце выйсці? (Y/N)"
#: engines/scumm/dialogs.cpp:190
@@ -2677,516 +2742,541 @@ msgstr "Практыкант"
msgid "Expert"
msgstr "Эксперт"
-#: engines/scumm/help.cpp:73
+#: engines/scumm/help.cpp:74
msgid "Common keyboard commands:"
msgstr "Агульныя клавіятурныя каманды:"
-#: engines/scumm/help.cpp:74
+#: engines/scumm/help.cpp:75
msgid "Save / Load dialog"
msgstr "Дыялог запісу / чытання"
-#: engines/scumm/help.cpp:76
+#: engines/scumm/help.cpp:77
msgid "Skip line of text"
msgstr "Прапусціць радок"
-#: engines/scumm/help.cpp:77
+#: engines/scumm/help.cpp:78
msgid "Esc"
msgstr "Esc"
-#: engines/scumm/help.cpp:77
+#: engines/scumm/help.cpp:78
msgid "Skip cutscene"
msgstr "Прапусціць застаўку"
-#: engines/scumm/help.cpp:78
+#: engines/scumm/help.cpp:79
msgid "Space"
msgstr "Прабел"
-#: engines/scumm/help.cpp:78
+#: engines/scumm/help.cpp:79
msgid "Pause game"
msgstr "Паўза гульні"
-#: engines/scumm/help.cpp:79 engines/scumm/help.cpp:84
-#: engines/scumm/help.cpp:95 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: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:79
+#: engines/scumm/help.cpp:80
msgid "Load game state 1-10"
msgstr "Загрузіць гульню 1-10"
-#: engines/scumm/help.cpp:80 engines/scumm/help.cpp:84
-#: engines/scumm/help.cpp:86 engines/scumm/help.cpp:100
-#: engines/scumm/help.cpp:101 engines/scumm/help.cpp:102
+#: 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:80
+#: engines/scumm/help.cpp:81
msgid "Save game state 1-10"
msgstr "Захаваць гульню 1-10"
-#: engines/scumm/help.cpp:86 engines/scumm/help.cpp:89
+#: engines/scumm/help.cpp:87 engines/scumm/help.cpp:90
msgid "Enter"
msgstr "Увод"
-#: engines/scumm/help.cpp:87
+#: engines/scumm/help.cpp:88
msgid "Music volume up / down"
msgstr "Гучнасць музыкі павялічыць / паменшыць"
-#: engines/scumm/help.cpp:88
+#: engines/scumm/help.cpp:89
msgid "Text speed slower / faster"
msgstr "Хуткасць тэксту хутчэй / павольней"
-#: engines/scumm/help.cpp:89
+#: engines/scumm/help.cpp:90
msgid "Simulate left mouse button"
msgstr "Эмуляцыя левай клавішы мышы"
-#: engines/scumm/help.cpp:90
+#: engines/scumm/help.cpp:91
msgid "Tab"
msgstr "Tab"
-#: engines/scumm/help.cpp:90
+#: engines/scumm/help.cpp:91
msgid "Simulate right mouse button"
msgstr "Эмуляцыя правай клавішы мышы"
-#: engines/scumm/help.cpp:93
+#: engines/scumm/help.cpp:94
msgid "Special keyboard commands:"
msgstr "Спецыяльныя клавіятурныя каманды:"
-#: engines/scumm/help.cpp:94
+#: engines/scumm/help.cpp:95
msgid "Show / Hide console"
msgstr "Паказаць / Прыбраць кансоль"
-#: engines/scumm/help.cpp:95
+#: engines/scumm/help.cpp:96
msgid "Start the debugger"
msgstr "Запуск адладчыка"
-#: engines/scumm/help.cpp:96
+#: engines/scumm/help.cpp:97
msgid "Show memory consumption"
msgstr "Паказаць спажыванне памяці"
-#: engines/scumm/help.cpp:97
+#: engines/scumm/help.cpp:98
msgid "Run in fast mode (*)"
msgstr "Запусціць хуткі рэжым (*)"
-#: engines/scumm/help.cpp:98
+#: engines/scumm/help.cpp:99
msgid "Run in really fast mode (*)"
msgstr "Запусціць вельмі хуткі рэжым (*)"
-#: engines/scumm/help.cpp:99
+#: engines/scumm/help.cpp:100
msgid "Toggle mouse capture"
msgstr "Пераключэнне перахопу мышы"
-#: engines/scumm/help.cpp:100
+#: engines/scumm/help.cpp:101
msgid "Switch between graphics filters"
msgstr "Пераключэнне паміж графічнымі фільтрамі"
-#: engines/scumm/help.cpp:101
+#: engines/scumm/help.cpp:102
msgid "Increase / Decrease scale factor"
msgstr "Павялічыць/паменшыць маштаб"
-#: engines/scumm/help.cpp:102
+#: engines/scumm/help.cpp:103
msgid "Toggle aspect-ratio correction"
msgstr "Пераключэнне карэкцыі суадносін бакоў"
-#: engines/scumm/help.cpp:107
+#: engines/scumm/help.cpp:108
msgid "* Note that using ctrl-f and"
msgstr "* Выкарыстанне Ctrl-F і"
-#: engines/scumm/help.cpp:108
+#: engines/scumm/help.cpp:109
msgid " ctrl-g are not recommended"
msgstr " Ctrl-G не рэкамендуецца,"
-#: engines/scumm/help.cpp:109
+#: engines/scumm/help.cpp:110
msgid " since they may cause crashes"
msgstr " бо яны могуць прывесці да"
-#: engines/scumm/help.cpp:110
+#: engines/scumm/help.cpp:111
msgid " or incorrect game behavior."
msgstr " няслушнай работы гульні."
-#: engines/scumm/help.cpp:114
+#: engines/scumm/help.cpp:115
msgid "Spinning drafts on the keyboard:"
msgstr "Змяняныя чарнавікі на клавіятуры:"
-#: engines/scumm/help.cpp:116
+#: engines/scumm/help.cpp:117
msgid "Main game controls:"
msgstr "Асноўнае кіраванне гульнёй:"
-#: engines/scumm/help.cpp:121 engines/scumm/help.cpp:136
-#: engines/scumm/help.cpp:161
+#: engines/scumm/help.cpp:122 engines/scumm/help.cpp:137
+#: engines/scumm/help.cpp:162
msgid "Push"
msgstr "Пхаць"
-#: engines/scumm/help.cpp:122 engines/scumm/help.cpp:137
-#: engines/scumm/help.cpp:162
+#: engines/scumm/help.cpp:123 engines/scumm/help.cpp:138
+#: engines/scumm/help.cpp:163
msgid "Pull"
msgstr "Цягнуць"
-#: engines/scumm/help.cpp:123 engines/scumm/help.cpp:138
-#: engines/scumm/help.cpp:163 engines/scumm/help.cpp:197
-#: engines/scumm/help.cpp:207
+#: 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 "Даць"
-#: engines/scumm/help.cpp:124 engines/scumm/help.cpp:139
-#: engines/scumm/help.cpp:164 engines/scumm/help.cpp:190
-#: engines/scumm/help.cpp:208
+#: 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 "Адчыніць"
-#: engines/scumm/help.cpp:126
+#: engines/scumm/help.cpp:127
msgid "Go to"
msgstr "Ісці"
-#: engines/scumm/help.cpp:127
+#: engines/scumm/help.cpp:128
msgid "Get"
msgstr "Узяць"
-#: engines/scumm/help.cpp:128 engines/scumm/help.cpp:152
-#: engines/scumm/help.cpp:170 engines/scumm/help.cpp:198
-#: engines/scumm/help.cpp:213 engines/scumm/help.cpp:224
-#: engines/scumm/help.cpp:250
+#: 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 "Выкарыстаць"
-#: engines/scumm/help.cpp:129 engines/scumm/help.cpp:141
+#: engines/scumm/help.cpp:130 engines/scumm/help.cpp:142
msgid "Read"
msgstr "Чытаць"
-#: engines/scumm/help.cpp:130 engines/scumm/help.cpp:147
+#: engines/scumm/help.cpp:131 engines/scumm/help.cpp:148
msgid "New kid"
msgstr "Новы перс"
-#: engines/scumm/help.cpp:131 engines/scumm/help.cpp:153
-#: engines/scumm/help.cpp:171
+#: engines/scumm/help.cpp:132 engines/scumm/help.cpp:154
+#: engines/scumm/help.cpp:172
msgid "Turn on"
msgstr "Уключыць"
-#: engines/scumm/help.cpp:132 engines/scumm/help.cpp:154
-#: engines/scumm/help.cpp:172
+#: engines/scumm/help.cpp:133 engines/scumm/help.cpp:155
+#: engines/scumm/help.cpp:173
msgid "Turn off"
msgstr "Выключыць"
-#: engines/scumm/help.cpp:142 engines/scumm/help.cpp:167
-#: engines/scumm/help.cpp:194
+#: engines/scumm/help.cpp:143 engines/scumm/help.cpp:168
+#: engines/scumm/help.cpp:195
msgid "Walk to"
msgstr "Ісці да"
-#: engines/scumm/help.cpp:143 engines/scumm/help.cpp:168
-#: engines/scumm/help.cpp:195 engines/scumm/help.cpp:210
-#: engines/scumm/help.cpp:227
+#: 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 "Падняць"
-#: engines/scumm/help.cpp:144 engines/scumm/help.cpp:169
+#: engines/scumm/help.cpp:145 engines/scumm/help.cpp:170
msgid "What is"
msgstr "Што такое"
-#: engines/scumm/help.cpp:146
+#: engines/scumm/help.cpp:147
msgid "Unlock"
msgstr "Адчыніць"
-#: engines/scumm/help.cpp:149
+#: engines/scumm/help.cpp:150
msgid "Put on"
msgstr "Пакласці"
-#: engines/scumm/help.cpp:150
+#: engines/scumm/help.cpp:151
msgid "Take off"
msgstr "Падняць"
-#: engines/scumm/help.cpp:156
+#: engines/scumm/help.cpp:157
msgid "Fix"
msgstr "Выправіць"
-#: engines/scumm/help.cpp:158
+#: engines/scumm/help.cpp:159
msgid "Switch"
msgstr "Пераключыць"
-#: engines/scumm/help.cpp:166 engines/scumm/help.cpp:228
+#: engines/scumm/help.cpp:167 engines/scumm/help.cpp:229
msgid "Look"
msgstr "Глядзець"
-#: engines/scumm/help.cpp:173 engines/scumm/help.cpp:223
+#: engines/scumm/help.cpp:174 engines/scumm/help.cpp:224
msgid "Talk"
msgstr "Гаварыць"
-#: engines/scumm/help.cpp:174
+#: engines/scumm/help.cpp:175
msgid "Travel"
msgstr "Падарожнічаць"
-#: engines/scumm/help.cpp:175
+#: engines/scumm/help.cpp:176
msgid "To Henry / To Indy"
msgstr "Генры/Інды"
#. I18N: These are different musical notes
-#: engines/scumm/help.cpp:179
+#: engines/scumm/help.cpp:180
msgid "play C minor on distaff"
msgstr "іграць до мінор на калаўроце"
-#: engines/scumm/help.cpp:180
+#: engines/scumm/help.cpp:181
msgid "play D on distaff"
msgstr "іграць рэ на калаўроце"
-#: engines/scumm/help.cpp:181
+#: engines/scumm/help.cpp:182
msgid "play E on distaff"
msgstr "іграць мі на калаўроце"
-#: engines/scumm/help.cpp:182
+#: engines/scumm/help.cpp:183
msgid "play F on distaff"
msgstr "іграць фа на калаўроце"
-#: engines/scumm/help.cpp:183
+#: engines/scumm/help.cpp:184
msgid "play G on distaff"
msgstr "іграць соль на калаўроце"
-#: engines/scumm/help.cpp:184
+#: engines/scumm/help.cpp:185
msgid "play A on distaff"
msgstr "іграць ля на калаўроце"
-#: engines/scumm/help.cpp:185
+#: engines/scumm/help.cpp:186
msgid "play B on distaff"
msgstr "іграць сі на калаўроце"
-#: engines/scumm/help.cpp:186
+#: engines/scumm/help.cpp:187
msgid "play C major on distaff"
msgstr "іграць до мажор на калаўроце"
-#: engines/scumm/help.cpp:192 engines/scumm/help.cpp:214
+#: engines/scumm/help.cpp:193 engines/scumm/help.cpp:215
msgid "puSh"
msgstr "пхаць"
-#: engines/scumm/help.cpp:193 engines/scumm/help.cpp:215
+#: engines/scumm/help.cpp:194 engines/scumm/help.cpp:216
msgid "pull (Yank)"
msgstr "цягнуць (чапляць)"
-#: engines/scumm/help.cpp:196 engines/scumm/help.cpp:212
-#: engines/scumm/help.cpp:248
+#: engines/scumm/help.cpp:197 engines/scumm/help.cpp:213
+#: engines/scumm/help.cpp:249
msgid "Talk to"
msgstr "Гаварыць з"
-#: engines/scumm/help.cpp:199 engines/scumm/help.cpp:211
+#: engines/scumm/help.cpp:200 engines/scumm/help.cpp:212
msgid "Look at"
msgstr "Глядзець на"
-#: engines/scumm/help.cpp:200
+#: engines/scumm/help.cpp:201
msgid "turn oN"
msgstr "уключыць"
-#: engines/scumm/help.cpp:201
+#: engines/scumm/help.cpp:202
msgid "turn oFf"
msgstr "выключыць"
-#: engines/scumm/help.cpp:217
+#: engines/scumm/help.cpp:218
msgid "KeyUp"
msgstr "Уверх"
-#: engines/scumm/help.cpp:217
+#: engines/scumm/help.cpp:218
msgid "Highlight prev dialogue"
msgstr "Падсвятліць папярэдні дыялог"
-#: engines/scumm/help.cpp:218
+#: engines/scumm/help.cpp:219
msgid "KeyDown"
msgstr "Уніз"
-#: engines/scumm/help.cpp:218
+#: engines/scumm/help.cpp:219
msgid "Highlight next dialogue"
msgstr "Падсвятліць наступны дыялог"
-#: engines/scumm/help.cpp:222
+#: engines/scumm/help.cpp:223
msgid "Walk"
msgstr "Ісці"
-#: engines/scumm/help.cpp:225 engines/scumm/help.cpp:234
-#: engines/scumm/help.cpp:241 engines/scumm/help.cpp:249
+#: engines/scumm/help.cpp:226 engines/scumm/help.cpp:235
+#: engines/scumm/help.cpp:242 engines/scumm/help.cpp:250
msgid "Inventory"
msgstr "Інвентар"
-#: engines/scumm/help.cpp:226
+#: engines/scumm/help.cpp:227
msgid "Object"
msgstr "Аб'ект"
-#: engines/scumm/help.cpp:229
+#: engines/scumm/help.cpp:230
msgid "Black and White / Color"
msgstr "Чорна-белы / Каляровы"
-#: engines/scumm/help.cpp:232
+#: engines/scumm/help.cpp:233
msgid "Eyes"
msgstr "Вочы"
-#: engines/scumm/help.cpp:233
+#: engines/scumm/help.cpp:234
msgid "Tongue"
msgstr "Язык"
-#: engines/scumm/help.cpp:235
+#: engines/scumm/help.cpp:236
msgid "Punch"
msgstr "Удар"
-#: engines/scumm/help.cpp:236
+#: engines/scumm/help.cpp:237
msgid "Kick"
msgstr "Нагой"
-#: engines/scumm/help.cpp:239 engines/scumm/help.cpp:247
+#: engines/scumm/help.cpp:240 engines/scumm/help.cpp:248
msgid "Examine"
msgstr "Праверыць"
-#: engines/scumm/help.cpp:240
+#: engines/scumm/help.cpp:241
msgid "Regular cursor"
msgstr "Звычайны курсор"
#. I18N: Comm is a communication device
-#: engines/scumm/help.cpp:243
+#: engines/scumm/help.cpp:244
msgid "Comm"
msgstr "Кам"
-#: engines/scumm/help.cpp:246
+#: engines/scumm/help.cpp:247
msgid "Save / Load / Options"
msgstr "Загрузіць / Захаваць / Налады"
-#: engines/scumm/help.cpp:255
+#: engines/scumm/help.cpp:256
msgid "Other game controls:"
msgstr "Астатняе кіраванне гульнёй:"
-#: engines/scumm/help.cpp:257 engines/scumm/help.cpp:267
+#: engines/scumm/help.cpp:258 engines/scumm/help.cpp:268
msgid "Inventory:"
msgstr "Інвентар:"
-#: engines/scumm/help.cpp:258 engines/scumm/help.cpp:274
+#: engines/scumm/help.cpp:259 engines/scumm/help.cpp:275
msgid "Scroll list up"
msgstr "Пракруціць спіс уверх"
-#: engines/scumm/help.cpp:259 engines/scumm/help.cpp:275
+#: engines/scumm/help.cpp:260 engines/scumm/help.cpp:276
msgid "Scroll list down"
msgstr "Пракруціць спіс уніз"
-#: engines/scumm/help.cpp:260 engines/scumm/help.cpp:268
+#: engines/scumm/help.cpp:261 engines/scumm/help.cpp:269
msgid "Upper left item"
msgstr "Верхні левы прадмет"
-#: engines/scumm/help.cpp:261 engines/scumm/help.cpp:270
+#: engines/scumm/help.cpp:262 engines/scumm/help.cpp:271
msgid "Lower left item"
msgstr "Ніжні левы прадмет"
-#: engines/scumm/help.cpp:262 engines/scumm/help.cpp:271
+#: engines/scumm/help.cpp:263 engines/scumm/help.cpp:272
msgid "Upper right item"
msgstr "Верхні правы прадмет"
-#: engines/scumm/help.cpp:263 engines/scumm/help.cpp:273
+#: engines/scumm/help.cpp:264 engines/scumm/help.cpp:274
msgid "Lower right item"
msgstr "Ніжні правы прадмет"
-#: engines/scumm/help.cpp:269
+#: engines/scumm/help.cpp:270
msgid "Middle left item"
msgstr "Сярэдні левы прадмет"
-#: engines/scumm/help.cpp:272
+#: engines/scumm/help.cpp:273
msgid "Middle right item"
msgstr "Сярэдні правы прадмет"
-#: engines/scumm/help.cpp:279 engines/scumm/help.cpp:284
+#: engines/scumm/help.cpp:280 engines/scumm/help.cpp:285
msgid "Switching characters:"
msgstr "Змена героя:"
-#: engines/scumm/help.cpp:281
+#: engines/scumm/help.cpp:282
msgid "Second kid"
msgstr "Другі герой"
-#: engines/scumm/help.cpp:282
+#: engines/scumm/help.cpp:283
msgid "Third kid"
msgstr "Трэці герой"
-#: engines/scumm/help.cpp:294
+#: engines/scumm/help.cpp:292
+#, fuzzy
+msgid "Toggle Inventory/IQ Points display"
+msgstr "Уключыць паказ дадзеных у цэнтры экрана"
+
+#: engines/scumm/help.cpp:293
+msgid "Toggle Keyboard/Mouse Fighting (*)"
+msgstr ""
+
+#: engines/scumm/help.cpp:295
+msgid "* Keyboard Fighting is always on,"
+msgstr ""
+
+#: engines/scumm/help.cpp:296
+msgid " so despite the in-game message this"
+msgstr ""
+
+#: engines/scumm/help.cpp:297
+msgid " actually toggles Mouse Fighting Off/On"
+msgstr ""
+
+#: engines/scumm/help.cpp:304
msgid "Fighting controls (numpad):"
msgstr "Кіраванне боем (лічбавыя клавішы)"
-#: engines/scumm/help.cpp:295 engines/scumm/help.cpp:296
-#: engines/scumm/help.cpp:297
+#: engines/scumm/help.cpp:305 engines/scumm/help.cpp:306
+#: engines/scumm/help.cpp:307
msgid "Step back"
msgstr "Крок назад"
-#: engines/scumm/help.cpp:298
+#: engines/scumm/help.cpp:308
msgid "Block high"
msgstr "Абарона зверху"
-#: engines/scumm/help.cpp:299
+#: engines/scumm/help.cpp:309
msgid "Block middle"
msgstr "Абарона пасярэдзіне"
-#: engines/scumm/help.cpp:300
+#: engines/scumm/help.cpp:310
msgid "Block low"
msgstr "Абарона знізу"
-#: engines/scumm/help.cpp:301
+#: engines/scumm/help.cpp:311
msgid "Punch high"
msgstr "Удар зверху"
-#: engines/scumm/help.cpp:302
+#: engines/scumm/help.cpp:312
msgid "Punch middle"
msgstr "Удар пасярэдзіне"
-#: engines/scumm/help.cpp:303
+#: engines/scumm/help.cpp:313
msgid "Punch low"
msgstr "Удар знізу"
-#: engines/scumm/help.cpp:306
+#: engines/scumm/help.cpp:315
+msgid "Sucker punch"
+msgstr ""
+
+#: engines/scumm/help.cpp:318
msgid "These are for Indy on left."
msgstr "Гэта калі Інды злева."
-#: engines/scumm/help.cpp:307
+#: engines/scumm/help.cpp:319
msgid "When Indy is on the right,"
msgstr "Калі Інды справа,"
-#: engines/scumm/help.cpp:308
+#: engines/scumm/help.cpp:320
msgid "7, 4, and 1 are switched with"
msgstr "7, 4 і 1 змяняюцца з"
-#: engines/scumm/help.cpp:309
+#: engines/scumm/help.cpp:321
msgid "9, 6, and 3, respectively."
msgstr "9, 6 і 3 адпаведна."
-#: engines/scumm/help.cpp:316
+#: engines/scumm/help.cpp:328
msgid "Biplane controls (numpad):"
msgstr "Кіраванне самалётам (лічбавыя клавішы)"
-#: engines/scumm/help.cpp:317
+#: engines/scumm/help.cpp:329
msgid "Fly to upper left"
msgstr "Ляцець налева-ўверх"
-#: engines/scumm/help.cpp:318
+#: engines/scumm/help.cpp:330
msgid "Fly to left"
msgstr "Ляцець налева"
-#: engines/scumm/help.cpp:319
+#: engines/scumm/help.cpp:331
msgid "Fly to lower left"
msgstr "Ляцець налева-ўніз"
-#: engines/scumm/help.cpp:320
+#: engines/scumm/help.cpp:332
msgid "Fly upwards"
msgstr "Ляцець уверх"
-#: engines/scumm/help.cpp:321
+#: engines/scumm/help.cpp:333
msgid "Fly straight"
msgstr "Ляцець прама"
-#: engines/scumm/help.cpp:322
+#: engines/scumm/help.cpp:334
msgid "Fly down"
msgstr "Ляцець уніз"
-#: engines/scumm/help.cpp:323
+#: engines/scumm/help.cpp:335
msgid "Fly to upper right"
msgstr "Ляцець направа-ўверх"
-#: engines/scumm/help.cpp:324
+#: engines/scumm/help.cpp:336
msgid "Fly to right"
msgstr "Ляцець направа"
-#: engines/scumm/help.cpp:325
+#: engines/scumm/help.cpp:337
msgid "Fly to lower right"
msgstr "Ляцець направа-ўніз"
-#: engines/scumm/scumm.cpp:1823
+#: engines/scumm/scumm.cpp:1832
#, c-format
msgid ""
"Native MIDI support requires the Roland Upgrade from LucasArts,\n"
@@ -3195,11 +3285,12 @@ msgstr ""
"Рэжым \"роднага\" MIDI патрабуе абнаўленне Roland Upgrade ад\n"
"LucasArts, але не хапае %s. Пераключаюся на AdLib."
-#: engines/scumm/scumm.cpp:2594
+#: engines/scumm/scumm.cpp:2644
+#, fuzzy
msgid ""
-"Usually, Maniac Mansion would start now. But ScummVM doesn't do that yet. To "
-"play it, go to 'Add Game' in the ScummVM start menu and select the 'Maniac' "
-"directory inside the Tentacle game directory."
+"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, а "
@@ -3338,6 +3429,48 @@ msgstr ""
msgid "Show the current number of frames per second in the upper left corner"
msgstr ""
+#: engines/zvision/detection.cpp:256
+msgid "Double FPS"
+msgstr ""
+
+#: engines/zvision/detection.cpp:257
+msgid "Increase game FPS from 30 to 60"
+msgstr ""
+
+#: engines/zvision/detection.cpp:266
+#, fuzzy
+msgid "Enable Venus"
+msgstr "Уключыць рэжым гелія"
+
+#: engines/zvision/detection.cpp:267
+msgid "Enable the Venus help system"
+msgstr ""
+
+#: engines/zvision/detection.cpp:276
+msgid "Disable animation while turning"
+msgstr ""
+
+#: engines/zvision/detection.cpp:277
+msgid "Disable animation while turning in panoramic mode"
+msgstr ""
+
+#: engines/zvision/detection.cpp:286
+msgid "Use the hires MPEG movies"
+msgstr ""
+
+#: engines/zvision/detection.cpp:287
+#, fuzzy
+msgid ""
+"Use the hires MPEG movies of the DVD version, instead of the lowres AVI ones"
+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 быў сабраны без "
@@ -3347,9 +3480,6 @@ msgstr ""
#~ msgid "Mass Add..."
#~ msgstr "Шмат гульняў..."
-#~ msgid "Mass Add..."
-#~ msgstr "Шмат гульняў..."
-
#~ msgid ""
#~ "Turns off General MIDI mapping for games with Roland MT-32 soundtrack"
#~ msgstr ""
diff --git a/po/ca_ES.po b/po/ca_ES.po
index 12a86b5db7..bfbc9b8c37 100644
--- a/po/ca_ES.po
+++ b/po/ca_ES.po
@@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: ScummVM 1.6.0git\n"
"Report-Msgid-Bugs-To: scummvm-devel@lists.sf.net\n"
-"POT-Creation-Date: 2014-10-04 00:58+0100\n"
+"POT-Creation-Date: 2015-06-30 20:57+0100\n"
"PO-Revision-Date: 2013-05-05 14:16+0100\n"
"Last-Translator: Jordi Vilalta Prat <jvprat@jvprat.com>\n"
"Language-Team: Catalan <scummvm-devel@lists.sf.net>\n"
@@ -52,10 +52,11 @@ msgstr "Amunt"
#: gui/browser.cpp:75 gui/chooser.cpp:46 gui/KeysDialog.cpp:43
#: gui/launcher.cpp:351 gui/massadd.cpp:95 gui/options.cpp:1239
+#: gui/recorderdialog.cpp:70 gui/recorderdialog.cpp:156
#: gui/saveload-dialog.cpp:216 gui/saveload-dialog.cpp:276
-#: gui/saveload-dialog.cpp:547 gui/saveload-dialog.cpp:922
+#: gui/saveload-dialog.cpp:547 gui/saveload-dialog.cpp:931
#: gui/themebrowser.cpp:55 gui/fluidsynth-dialog.cpp:152
-#: engines/engine.cpp:452 backends/platform/wii/options.cpp:48
+#: engines/engine.cpp:483 backends/platform/wii/options.cpp:48
#: backends/events/default/default-events.cpp:196
#: backends/events/default/default-events.cpp:218
#: engines/drascula/saveload.cpp:49 engines/parallaction/saveload.cpp:274
@@ -68,9 +69,9 @@ msgid "Choose"
msgstr "Escull"
#: gui/gui-manager.cpp:117 backends/keymapper/remap-dialog.cpp:53
-#: 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
+#: 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"
@@ -86,7 +87,7 @@ msgstr "Mostra el teclat"
msgid "Remap keys"
msgstr "Assigna les tecles"
-#: gui/gui-manager.cpp:131 base/main.cpp:326 engines/scumm/help.cpp:86
+#: gui/gui-manager.cpp:131 base/main.cpp:326 engines/scumm/help.cpp:87
msgid "Toggle fullscreen"
msgstr "Commuta la pantalla completa"
@@ -100,13 +101,13 @@ 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:1240
-#: gui/saveload-dialog.cpp:923 gui/fluidsynth-dialog.cpp:153
-#: engines/engine.cpp:371 engines/engine.cpp:382
+#: 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:399 engines/parallaction/saveload.cpp:274
-#: engines/scumm/dialogs.cpp:193 engines/scumm/scumm.cpp:1825
+#: 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
@@ -479,7 +480,7 @@ msgstr ""
#: gui/launcher.cpp:793 gui/launcher.cpp:941 gui/launcher.cpp:1000
#: gui/fluidsynth-dialog.cpp:217
-#: backends/events/symbiansdl/symbiansdl-events.cpp:184
+#: 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
@@ -489,7 +490,7 @@ 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:184
+#: 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
@@ -527,6 +528,14 @@ 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
+msgid "Mass Add..."
+msgstr "Addiciѓ Massiva..."
+
+#: gui/launcher.cpp:1161
+msgid "Record..."
+msgstr ""
+
#: gui/massadd.cpp:79 gui/massadd.cpp:82
msgid "... progress ..."
msgstr "... progrщs ..."
@@ -626,7 +635,7 @@ msgid "Special dithering modes supported by some games"
msgstr "Modes de tramat especials suportats per alguns jocs"
#: gui/options.cpp:760
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2249
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2298
msgid "Fullscreen mode"
msgstr "Mode pantalla completa"
@@ -946,6 +955,43 @@ msgstr ""
"El tema que heu seleccionat no suporta l'idioma actual. Si voleu utilitzar "
"aquest tema primer haureu de canviar a un altre idioma."
+#: gui/recorderdialog.cpp:64
+msgid "Recorder or Playback Gameplay"
+msgstr ""
+
+#: gui/recorderdialog.cpp:69 gui/recorderdialog.cpp:156
+#: gui/saveload-dialog.cpp:220 gui/saveload-dialog.cpp:276
+msgid "Delete"
+msgstr "Suprimeix"
+
+#: gui/recorderdialog.cpp:71
+msgid "Record"
+msgstr ""
+
+#: gui/recorderdialog.cpp:72
+#, fuzzy
+msgid "Playback"
+msgstr "Jugar"
+
+#: gui/recorderdialog.cpp:74
+msgid "Edit"
+msgstr ""
+
+#: gui/recorderdialog.cpp:86 gui/recorderdialog.cpp:243
+#: gui/recorderdialog.cpp:253
+msgid "Author: "
+msgstr ""
+
+#: gui/recorderdialog.cpp:87 gui/recorderdialog.cpp:244
+#: gui/recorderdialog.cpp:254
+msgid "Notes: "
+msgstr ""
+
+#: gui/recorderdialog.cpp:155
+#, fuzzy
+msgid "Do you really want to delete this record?"
+msgstr "Realment voleu suprimir aquesta partida?"
+
#: gui/saveload-dialog.cpp:167
msgid "List view"
msgstr "Vista de llistat"
@@ -966,23 +1012,19 @@ msgstr "No hi ha hora desada"
msgid "No playtime saved"
msgstr "No hi ha temps de joc desat"
-#: gui/saveload-dialog.cpp:220 gui/saveload-dialog.cpp:276
-msgid "Delete"
-msgstr "Suprimeix"
-
#: gui/saveload-dialog.cpp:275
msgid "Do you really want to delete this saved game?"
msgstr "Realment voleu suprimir aquesta partida?"
-#: gui/saveload-dialog.cpp:385 gui/saveload-dialog.cpp:875
+#: gui/saveload-dialog.cpp:385 gui/saveload-dialog.cpp:884
msgid "Date: "
msgstr "Data: "
-#: gui/saveload-dialog.cpp:389 gui/saveload-dialog.cpp:881
+#: gui/saveload-dialog.cpp:389 gui/saveload-dialog.cpp:890
msgid "Time: "
msgstr "Hora: "
-#: gui/saveload-dialog.cpp:395 gui/saveload-dialog.cpp:889
+#: gui/saveload-dialog.cpp:395 gui/saveload-dialog.cpp:898
msgid "Playtime: "
msgstr "Temps de joc: "
@@ -998,19 +1040,19 @@ msgstr "Segќent"
msgid "Prev"
msgstr "Anterior"
-#: gui/saveload-dialog.cpp:739
+#: gui/saveload-dialog.cpp:748
msgid "New Save"
msgstr "Nova partida desada"
-#: gui/saveload-dialog.cpp:739
+#: gui/saveload-dialog.cpp:748
msgid "Create a new save game"
msgstr "Crea una nova partida desada"
-#: gui/saveload-dialog.cpp:868
+#: gui/saveload-dialog.cpp:877
msgid "Name: "
msgstr "Nom: "
-#: gui/saveload-dialog.cpp:940
+#: gui/saveload-dialog.cpp:949
#, c-format
msgid "Enter a description for slot %d:"
msgstr "Entreu la descripciѓ per l'espai %d:"
@@ -1166,7 +1208,7 @@ msgstr "Salta la lэnia"
msgid "Error running game:"
msgstr "Error al executar el joc:"
-#: base/main.cpp:536
+#: base/main.cpp:554
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"
@@ -1284,7 +1326,7 @@ 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:758
+#: engines/pegasus/pegasus.cpp:377 engines/sci/engine/kfile.cpp:759
#: engines/toltecs/menu.cpp:281 engines/tsage/scenes.cpp:598
msgid "Save game:"
msgstr "Desa la partida:"
@@ -1297,7 +1339,7 @@ msgstr "Desa la partida:"
#: 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:758 engines/scumm/dialogs.cpp:188
+#: engines/sci/engine/kfile.cpp:759 engines/scumm/dialogs.cpp:188
#: engines/toltecs/menu.cpp:281 engines/tsage/scenes.cpp:598
msgid "Save"
msgstr "Desa"
@@ -1334,23 +1376,23 @@ msgstr "~C~ancelЗla"
msgid "~K~eys"
msgstr "~T~ecles"
-#: engines/engine.cpp:245
+#: engines/engine.cpp:276
msgid "Could not initialize color format."
msgstr "No s'ha pogut iniciar el format de color."
-#: engines/engine.cpp:253
+#: engines/engine.cpp:284
msgid "Could not switch to video mode: '"
msgstr "No s'ha pogut canviar al mode de vэdeo: '"
-#: engines/engine.cpp:262
+#: engines/engine.cpp:293
msgid "Could not apply aspect ratio setting."
msgstr "No s'ha pogut aplicar la configuraciѓ de la relaciѓ d'aspecte."
-#: engines/engine.cpp:267
+#: engines/engine.cpp:298
msgid "Could not apply fullscreen setting."
msgstr "No s'ha pogut aplicar l'ajust de pantalla completa."
-#: engines/engine.cpp:367
+#: engines/engine.cpp:398
msgid ""
"You appear to be playing this game directly\n"
"from the CD. This is known to cause problems,\n"
@@ -1364,7 +1406,7 @@ msgstr ""
"els fitxers de dades al disc dur.\n"
"Consulteu el fitxer README per a mщs detalls."
-#: engines/engine.cpp:378
+#: engines/engine.cpp:409
msgid ""
"This game has audio tracks in its disk. These\n"
"tracks need to be ripped from the disk using\n"
@@ -1378,7 +1420,7 @@ msgstr ""
"tal de poder sentir la mњsica del joc.\n"
"Consulteu el fitxer README per a mщs detalls."
-#: engines/engine.cpp:436
+#: engines/engine.cpp:467
#, c-format
msgid ""
"Gamestate load failed (%s)! Please consult the README for basic information, "
@@ -1387,7 +1429,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:449
+#: engines/engine.cpp:480
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 "
@@ -1397,7 +1439,7 @@ 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:452
+#: engines/engine.cpp:483
msgid "Start anyway"
msgstr "Inicia de totes maneres"
@@ -1607,11 +1649,11 @@ msgstr "Mode Touchpad activat."
msgid "Touchpad mode disabled."
msgstr "Mode Touchpad desactivat."
-#: backends/platform/maemo/maemo.cpp:209
+#: backends/platform/maemo/maemo.cpp:208
msgid "Click Mode"
msgstr "Mode clic"
-#: backends/platform/maemo/maemo.cpp:215
+#: backends/platform/maemo/maemo.cpp:214
#: backends/platform/symbian/src/SymbianActions.cpp:42
#: backends/platform/wince/CEActionsPocket.cpp:60
#: backends/platform/wince/CEActionsSmartphone.cpp:43
@@ -1619,11 +1661,11 @@ msgstr "Mode clic"
msgid "Left Click"
msgstr "Clic esquerre"
-#: backends/platform/maemo/maemo.cpp:218
+#: backends/platform/maemo/maemo.cpp:217
msgid "Middle Click"
msgstr "Clic central"
-#: backends/platform/maemo/maemo.cpp:221
+#: 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
@@ -1660,19 +1702,19 @@ msgctxt "lowres"
msgid "Normal (no scaling)"
msgstr "Normal (no escalat)"
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2148
+#: 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:2154
+#: 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:2209
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2258
msgid "Active graphics filter:"
msgstr "Filtre de grрfics actiu:"
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2251
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2300
msgid "Windowed mode"
msgstr "Mode de finestra"
@@ -1732,8 +1774,8 @@ msgstr "Mode rрpid"
#: 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:82
-#: engines/scumm/help.cpp:84
+#: engines/scumm/dialogs.cpp:192 engines/scumm/help.cpp:83
+#: engines/scumm/help.cpp:85
msgid "Quit"
msgstr "Surt"
@@ -1753,7 +1795,7 @@ msgstr "Teclat virtual"
msgid "Key mapper"
msgstr "Assignador de tecles"
-#: backends/events/symbiansdl/symbiansdl-events.cpp:184
+#: backends/events/symbiansdl/symbiansdl-events.cpp:186
msgid "Do you want to quit ?"
msgstr "Vols sortir?"
@@ -2088,34 +2130,55 @@ msgstr "Clicat activat"
msgid "Clicking Disabled"
msgstr "Clicat desactivat"
-#: engines/agi/detection.cpp:142 engines/drascula/detection.cpp:302
+#: 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.cpp:103
+#: engines/zvision/detection.cpp:246
msgid "Use original save/load screens"
msgstr "Utilitza les pantalles originals de desat/cрrrega"
-#: engines/agi/detection.cpp:143 engines/drascula/detection.cpp:303
+#: 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/zvision/detection.cpp:104
+#: engines/zvision/detection.cpp:247
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"
+#: engines/agi/detection.cpp:157
+#, fuzzy
+msgid "Use an alternative palette"
+msgstr "Utilitza una introducciѓ del joc alternativa (nomщs per la versiѓ CD)"
+
+#: engines/agi/detection.cpp:158
+msgid ""
+"Use an alternative palette, common for all Amiga games. This was the old "
+"behavior"
+msgstr ""
+
+#: engines/agi/detection.cpp:167
+#, fuzzy
+msgid "Mouse support"
+msgstr "Suport per saltar text i escenes"
+
+#: 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:857 engines/toltecs/menu.cpp:256
+#: engines/sci/engine/kfile.cpp:858 engines/toltecs/menu.cpp:256
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:857 engines/toltecs/menu.cpp:256
+#: engines/sci/engine/kfile.cpp:858 engines/toltecs/menu.cpp:256
msgid "Restore"
msgstr "Restaura"
-#: engines/agos/saveload.cpp:160 engines/scumm/scumm.cpp:2368
+#: engines/agos/saveload.cpp:160 engines/scumm/scumm.cpp:2377
#, c-format
msgid ""
"Failed to load game state from file:\n"
@@ -2126,7 +2189,7 @@ msgstr ""
"\n"
"%s"
-#: engines/agos/saveload.cpp:195 engines/scumm/scumm.cpp:2361
+#: engines/agos/saveload.cpp:195 engines/scumm/scumm.cpp:2370
#, c-format
msgid ""
"Failed to save game state to file:\n"
@@ -2137,7 +2200,7 @@ msgstr ""
"\n"
"%s"
-#: engines/agos/saveload.cpp:203 engines/scumm/scumm.cpp:2379
+#: engines/agos/saveload.cpp:203 engines/scumm/scumm.cpp:2388
#, c-format
msgid ""
"Successfully saved game state in file:\n"
@@ -2153,12 +2216,12 @@ msgstr ""
msgid "Cutscene file '%s' not found!"
msgstr "No s'ha trobat el fitxer d'escena '%s'!"
-#: engines/cge/detection.cpp:105 engines/cge2/detection.cpp:81
+#: engines/cge/detection.cpp:105 engines/cge2/detection.cpp:101
#, fuzzy
msgid "Color Blind Mode"
msgstr "Mode clic"
-#: engines/cge/detection.cpp:106 engines/cge2/detection.cpp:82
+#: engines/cge/detection.cpp:106 engines/cge2/detection.cpp:102
msgid "Enable Color Blind Mode by default"
msgstr ""
@@ -2210,7 +2273,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:399
+#: engines/groovie/script.cpp:408
msgid "Failed to save game"
msgstr "No s'ha pogut desar l'estat del joc"
@@ -2508,12 +2571,12 @@ 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
-msgid "EGA undithering"
-msgstr "Elimina el tramat d'EGA"
+msgid "Skip EGA dithering pass (full color backgrounds)"
+msgstr ""
#: engines/sci/detection.cpp:375
-msgid "Enable undithering in EGA games"
-msgstr "Activa l'eliminaciѓ del tramat en els jocs EGA"
+msgid "Skip dithering pass in EGA games, graphics are shown with full colors"
+msgstr ""
#: engines/sci/detection.cpp:384
msgid "Prefer digital sound effects"
@@ -2589,12 +2652,14 @@ msgstr "Joc pausat. Premeu ESPAI per continuar."
#. "Moechten Sie wirklich neu starten? (J/N)J"
#. Will react to J as 'Yes'
#: engines/scumm/dialogs.cpp:183
-msgid "Are you sure you want to restart? (Y/N)"
+#, 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
-msgid "Are you sure you want to quit? (Y/N)"
+#, 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
@@ -2682,516 +2747,541 @@ msgstr "Prрctica"
msgid "Expert"
msgstr "Expert"
-#: engines/scumm/help.cpp:73
+#: engines/scumm/help.cpp:74
msgid "Common keyboard commands:"
msgstr "Comandes comuns de teclat:"
-#: engines/scumm/help.cpp:74
+#: engines/scumm/help.cpp:75
msgid "Save / Load dialog"
msgstr "Diрleg de desat / cрrrega"
-#: engines/scumm/help.cpp:76
+#: engines/scumm/help.cpp:77
msgid "Skip line of text"
msgstr "Salta la lэnia de text"
-#: engines/scumm/help.cpp:77
+#: engines/scumm/help.cpp:78
msgid "Esc"
msgstr "Esc"
-#: engines/scumm/help.cpp:77
+#: engines/scumm/help.cpp:78
msgid "Skip cutscene"
msgstr "Salta la seqќшncia de video"
-#: engines/scumm/help.cpp:78
+#: engines/scumm/help.cpp:79
msgid "Space"
msgstr "Espai"
-#: engines/scumm/help.cpp:78
+#: engines/scumm/help.cpp:79
msgid "Pause game"
msgstr "Pausa la partida"
-#: engines/scumm/help.cpp:79 engines/scumm/help.cpp:84
-#: engines/scumm/help.cpp:95 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: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:79
+#: engines/scumm/help.cpp:80
msgid "Load game state 1-10"
msgstr "Carrega partida 1-10"
-#: engines/scumm/help.cpp:80 engines/scumm/help.cpp:84
-#: engines/scumm/help.cpp:86 engines/scumm/help.cpp:100
-#: engines/scumm/help.cpp:101 engines/scumm/help.cpp:102
+#: 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:80
+#: engines/scumm/help.cpp:81
msgid "Save game state 1-10"
msgstr "Desa partida 1-10"
-#: engines/scumm/help.cpp:86 engines/scumm/help.cpp:89
+#: engines/scumm/help.cpp:87 engines/scumm/help.cpp:90
msgid "Enter"
msgstr "Intro"
-#: engines/scumm/help.cpp:87
+#: engines/scumm/help.cpp:88
msgid "Music volume up / down"
msgstr "Puja / Baixa el volum de la mњsica"
-#: engines/scumm/help.cpp:88
+#: engines/scumm/help.cpp:89
msgid "Text speed slower / faster"
msgstr "Velocitat de text mщs lenta / mщs rрpida"
-#: engines/scumm/help.cpp:89
+#: engines/scumm/help.cpp:90
msgid "Simulate left mouse button"
msgstr "Simula el botѓ esquerre del ratolэ"
-#: engines/scumm/help.cpp:90
+#: engines/scumm/help.cpp:91
msgid "Tab"
msgstr "Tab"
-#: engines/scumm/help.cpp:90
+#: engines/scumm/help.cpp:91
msgid "Simulate right mouse button"
msgstr "Simula el botѓ dret del ratolэ"
-#: engines/scumm/help.cpp:93
+#: engines/scumm/help.cpp:94
msgid "Special keyboard commands:"
msgstr "Comandes especials de teclat:"
-#: engines/scumm/help.cpp:94
+#: engines/scumm/help.cpp:95
msgid "Show / Hide console"
msgstr "Mostra / Oculta la consola"
-#: engines/scumm/help.cpp:95
+#: engines/scumm/help.cpp:96
msgid "Start the debugger"
msgstr "Inicia el depurador"
-#: engines/scumm/help.cpp:96
+#: engines/scumm/help.cpp:97
msgid "Show memory consumption"
msgstr "Mostra el consum de memђria"
-#: engines/scumm/help.cpp:97
+#: engines/scumm/help.cpp:98
msgid "Run in fast mode (*)"
msgstr "Executa en mode rрpid (*)"
-#: engines/scumm/help.cpp:98
+#: engines/scumm/help.cpp:99
msgid "Run in really fast mode (*)"
msgstr "Executa en mode realment rрpid (*)"
-#: engines/scumm/help.cpp:99
+#: engines/scumm/help.cpp:100
msgid "Toggle mouse capture"
msgstr "Commuta la captura del ratolэ"
-#: engines/scumm/help.cpp:100
+#: engines/scumm/help.cpp:101
msgid "Switch between graphics filters"
msgstr "Commuta entre els filtres grрfics"
-#: engines/scumm/help.cpp:101
+#: engines/scumm/help.cpp:102
msgid "Increase / Decrease scale factor"
msgstr "Augmenta / Disminueix el factor d'escala"
-#: engines/scumm/help.cpp:102
+#: engines/scumm/help.cpp:103
msgid "Toggle aspect-ratio correction"
msgstr "Commuta la correcciѓ de la relaciѓ d'aspecte"
-#: engines/scumm/help.cpp:107
+#: engines/scumm/help.cpp:108
msgid "* Note that using ctrl-f and"
msgstr "* Tingueu en compte que no es"
-#: engines/scumm/help.cpp:108
+#: engines/scumm/help.cpp:109
msgid " ctrl-g are not recommended"
msgstr " recomana utilitzar ctrl-f i ctrl-g"
-#: engines/scumm/help.cpp:109
+#: engines/scumm/help.cpp:110
msgid " since they may cause crashes"
msgstr " ja que poden provocar errors o"
-#: engines/scumm/help.cpp:110
+#: engines/scumm/help.cpp:111
msgid " or incorrect game behavior."
msgstr " comportament del joc incorrecte."
-#: engines/scumm/help.cpp:114
+#: engines/scumm/help.cpp:115
msgid "Spinning drafts on the keyboard:"
msgstr "Filant des del teclat:"
-#: engines/scumm/help.cpp:116
+#: engines/scumm/help.cpp:117
msgid "Main game controls:"
msgstr "Controls principals del joc:"
-#: engines/scumm/help.cpp:121 engines/scumm/help.cpp:136
-#: engines/scumm/help.cpp:161
+#: engines/scumm/help.cpp:122 engines/scumm/help.cpp:137
+#: engines/scumm/help.cpp:162
msgid "Push"
msgstr "Empeny"
-#: engines/scumm/help.cpp:122 engines/scumm/help.cpp:137
-#: engines/scumm/help.cpp:162
+#: engines/scumm/help.cpp:123 engines/scumm/help.cpp:138
+#: engines/scumm/help.cpp:163
msgid "Pull"
msgstr "Estira"
-#: engines/scumm/help.cpp:123 engines/scumm/help.cpp:138
-#: engines/scumm/help.cpp:163 engines/scumm/help.cpp:197
-#: engines/scumm/help.cpp:207
+#: 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 "Dѓna"
-#: engines/scumm/help.cpp:124 engines/scumm/help.cpp:139
-#: engines/scumm/help.cpp:164 engines/scumm/help.cpp:190
-#: engines/scumm/help.cpp:208
+#: 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 "Obre"
-#: engines/scumm/help.cpp:126
+#: engines/scumm/help.cpp:127
msgid "Go to"
msgstr "Vщs a"
-#: engines/scumm/help.cpp:127
+#: engines/scumm/help.cpp:128
msgid "Get"
msgstr "Obtщ"
-#: engines/scumm/help.cpp:128 engines/scumm/help.cpp:152
-#: engines/scumm/help.cpp:170 engines/scumm/help.cpp:198
-#: engines/scumm/help.cpp:213 engines/scumm/help.cpp:224
-#: engines/scumm/help.cpp:250
+#: 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 "Utilitza"
-#: engines/scumm/help.cpp:129 engines/scumm/help.cpp:141
+#: engines/scumm/help.cpp:130 engines/scumm/help.cpp:142
msgid "Read"
msgstr "Llegeix"
-#: engines/scumm/help.cpp:130 engines/scumm/help.cpp:147
+#: engines/scumm/help.cpp:131 engines/scumm/help.cpp:148
msgid "New kid"
msgstr "Nou noi"
-#: engines/scumm/help.cpp:131 engines/scumm/help.cpp:153
-#: engines/scumm/help.cpp:171
+#: engines/scumm/help.cpp:132 engines/scumm/help.cpp:154
+#: engines/scumm/help.cpp:172
msgid "Turn on"
msgstr "Engega"
-#: engines/scumm/help.cpp:132 engines/scumm/help.cpp:154
-#: engines/scumm/help.cpp:172
+#: engines/scumm/help.cpp:133 engines/scumm/help.cpp:155
+#: engines/scumm/help.cpp:173
msgid "Turn off"
msgstr "Apaga"
-#: engines/scumm/help.cpp:142 engines/scumm/help.cpp:167
-#: engines/scumm/help.cpp:194
+#: engines/scumm/help.cpp:143 engines/scumm/help.cpp:168
+#: engines/scumm/help.cpp:195
msgid "Walk to"
msgstr "Vщs a"
-#: engines/scumm/help.cpp:143 engines/scumm/help.cpp:168
-#: engines/scumm/help.cpp:195 engines/scumm/help.cpp:210
-#: engines/scumm/help.cpp:227
+#: 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 "Agafa"
-#: engines/scumm/help.cpp:144 engines/scumm/help.cpp:169
+#: engines/scumm/help.cpp:145 engines/scumm/help.cpp:170
msgid "What is"
msgstr "Quш щs"
-#: engines/scumm/help.cpp:146
+#: engines/scumm/help.cpp:147
msgid "Unlock"
msgstr "Desbloqueja"
-#: engines/scumm/help.cpp:149
+#: engines/scumm/help.cpp:150
msgid "Put on"
msgstr "Posa a"
-#: engines/scumm/help.cpp:150
+#: engines/scumm/help.cpp:151
msgid "Take off"
msgstr "Aixecar el vol"
-#: engines/scumm/help.cpp:156
+#: engines/scumm/help.cpp:157
msgid "Fix"
msgstr "Arregla"
-#: engines/scumm/help.cpp:158
+#: engines/scumm/help.cpp:159
msgid "Switch"
msgstr "Commuta"
-#: engines/scumm/help.cpp:166 engines/scumm/help.cpp:228
+#: engines/scumm/help.cpp:167 engines/scumm/help.cpp:229
msgid "Look"
msgstr "Mira"
-#: engines/scumm/help.cpp:173 engines/scumm/help.cpp:223
+#: engines/scumm/help.cpp:174 engines/scumm/help.cpp:224
msgid "Talk"
msgstr "Parla"
-#: engines/scumm/help.cpp:174
+#: engines/scumm/help.cpp:175
msgid "Travel"
msgstr "Viatja"
-#: engines/scumm/help.cpp:175
+#: engines/scumm/help.cpp:176
msgid "To Henry / To Indy"
msgstr "A en Henry / A l'Indy"
#. I18N: These are different musical notes
-#: engines/scumm/help.cpp:179
+#: engines/scumm/help.cpp:180
msgid "play C minor on distaff"
msgstr "toca un Do menor amb la filosa"
-#: engines/scumm/help.cpp:180
+#: engines/scumm/help.cpp:181
msgid "play D on distaff"
msgstr "toca un Re amb la filosa"
-#: engines/scumm/help.cpp:181
+#: engines/scumm/help.cpp:182
msgid "play E on distaff"
msgstr "toca un Mi amb la filosa"
-#: engines/scumm/help.cpp:182
+#: engines/scumm/help.cpp:183
msgid "play F on distaff"
msgstr "toca un Fa amb la filosa"
-#: engines/scumm/help.cpp:183
+#: engines/scumm/help.cpp:184
msgid "play G on distaff"
msgstr "toca un Sol amb la filosa"
-#: engines/scumm/help.cpp:184
+#: engines/scumm/help.cpp:185
msgid "play A on distaff"
msgstr "toca un La amb la filosa"
-#: engines/scumm/help.cpp:185
+#: engines/scumm/help.cpp:186
msgid "play B on distaff"
msgstr "toca un Si amb la filosa"
-#: engines/scumm/help.cpp:186
+#: engines/scumm/help.cpp:187
msgid "play C major on distaff"
msgstr "toca un Do major amb la filosa"
-#: engines/scumm/help.cpp:192 engines/scumm/help.cpp:214
+#: engines/scumm/help.cpp:193 engines/scumm/help.cpp:215
msgid "puSh"
msgstr "empentar"
-#: engines/scumm/help.cpp:193 engines/scumm/help.cpp:215
+#: engines/scumm/help.cpp:194 engines/scumm/help.cpp:216
msgid "pull (Yank)"
msgstr "estirar"
-#: engines/scumm/help.cpp:196 engines/scumm/help.cpp:212
-#: engines/scumm/help.cpp:248
+#: engines/scumm/help.cpp:197 engines/scumm/help.cpp:213
+#: engines/scumm/help.cpp:249
msgid "Talk to"
msgstr "Parla amb"
-#: engines/scumm/help.cpp:199 engines/scumm/help.cpp:211
+#: engines/scumm/help.cpp:200 engines/scumm/help.cpp:212
msgid "Look at"
msgstr "Mira"
-#: engines/scumm/help.cpp:200
+#: engines/scumm/help.cpp:201
msgid "turn oN"
msgstr "engega"
-#: engines/scumm/help.cpp:201
+#: engines/scumm/help.cpp:202
msgid "turn oFf"
msgstr "apaga"
-#: engines/scumm/help.cpp:217
+#: engines/scumm/help.cpp:218
msgid "KeyUp"
msgstr "Tecla amunt"
-#: engines/scumm/help.cpp:217
+#: engines/scumm/help.cpp:218
msgid "Highlight prev dialogue"
msgstr "Remarcar el diрleg anterior"
-#: engines/scumm/help.cpp:218
+#: engines/scumm/help.cpp:219
msgid "KeyDown"
msgstr "Tecla avall"
-#: engines/scumm/help.cpp:218
+#: engines/scumm/help.cpp:219
msgid "Highlight next dialogue"
msgstr "Remarcar el diрleg segќent"
-#: engines/scumm/help.cpp:222
+#: engines/scumm/help.cpp:223
msgid "Walk"
msgstr "Camina"
-#: engines/scumm/help.cpp:225 engines/scumm/help.cpp:234
-#: engines/scumm/help.cpp:241 engines/scumm/help.cpp:249
+#: engines/scumm/help.cpp:226 engines/scumm/help.cpp:235
+#: engines/scumm/help.cpp:242 engines/scumm/help.cpp:250
msgid "Inventory"
msgstr "Inventari"
-#: engines/scumm/help.cpp:226
+#: engines/scumm/help.cpp:227
msgid "Object"
msgstr "Objecte"
-#: engines/scumm/help.cpp:229
+#: engines/scumm/help.cpp:230
msgid "Black and White / Color"
msgstr "Blanc i negre / Color"
-#: engines/scumm/help.cpp:232
+#: engines/scumm/help.cpp:233
msgid "Eyes"
msgstr "Ulls"
-#: engines/scumm/help.cpp:233
+#: engines/scumm/help.cpp:234
msgid "Tongue"
msgstr "Llengua"
-#: engines/scumm/help.cpp:235
+#: engines/scumm/help.cpp:236
msgid "Punch"
msgstr "Cop de puny"
-#: engines/scumm/help.cpp:236
+#: engines/scumm/help.cpp:237
msgid "Kick"
msgstr "Puntada"
-#: engines/scumm/help.cpp:239 engines/scumm/help.cpp:247
+#: engines/scumm/help.cpp:240 engines/scumm/help.cpp:248
msgid "Examine"
msgstr "Examina"
-#: engines/scumm/help.cpp:240
+#: engines/scumm/help.cpp:241
msgid "Regular cursor"
msgstr "Cursor normal"
#. I18N: Comm is a communication device
-#: engines/scumm/help.cpp:243
+#: engines/scumm/help.cpp:244
msgid "Comm"
msgstr "Comunicador"
-#: engines/scumm/help.cpp:246
+#: engines/scumm/help.cpp:247
msgid "Save / Load / Options"
msgstr "Desa / Carrega / Opcions"
-#: engines/scumm/help.cpp:255
+#: engines/scumm/help.cpp:256
msgid "Other game controls:"
msgstr "Altres controls del joc"
-#: engines/scumm/help.cpp:257 engines/scumm/help.cpp:267
+#: engines/scumm/help.cpp:258 engines/scumm/help.cpp:268
msgid "Inventory:"
msgstr "Inventari:"
-#: engines/scumm/help.cpp:258 engines/scumm/help.cpp:274
+#: engines/scumm/help.cpp:259 engines/scumm/help.cpp:275
msgid "Scroll list up"
msgstr "Desplaчa la llista amunt"
-#: engines/scumm/help.cpp:259 engines/scumm/help.cpp:275
+#: engines/scumm/help.cpp:260 engines/scumm/help.cpp:276
msgid "Scroll list down"
msgstr "Desplaчa la llista avall"
-#: engines/scumm/help.cpp:260 engines/scumm/help.cpp:268
+#: engines/scumm/help.cpp:261 engines/scumm/help.cpp:269
msgid "Upper left item"
msgstr "Element superior esquerre"
-#: engines/scumm/help.cpp:261 engines/scumm/help.cpp:270
+#: engines/scumm/help.cpp:262 engines/scumm/help.cpp:271
msgid "Lower left item"
msgstr "Element inferior esquerre"
-#: engines/scumm/help.cpp:262 engines/scumm/help.cpp:271
+#: engines/scumm/help.cpp:263 engines/scumm/help.cpp:272
msgid "Upper right item"
msgstr "Element superior dret"
-#: engines/scumm/help.cpp:263 engines/scumm/help.cpp:273
+#: engines/scumm/help.cpp:264 engines/scumm/help.cpp:274
msgid "Lower right item"
msgstr "Element inferior dret"
-#: engines/scumm/help.cpp:269
+#: engines/scumm/help.cpp:270
msgid "Middle left item"
msgstr "Element mig esquerre"
-#: engines/scumm/help.cpp:272
+#: engines/scumm/help.cpp:273
msgid "Middle right item"
msgstr "Element mig dret"
-#: engines/scumm/help.cpp:279 engines/scumm/help.cpp:284
+#: engines/scumm/help.cpp:280 engines/scumm/help.cpp:285
msgid "Switching characters:"
msgstr "Canvia els personatges:"
-#: engines/scumm/help.cpp:281
+#: engines/scumm/help.cpp:282
msgid "Second kid"
msgstr "Segon noi"
-#: engines/scumm/help.cpp:282
+#: engines/scumm/help.cpp:283
msgid "Third kid"
msgstr "Tercer noi"
-#: engines/scumm/help.cpp:294
+#: engines/scumm/help.cpp:292
+#, fuzzy
+msgid "Toggle Inventory/IQ Points display"
+msgstr "Conmuta la visualitzaciѓ de dades central"
+
+#: engines/scumm/help.cpp:293
+msgid "Toggle Keyboard/Mouse Fighting (*)"
+msgstr ""
+
+#: engines/scumm/help.cpp:295
+msgid "* Keyboard Fighting is always on,"
+msgstr ""
+
+#: engines/scumm/help.cpp:296
+msgid " so despite the in-game message this"
+msgstr ""
+
+#: engines/scumm/help.cpp:297
+msgid " actually toggles Mouse Fighting Off/On"
+msgstr ""
+
+#: engines/scumm/help.cpp:304
msgid "Fighting controls (numpad):"
msgstr "Controls de lluita (teclat numшric):"
-#: engines/scumm/help.cpp:295 engines/scumm/help.cpp:296
-#: engines/scumm/help.cpp:297
+#: engines/scumm/help.cpp:305 engines/scumm/help.cpp:306
+#: engines/scumm/help.cpp:307
msgid "Step back"
msgstr "Pas enrere"
-#: engines/scumm/help.cpp:298
+#: engines/scumm/help.cpp:308
msgid "Block high"
msgstr "Bloqueig alt"
-#: engines/scumm/help.cpp:299
+#: engines/scumm/help.cpp:309
msgid "Block middle"
msgstr "Bloqueig mig"
-#: engines/scumm/help.cpp:300
+#: engines/scumm/help.cpp:310
msgid "Block low"
msgstr "Bloqueig baix"
-#: engines/scumm/help.cpp:301
+#: engines/scumm/help.cpp:311
msgid "Punch high"
msgstr "Puntada alta"
-#: engines/scumm/help.cpp:302
+#: engines/scumm/help.cpp:312
msgid "Punch middle"
msgstr "Puntada mitja"
-#: engines/scumm/help.cpp:303
+#: engines/scumm/help.cpp:313
msgid "Punch low"
msgstr "Puntada baixa"
-#: engines/scumm/help.cpp:306
+#: engines/scumm/help.cpp:315
+msgid "Sucker punch"
+msgstr ""
+
+#: engines/scumm/help.cpp:318
msgid "These are for Indy on left."
msgstr "Aquests sѓn per l'Indy a l'esquerra."
-#: engines/scumm/help.cpp:307
+#: engines/scumm/help.cpp:319
msgid "When Indy is on the right,"
msgstr "Quan l'Indy щs a la dreta,"
-#: engines/scumm/help.cpp:308
+#: engines/scumm/help.cpp:320
msgid "7, 4, and 1 are switched with"
msgstr "el 7, el 4 i l'1 s'intercanvien amb"
-#: engines/scumm/help.cpp:309
+#: engines/scumm/help.cpp:321
msgid "9, 6, and 3, respectively."
msgstr "el 9, el 6 i el 3, respectivament."
-#: engines/scumm/help.cpp:316
+#: engines/scumm/help.cpp:328
msgid "Biplane controls (numpad):"
msgstr "Controls del biplр (teclat numшric):"
-#: engines/scumm/help.cpp:317
+#: engines/scumm/help.cpp:329
msgid "Fly to upper left"
msgstr "Vola amunt i a l'esquerra"
-#: engines/scumm/help.cpp:318
+#: engines/scumm/help.cpp:330
msgid "Fly to left"
msgstr "Vola a l'esquerra"
-#: engines/scumm/help.cpp:319
+#: engines/scumm/help.cpp:331
msgid "Fly to lower left"
msgstr "Vola avall i a l'esquerra"
-#: engines/scumm/help.cpp:320
+#: engines/scumm/help.cpp:332
msgid "Fly upwards"
msgstr "Vola amunt"
-#: engines/scumm/help.cpp:321
+#: engines/scumm/help.cpp:333
msgid "Fly straight"
msgstr "Vola recte"
-#: engines/scumm/help.cpp:322
+#: engines/scumm/help.cpp:334
msgid "Fly down"
msgstr "Vola avall"
-#: engines/scumm/help.cpp:323
+#: engines/scumm/help.cpp:335
msgid "Fly to upper right"
msgstr "Vola amunt i a la dreta"
-#: engines/scumm/help.cpp:324
+#: engines/scumm/help.cpp:336
msgid "Fly to right"
msgstr "Vola a la dreta"
-#: engines/scumm/help.cpp:325
+#: engines/scumm/help.cpp:337
msgid "Fly to lower right"
msgstr "Vola avall i a la dreta"
-#: engines/scumm/scumm.cpp:1823
+#: engines/scumm/scumm.cpp:1832
#, c-format
msgid ""
"Native MIDI support requires the Roland Upgrade from LucasArts,\n"
@@ -3200,11 +3290,12 @@ 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:2594
+#: engines/scumm/scumm.cpp:2644
+#, fuzzy
msgid ""
-"Usually, Maniac Mansion would start now. But ScummVM doesn't do that yet. To "
-"play it, go to 'Add Game' in the ScummVM start menu and select the 'Maniac' "
-"directory inside the Tentacle game directory."
+"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 ""
"Normalment, en aquest punt s'engegaria el Maniac Mansion. Perђ ScummVM no ho "
"fa encara. Per jugar-hi, aneu a 'Afegir joc' al menњ principal de ScummVM i "
@@ -3346,6 +3437,49 @@ msgstr ""
msgid "Show the current number of frames per second in the upper left corner"
msgstr ""
+#: engines/zvision/detection.cpp:256
+msgid "Double FPS"
+msgstr ""
+
+#: engines/zvision/detection.cpp:257
+msgid "Increase game FPS from 30 to 60"
+msgstr ""
+
+#: engines/zvision/detection.cpp:266
+#, fuzzy
+msgid "Enable Venus"
+msgstr "Activa el mode heli"
+
+#: engines/zvision/detection.cpp:267
+msgid "Enable the Venus help system"
+msgstr ""
+
+#: engines/zvision/detection.cpp:276
+msgid "Disable animation while turning"
+msgstr ""
+
+#: engines/zvision/detection.cpp:277
+msgid "Disable animation while turning in panoramic mode"
+msgstr ""
+
+#: engines/zvision/detection.cpp:286
+msgid "Use the hires MPEG movies"
+msgstr ""
+
+#: engines/zvision/detection.cpp:287
+#, fuzzy
+msgid ""
+"Use the hires MPEG movies of the DVD version, instead of the lowres AVI ones"
+msgstr ""
+"Utilitza el conjunt alternatiu de cursors platejats, en lloc dels normals "
+"daurats"
+
+#~ msgid "EGA undithering"
+#~ msgstr "Elimina el tramat d'EGA"
+
+#~ msgid "Enable undithering in EGA games"
+#~ msgstr "Activa l'eliminaciѓ del tramat en els jocs EGA"
+
#, fuzzy
#~ msgid "MPEG-2 cutscenes found but ScummVM has been built without MPEG-2"
#~ msgstr ""
@@ -3356,9 +3490,6 @@ msgstr ""
#~ msgid "Mass Add..."
#~ msgstr "Afegeix Jocs"
-#~ msgid "Mass Add..."
-#~ msgstr "Addiciѓ Massiva..."
-
#~ msgid ""
#~ "Turns off General MIDI mapping for games with Roland MT-32 soundtrack"
#~ msgstr ""
diff --git a/po/cs_CZ.po b/po/cs_CZ.po
index 4832a1f107..1e5ebc3b42 100644
--- a/po/cs_CZ.po
+++ b/po/cs_CZ.po
@@ -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: 2014-10-04 00:58+0100\n"
-"PO-Revision-Date: 2014-02-27 21:43+0100\n"
+"POT-Creation-Date: 2015-07-26 18:48+0200\n"
+"PO-Revision-Date: 2015-07-26 18:51+0200\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.6.4\n"
+"X-Generator: Poedit 1.8.3\n"
"X-Poedit-Basepath: ..\n"
#: gui/about.cpp:94
@@ -56,10 +56,11 @@ msgstr "Jэt nahoru"
#: gui/browser.cpp:75 gui/chooser.cpp:46 gui/KeysDialog.cpp:43
#: gui/launcher.cpp:351 gui/massadd.cpp:95 gui/options.cpp:1239
+#: gui/recorderdialog.cpp:70 gui/recorderdialog.cpp:156
#: gui/saveload-dialog.cpp:216 gui/saveload-dialog.cpp:276
-#: gui/saveload-dialog.cpp:547 gui/saveload-dialog.cpp:922
-#: gui/themebrowser.cpp:55 gui/fluidsynth-dialog.cpp:152
-#: engines/engine.cpp:452 backends/platform/wii/options.cpp:48
+#: 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
#: backends/events/default/default-events.cpp:196
#: backends/events/default/default-events.cpp:218
#: engines/drascula/saveload.cpp:49 engines/parallaction/saveload.cpp:274
@@ -72,9 +73,9 @@ msgid "Choose"
msgstr "Zvolit"
#: gui/gui-manager.cpp:117 backends/keymapper/remap-dialog.cpp:53
-#: 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
+#: 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"
@@ -90,7 +91,7 @@ msgstr "Zobrazit klсvesnici"
msgid "Remap keys"
msgstr "Pјemapovat klсvesy"
-#: gui/gui-manager.cpp:131 base/main.cpp:326 engines/scumm/help.cpp:86
+#: gui/gui-manager.cpp:131 base/main.cpp:326 engines/scumm/help.cpp:87
msgid "Toggle fullscreen"
msgstr "Pјepnout celou obrazovku"
@@ -104,13 +105,13 @@ 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:1240
-#: gui/saveload-dialog.cpp:923 gui/fluidsynth-dialog.cpp:153
-#: engines/engine.cpp:371 engines/engine.cpp:382
+#: 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:399 engines/parallaction/saveload.cpp:274
-#: engines/scumm/dialogs.cpp:193 engines/scumm/scumm.cpp:1825
+#: 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
@@ -478,7 +479,7 @@ msgstr ""
#: gui/launcher.cpp:793 gui/launcher.cpp:941 gui/launcher.cpp:1000
#: gui/fluidsynth-dialog.cpp:217
-#: backends/events/symbiansdl/symbiansdl-events.cpp:184
+#: 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
@@ -488,7 +489,7 @@ 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:184
+#: 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
@@ -524,6 +525,14 @@ msgstr "Tato hra nepodporuje spouЙtьnэ her ze spouЙtьшe"
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
+msgid "Mass Add..."
+msgstr "Hromadnщ Pјidсnэ..."
+
+#: gui/launcher.cpp:1161
+msgid "Record..."
+msgstr "Nahrсt..."
+
#: gui/massadd.cpp:79 gui/massadd.cpp:82
msgid "... progress ..."
msgstr "... prљbьh ..."
@@ -622,7 +631,7 @@ msgid "Special dithering modes supported by some games"
msgstr "Speciсlnэ reОimy chvьnэ podporovanщ nьkter§mi hrami"
#: gui/options.cpp:760
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2249
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2298
msgid "Fullscreen mode"
msgstr "ReОim celщ obrazovky"
@@ -938,6 +947,41 @@ msgstr ""
"Vzhled, kter§ jste zvolili, nepodporuje VсЙ souшasn§ jazyk. Pokud chcete "
"tento vzhled pouОэt, musэte nejdјэve pјepnout na jin§ jazyk."
+#: gui/recorderdialog.cpp:64
+msgid "Recorder or Playback Gameplay"
+msgstr "Nahrсvat nebo pјehrсt hru"
+
+#: gui/recorderdialog.cpp:69 gui/recorderdialog.cpp:156
+#: gui/saveload-dialog.cpp:220 gui/saveload-dialog.cpp:276
+msgid "Delete"
+msgstr "Smazat"
+
+#: gui/recorderdialog.cpp:71
+msgid "Record"
+msgstr "Nahrсt"
+
+#: gui/recorderdialog.cpp:72
+msgid "Playback"
+msgstr "Pјehrсt"
+
+#: gui/recorderdialog.cpp:74
+msgid "Edit"
+msgstr "Upravit"
+
+#: gui/recorderdialog.cpp:86 gui/recorderdialog.cpp:243
+#: gui/recorderdialog.cpp:253
+msgid "Author: "
+msgstr "Autor:"
+
+#: gui/recorderdialog.cpp:87 gui/recorderdialog.cpp:244
+#: gui/recorderdialog.cpp:254
+msgid "Notes: "
+msgstr "Poznсmky:"
+
+#: gui/recorderdialog.cpp:155
+msgid "Do you really want to delete this record?"
+msgstr "Opravdu chcete tento zсznam smazat?"
+
#: gui/saveload-dialog.cpp:167
msgid "List view"
msgstr "Seznam"
@@ -958,23 +1002,19 @@ msgstr "Ўсdn§ uloОen§ шas"
msgid "No playtime saved"
msgstr "Ўсdnс uloОenс doba hranэ"
-#: gui/saveload-dialog.cpp:220 gui/saveload-dialog.cpp:276
-msgid "Delete"
-msgstr "Smazat"
-
#: gui/saveload-dialog.cpp:275
msgid "Do you really want to delete this saved game?"
msgstr "Opravdu chcete tuto uloОenou hru vymazat"
-#: gui/saveload-dialog.cpp:385 gui/saveload-dialog.cpp:875
+#: gui/saveload-dialog.cpp:385 gui/saveload-dialog.cpp:884
msgid "Date: "
msgstr "Datum:"
-#: gui/saveload-dialog.cpp:389 gui/saveload-dialog.cpp:881
+#: gui/saveload-dialog.cpp:389 gui/saveload-dialog.cpp:890
msgid "Time: "
msgstr "Шas:"
-#: gui/saveload-dialog.cpp:395 gui/saveload-dialog.cpp:889
+#: gui/saveload-dialog.cpp:395 gui/saveload-dialog.cpp:898
msgid "Playtime: "
msgstr "Doba hranэ:"
@@ -990,19 +1030,19 @@ msgstr "DalЙэ"
msgid "Prev"
msgstr "Pјedchozэ"
-#: gui/saveload-dialog.cpp:739
+#: gui/saveload-dialog.cpp:748
msgid "New Save"
msgstr "Novс uloОenс pozice"
-#: gui/saveload-dialog.cpp:739
+#: gui/saveload-dialog.cpp:748
msgid "Create a new save game"
msgstr "Vytvoјit novou uloОenou hru."
-#: gui/saveload-dialog.cpp:868
+#: gui/saveload-dialog.cpp:877
msgid "Name: "
msgstr "Nсzev:"
-#: gui/saveload-dialog.cpp:940
+#: gui/saveload-dialog.cpp:949
#, c-format
msgid "Enter a description for slot %d:"
msgstr "Zadejte popis pro pozici %d:"
@@ -1155,7 +1195,7 @@ msgstr "Pјeskoшit јсdek"
msgid "Error running game:"
msgstr "Chyba pјi spuЙtьnэ hry:"
-#: base/main.cpp:536
+#: base/main.cpp:554
msgid "Could not find any engine capable of running the selected game"
msgstr "Nelze nalщzt Осdnщ jсdro schopnщ vybranou hru spustit"
@@ -1272,7 +1312,7 @@ 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:758
+#: engines/pegasus/pegasus.cpp:377 engines/sci/engine/kfile.cpp:759
#: engines/toltecs/menu.cpp:281 engines/tsage/scenes.cpp:598
msgid "Save game:"
msgstr "UloОit hru:"
@@ -1285,7 +1325,7 @@ msgstr "UloОit hru:"
#: 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:758 engines/scumm/dialogs.cpp:188
+#: engines/sci/engine/kfile.cpp:759 engines/scumm/dialogs.cpp:188
#: engines/toltecs/menu.cpp:281 engines/tsage/scenes.cpp:598
msgid "Save"
msgstr "UloОit"
@@ -1323,23 +1363,23 @@ msgstr "~Z~ruЙit"
msgid "~K~eys"
msgstr "~K~lсvesy"
-#: engines/engine.cpp:245
+#: engines/engine.cpp:276
msgid "Could not initialize color format."
msgstr "Nelze zavщst barevn§ formсt."
-#: engines/engine.cpp:253
+#: engines/engine.cpp:284
msgid "Could not switch to video mode: '"
msgstr "Nelze pјepnout na reОim obrazu: '"
-#: engines/engine.cpp:262
+#: engines/engine.cpp:293
msgid "Could not apply aspect ratio setting."
msgstr "Nelze pouОэt nastavenэ pomьru stran."
-#: engines/engine.cpp:267
+#: engines/engine.cpp:298
msgid "Could not apply fullscreen setting."
msgstr "Nelze pouОэt nastavenэ celщ obrazovky."
-#: engines/engine.cpp:367
+#: engines/engine.cpp:398
msgid ""
"You appear to be playing this game directly\n"
"from the CD. This is known to cause problems,\n"
@@ -1353,7 +1393,7 @@ msgstr ""
"datovщ soubory na VсЙ pevn§ disk.\n"
"Pro podrobnosti si pјeшtьte README."
-#: engines/engine.cpp:378
+#: engines/engine.cpp:409
msgid ""
"This game has audio tracks in its disk. These\n"
"tracks need to be ripped from the disk using\n"
@@ -1367,7 +1407,7 @@ msgstr ""
"abyste mohli poslouchat hudbu ve hјe.\n"
"Pro podrobnosti si pјeшtьte README."
-#: engines/engine.cpp:436
+#: engines/engine.cpp:467
#, c-format
msgid ""
"Gamestate load failed (%s)! Please consult the README for basic information, "
@@ -1376,7 +1416,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:449
+#: engines/engine.cpp:480
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 "
@@ -1386,7 +1426,7 @@ 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:452
+#: engines/engine.cpp:483
msgid "Start anyway"
msgstr "Pјesto spustit"
@@ -1596,11 +1636,11 @@ msgstr "Touchpad reОim zapnut"
msgid "Touchpad mode disabled."
msgstr "Touchpad reОim vypnut"
-#: backends/platform/maemo/maemo.cpp:209
+#: backends/platform/maemo/maemo.cpp:208
msgid "Click Mode"
msgstr "ReОim kliknutэ"
-#: backends/platform/maemo/maemo.cpp:215
+#: backends/platform/maemo/maemo.cpp:214
#: backends/platform/symbian/src/SymbianActions.cpp:42
#: backends/platform/wince/CEActionsPocket.cpp:60
#: backends/platform/wince/CEActionsSmartphone.cpp:43
@@ -1608,11 +1648,11 @@ msgstr "ReОim kliknutэ"
msgid "Left Click"
msgstr "Levщ Kliknutэ"
-#: backends/platform/maemo/maemo.cpp:218
+#: backends/platform/maemo/maemo.cpp:217
msgid "Middle Click"
msgstr "Kliknutэ prostјednэm tlaшэtkem"
-#: backends/platform/maemo/maemo.cpp:221
+#: 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
@@ -1649,19 +1689,19 @@ msgctxt "lowres"
msgid "Normal (no scaling)"
msgstr "Normсlnэ (bez zmьny velikosti)"
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2148
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2197
msgid "Enabled aspect ratio correction"
msgstr "Povolena korekce pomьru stran"
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2154
+#: 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:2209
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2258
msgid "Active graphics filter:"
msgstr "Aktivnэ grafick§ filtr:"
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2251
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2300
msgid "Windowed mode"
msgstr "ReОim do okna"
@@ -1719,9 +1759,8 @@ 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:82
-#: engines/scumm/help.cpp:84
+#: 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"
@@ -1741,7 +1780,7 @@ msgstr "Virtuсlnэ klсvesnice"
msgid "Key mapper"
msgstr "Mapovaш klсves"
-#: backends/events/symbiansdl/symbiansdl-events.cpp:184
+#: backends/events/symbiansdl/symbiansdl-events.cpp:186
msgid "Do you want to quit ?"
msgstr "Chcete ukonшit ?"
@@ -1994,7 +2033,7 @@ msgstr ""
#: backends/events/default/default-events.cpp:196
msgid "Do you really want to return to the Launcher?"
-msgstr "Opravdu se chcete vrсtit tuto do SpouЙtьшe?"
+msgstr "Opravdu se chcete vrсtit do SpouЙtьшe?"
#: backends/events/default/default-events.cpp:196
msgid "Launcher"
@@ -2078,33 +2117,56 @@ msgstr "Kliknutэ Povoleno"
msgid "Clicking Disabled"
msgstr "Kliknutэ Zakсzсno"
-#: engines/agi/detection.cpp:142 engines/drascula/detection.cpp:302
+#: 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.cpp:103
+#: engines/zvision/detection.cpp:246
msgid "Use original save/load screens"
msgstr "PouОэt pљvodnэ obrazovky naшtenэ/uloОenэ"
-#: engines/agi/detection.cpp:143 engines/drascula/detection.cpp:303
+#: 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/zvision/detection.cpp:104
+#: engines/zvision/detection.cpp:247
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"
+#: engines/agi/detection.cpp:157
+msgid "Use an alternative palette"
+msgstr "PouОэt jinou paletu"
+
+#: engines/agi/detection.cpp:158
+msgid ""
+"Use an alternative palette, common for all Amiga games. This was the old "
+"behavior"
+msgstr ""
+"PouОэt alternativnэ paletu, bьОnщ pro hry Amiga. Toto byl pљvodnэ star§ "
+"standard"
+
+#: engines/agi/detection.cpp:167
+msgid "Mouse support"
+msgstr "Podpora myЙi"
+
+#: engines/agi/detection.cpp:168
+msgid ""
+"Enables mouse support. Allows to use mouse for movement and in game menus."
+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:857 engines/toltecs/menu.cpp:256
+#: engines/sci/engine/kfile.cpp:858 engines/toltecs/menu.cpp:256
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:857 engines/toltecs/menu.cpp:256
+#: engines/sci/engine/kfile.cpp:858 engines/toltecs/menu.cpp:256
msgid "Restore"
msgstr "Obnovit"
-#: engines/agos/saveload.cpp:160 engines/scumm/scumm.cpp:2368
+#: engines/agos/saveload.cpp:160 engines/scumm/scumm.cpp:2377
#, c-format
msgid ""
"Failed to load game state from file:\n"
@@ -2115,7 +2177,7 @@ msgstr ""
"\n"
"%s"
-#: engines/agos/saveload.cpp:195 engines/scumm/scumm.cpp:2361
+#: engines/agos/saveload.cpp:195 engines/scumm/scumm.cpp:2370
#, c-format
msgid ""
"Failed to save game state to file:\n"
@@ -2126,7 +2188,7 @@ msgstr ""
"\n"
"%s"
-#: engines/agos/saveload.cpp:203 engines/scumm/scumm.cpp:2379
+#: engines/agos/saveload.cpp:203 engines/scumm/scumm.cpp:2388
#, c-format
msgid ""
"Successfully saved game state in file:\n"
@@ -2142,14 +2204,13 @@ msgstr ""
msgid "Cutscene file '%s' not found!"
msgstr "Soubor videa '%s' nenalezen'"
-#: engines/cge/detection.cpp:105 engines/cge2/detection.cpp:81
-#, fuzzy
+#: engines/cge/detection.cpp:105 engines/cge2/detection.cpp:101
msgid "Color Blind Mode"
-msgstr "ReОim kliknutэ"
+msgstr "ReОim pro barvoslepщ"
-#: engines/cge/detection.cpp:106 engines/cge2/detection.cpp:82
+#: engines/cge/detection.cpp:106 engines/cge2/detection.cpp:102
msgid "Enable Color Blind Mode by default"
-msgstr ""
+msgstr "Standardnь zapэnat reОim pro barvoslepщ"
#: engines/drascula/saveload.cpp:47
msgid ""
@@ -2199,17 +2260,17 @@ 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:399
+#: engines/groovie/script.cpp:408
msgid "Failed to save game"
msgstr "Nelze uloОit hru."
#: engines/hopkins/detection.cpp:76 engines/hopkins/detection.cpp:86
msgid "Gore Mode"
-msgstr ""
+msgstr "Povolit nсsilnщ scщny"
#: engines/hopkins/detection.cpp:77 engines/hopkins/detection.cpp:87
msgid "Enable Gore Mode when available"
-msgstr ""
+msgstr "Povolit nсsilnщ scщny, jsou-li dostupnщ"
#. I18N: Studio audience adds an applause and cheering sounds whenever
#. Malcolm makes a joke.
@@ -2341,6 +2402,12 @@ msgid ""
"Do you wish to use this save game file with ScummVM?\n"
"\n"
msgstr ""
+"V cestь vaЙэ hry byl nalezen nсsledujэcэ soubor s uloОenou hrou:\n"
+"\n"
+"%s %s\n"
+"\n"
+"Chcete tento soubor pouОэt v ScummVM?\n"
+"\n"
#: engines/kyra/saveload_eob.cpp:590
#, c-format
@@ -2348,6 +2415,8 @@ msgid ""
"A save game file was found in the specified slot %d. Overwrite?\n"
"\n"
msgstr ""
+"V urшenщ pozici %d byl nalezen soubor s uloОenou hrou. Pјepsat?\n"
+"\n"
#: engines/kyra/saveload_eob.cpp:623
#, c-format
@@ -2359,6 +2428,10 @@ msgid ""
"'import_savefile'.\n"
"\n"
msgstr ""
+"%d pљvodnэch souborљ s uloОenou hrou bylo њspьЙnь importovсno do\n"
+"ScummVM. Pokud chcete pozdьji toto uшinit znovu ruшnь, je tјeba otevјэt\n"
+"ladэcэ konzoli ScummVM a pouОэt pјэkaz 'import_savefile'.\n"
+"\n"
#. I18N: Option for fast scene switching
#: engines/mohawk/dialogs.cpp:92 engines/mohawk/dialogs.cpp:167
@@ -2496,12 +2569,13 @@ msgid "Use an alternative game intro (CD version only)"
msgstr "PouОэt jinou verzi њvodu (Pouze verze CD)"
#: engines/sci/detection.cpp:374
-msgid "EGA undithering"
-msgstr "Nerozklсdсnэ EGA"
+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
-msgid "Enable undithering in EGA games"
-msgstr "Povolit nerozklсdсnэ v EGA hrсch"
+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
msgid "Prefer digital sound effects"
@@ -2572,12 +2646,12 @@ msgstr "Hra Pozastavena. Stisknьte MEZERNЭK pro pokraшovсnэ."
#. "Moechten Sie wirklich neu starten? (J/N)J"
#. Will react to J as 'Yes'
#: engines/scumm/dialogs.cpp:183
-msgid "Are you sure you want to restart? (Y/N)"
+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
-msgid "Are you sure you want to quit? (Y/N)"
+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
@@ -2665,516 +2739,540 @@ msgstr "Cviшenэ"
msgid "Expert"
msgstr "Pokroшil§"
-#: engines/scumm/help.cpp:73
+#: engines/scumm/help.cpp:74
msgid "Common keyboard commands:"
msgstr "BьОnщ klсvesovщ pјэkazy"
-#: engines/scumm/help.cpp:74
+#: engines/scumm/help.cpp:75
msgid "Save / Load dialog"
msgstr "Dialog Nahrсt / UloОit"
-#: engines/scumm/help.cpp:76
+#: engines/scumm/help.cpp:77
msgid "Skip line of text"
msgstr "Pјeskoшit јсdek textu"
-#: engines/scumm/help.cpp:77
+#: engines/scumm/help.cpp:78
msgid "Esc"
msgstr "Mezernэk"
-#: engines/scumm/help.cpp:77
+#: engines/scumm/help.cpp:78
msgid "Skip cutscene"
msgstr "Pјeskoшit video"
-#: engines/scumm/help.cpp:78
+#: engines/scumm/help.cpp:79
msgid "Space"
msgstr "Mezernэk"
-#: engines/scumm/help.cpp:78
+#: engines/scumm/help.cpp:79
msgid "Pause game"
msgstr "Pozastavit hru"
-#: engines/scumm/help.cpp:79 engines/scumm/help.cpp:84
-#: engines/scumm/help.cpp:95 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: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:79
+#: engines/scumm/help.cpp:80
msgid "Load game state 1-10"
msgstr "Nahrсt stav hry 1-10"
-#: engines/scumm/help.cpp:80 engines/scumm/help.cpp:84
-#: engines/scumm/help.cpp:86 engines/scumm/help.cpp:100
-#: engines/scumm/help.cpp:101 engines/scumm/help.cpp:102
+#: 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:80
+#: engines/scumm/help.cpp:81
msgid "Save game state 1-10"
msgstr "UloОit stav hry 1-10"
-#: engines/scumm/help.cpp:86 engines/scumm/help.cpp:89
+#: engines/scumm/help.cpp:87 engines/scumm/help.cpp:90
msgid "Enter"
msgstr "Enter"
-#: engines/scumm/help.cpp:87
+#: engines/scumm/help.cpp:88
msgid "Music volume up / down"
msgstr "Hlasitost hudby nahoru / dolљ"
-#: engines/scumm/help.cpp:88
+#: engines/scumm/help.cpp:89
msgid "Text speed slower / faster"
msgstr "Zv§Йit / SnэОit rychlost textu"
-#: engines/scumm/help.cpp:89
+#: engines/scumm/help.cpp:90
msgid "Simulate left mouse button"
msgstr "Napodobit levщ tlaшэtko myЙi"
-#: engines/scumm/help.cpp:90
+#: engines/scumm/help.cpp:91
msgid "Tab"
msgstr "Tab"
-#: engines/scumm/help.cpp:90
+#: engines/scumm/help.cpp:91
msgid "Simulate right mouse button"
msgstr "Napodobit pravщ tlaшэtko myЙi"
-#: engines/scumm/help.cpp:93
+#: engines/scumm/help.cpp:94
msgid "Special keyboard commands:"
msgstr "Speciсlnэ klсvesovщ pјэkazy"
-#: engines/scumm/help.cpp:94
+#: engines/scumm/help.cpp:95
msgid "Show / Hide console"
msgstr "Ukсzat / Skr§t konzoli"
-#: engines/scumm/help.cpp:95
+#: engines/scumm/help.cpp:96
msgid "Start the debugger"
msgstr "Spustit ladэcэ program"
-#: engines/scumm/help.cpp:96
+#: engines/scumm/help.cpp:97
msgid "Show memory consumption"
msgstr "Zobrazit spotјebu pamьti"
-#: engines/scumm/help.cpp:97
+#: engines/scumm/help.cpp:98
msgid "Run in fast mode (*)"
msgstr "Spustit v rychlщm reОimu (*)"
-#: engines/scumm/help.cpp:98
+#: engines/scumm/help.cpp:99
msgid "Run in really fast mode (*)"
msgstr "Spustit ve velmi rychlщm reОimu (*)"
-#: engines/scumm/help.cpp:99
+#: engines/scumm/help.cpp:100
msgid "Toggle mouse capture"
msgstr "Povolit zachycovсnэ myЙi"
-#: engines/scumm/help.cpp:100
+#: engines/scumm/help.cpp:101
msgid "Switch between graphics filters"
msgstr "Pјepэnat mezi grafick§mi filtry"
-#: engines/scumm/help.cpp:101
+#: engines/scumm/help.cpp:102
msgid "Increase / Decrease scale factor"
msgstr "ZvьtЙit / ZmenЙit faktor zmьny velikosti"
-#: engines/scumm/help.cpp:102
+#: engines/scumm/help.cpp:103
msgid "Toggle aspect-ratio correction"
msgstr "Povolit korekci pomьru stran"
-#: engines/scumm/help.cpp:107
+#: engines/scumm/help.cpp:108
msgid "* Note that using ctrl-f and"
msgstr "Upozorђujeme, Оe pouОэvсnэ ctrl-f a"
-#: engines/scumm/help.cpp:108
+#: engines/scumm/help.cpp:109
msgid " ctrl-g are not recommended"
msgstr " ctrl-g nenэ doporuшeno"
-#: engines/scumm/help.cpp:109
+#: engines/scumm/help.cpp:110
msgid " since they may cause crashes"
msgstr "jelikoО mљОou zpљsobit pсd"
-#: engines/scumm/help.cpp:110
+#: engines/scumm/help.cpp:111
msgid " or incorrect game behavior."
msgstr " nebo nesprсvnщ chovсnэ hry."
-#: engines/scumm/help.cpp:114
+#: engines/scumm/help.cpp:115
msgid "Spinning drafts on the keyboard:"
msgstr "Pletenэ nсшrtkљ na klсvesnici:"
-#: engines/scumm/help.cpp:116
+#: engines/scumm/help.cpp:117
msgid "Main game controls:"
msgstr "Hlavnэ ovlсdacэ prvky:"
-#: engines/scumm/help.cpp:121 engines/scumm/help.cpp:136
-#: engines/scumm/help.cpp:161
+#: engines/scumm/help.cpp:122 engines/scumm/help.cpp:137
+#: engines/scumm/help.cpp:162
msgid "Push"
msgstr "Tlaшit"
-#: engines/scumm/help.cpp:122 engines/scumm/help.cpp:137
-#: engines/scumm/help.cpp:162
+#: engines/scumm/help.cpp:123 engines/scumm/help.cpp:138
+#: engines/scumm/help.cpp:163
msgid "Pull"
msgstr "Tсhnout"
-#: engines/scumm/help.cpp:123 engines/scumm/help.cpp:138
-#: engines/scumm/help.cpp:163 engines/scumm/help.cpp:197
-#: engines/scumm/help.cpp:207
+#: 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 "Dсt"
-#: engines/scumm/help.cpp:124 engines/scumm/help.cpp:139
-#: engines/scumm/help.cpp:164 engines/scumm/help.cpp:190
-#: engines/scumm/help.cpp:208
+#: 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 "Otevјэt"
-#: engines/scumm/help.cpp:126
+#: engines/scumm/help.cpp:127
msgid "Go to"
msgstr "Jэt do"
-#: engines/scumm/help.cpp:127
+#: engines/scumm/help.cpp:128
msgid "Get"
msgstr "Vzэt"
-#: engines/scumm/help.cpp:128 engines/scumm/help.cpp:152
-#: engines/scumm/help.cpp:170 engines/scumm/help.cpp:198
-#: engines/scumm/help.cpp:213 engines/scumm/help.cpp:224
-#: engines/scumm/help.cpp:250
+#: 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 "PouОэt"
-#: engines/scumm/help.cpp:129 engines/scumm/help.cpp:141
+#: engines/scumm/help.cpp:130 engines/scumm/help.cpp:142
msgid "Read"
msgstr "Pјeшэst"
-#: engines/scumm/help.cpp:130 engines/scumm/help.cpp:147
+#: engines/scumm/help.cpp:131 engines/scumm/help.cpp:148
msgid "New kid"
msgstr "Novщ dэtь"
-#: engines/scumm/help.cpp:131 engines/scumm/help.cpp:153
-#: engines/scumm/help.cpp:171
+#: engines/scumm/help.cpp:132 engines/scumm/help.cpp:154
+#: engines/scumm/help.cpp:172
msgid "Turn on"
msgstr "Zapnout"
-#: engines/scumm/help.cpp:132 engines/scumm/help.cpp:154
-#: engines/scumm/help.cpp:172
+#: engines/scumm/help.cpp:133 engines/scumm/help.cpp:155
+#: engines/scumm/help.cpp:173
msgid "Turn off"
msgstr "Vypnout"
-#: engines/scumm/help.cpp:142 engines/scumm/help.cpp:167
-#: engines/scumm/help.cpp:194
+#: engines/scumm/help.cpp:143 engines/scumm/help.cpp:168
+#: engines/scumm/help.cpp:195
msgid "Walk to"
msgstr "Pјejэt na"
-#: engines/scumm/help.cpp:143 engines/scumm/help.cpp:168
-#: engines/scumm/help.cpp:195 engines/scumm/help.cpp:210
-#: engines/scumm/help.cpp:227
+#: 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 "Sebrat"
-#: engines/scumm/help.cpp:144 engines/scumm/help.cpp:169
+#: engines/scumm/help.cpp:145 engines/scumm/help.cpp:170
msgid "What is"
msgstr "Co je"
-#: engines/scumm/help.cpp:146
+#: engines/scumm/help.cpp:147
msgid "Unlock"
msgstr "Odemknout"
-#: engines/scumm/help.cpp:149
+#: engines/scumm/help.cpp:150
msgid "Put on"
msgstr "Oblщct"
-#: engines/scumm/help.cpp:150
+#: engines/scumm/help.cpp:151
msgid "Take off"
msgstr "Svlщct"
-#: engines/scumm/help.cpp:156
+#: engines/scumm/help.cpp:157
msgid "Fix"
msgstr "Spravit"
-#: engines/scumm/help.cpp:158
+#: engines/scumm/help.cpp:159
msgid "Switch"
msgstr "Pјepnout"
-#: engines/scumm/help.cpp:166 engines/scumm/help.cpp:228
+#: engines/scumm/help.cpp:167 engines/scumm/help.cpp:229
msgid "Look"
msgstr "Dэvat se"
-#: engines/scumm/help.cpp:173 engines/scumm/help.cpp:223
+#: engines/scumm/help.cpp:174 engines/scumm/help.cpp:224
msgid "Talk"
msgstr "Mluvit"
-#: engines/scumm/help.cpp:174
+#: engines/scumm/help.cpp:175
msgid "Travel"
msgstr "Cestovat"
-#: engines/scumm/help.cpp:175
+#: engines/scumm/help.cpp:176
msgid "To Henry / To Indy"
msgstr "Henrymu / Indymu"
#. I18N: These are different musical notes
-#: engines/scumm/help.cpp:179
+#: engines/scumm/help.cpp:180
msgid "play C minor on distaff"
msgstr "zahrсt c moll na pјeslici"
-#: engines/scumm/help.cpp:180
+#: engines/scumm/help.cpp:181
msgid "play D on distaff"
msgstr "zahrсt D na pјeslici"
-#: engines/scumm/help.cpp:181
+#: engines/scumm/help.cpp:182
msgid "play E on distaff"
msgstr "zahrсt E na pјeslici"
-#: engines/scumm/help.cpp:182
+#: engines/scumm/help.cpp:183
msgid "play F on distaff"
msgstr "zahrсt F na pјeslici"
-#: engines/scumm/help.cpp:183
+#: engines/scumm/help.cpp:184
msgid "play G on distaff"
msgstr "zahrсt G na pјeslici"
-#: engines/scumm/help.cpp:184
+#: engines/scumm/help.cpp:185
msgid "play A on distaff"
msgstr "zahrсt A na pјeslici"
-#: engines/scumm/help.cpp:185
+#: engines/scumm/help.cpp:186
msgid "play B on distaff"
msgstr "zahrсt B na pјeslici"
-#: engines/scumm/help.cpp:186
+#: engines/scumm/help.cpp:187
msgid "play C major on distaff"
msgstr "zahrсt C dur na pјeslici"
-#: engines/scumm/help.cpp:192 engines/scumm/help.cpp:214
+#: engines/scumm/help.cpp:193 engines/scumm/help.cpp:215
msgid "puSh"
msgstr "tlaшIt"
-#: engines/scumm/help.cpp:193 engines/scumm/help.cpp:215
+#: engines/scumm/help.cpp:194 engines/scumm/help.cpp:216
msgid "pull (Yank)"
msgstr "tсhnout (Љkubnout)"
-#: engines/scumm/help.cpp:196 engines/scumm/help.cpp:212
-#: engines/scumm/help.cpp:248
+#: engines/scumm/help.cpp:197 engines/scumm/help.cpp:213
+#: engines/scumm/help.cpp:249
msgid "Talk to"
msgstr "Mluvit s"
-#: engines/scumm/help.cpp:199 engines/scumm/help.cpp:211
+#: engines/scumm/help.cpp:200 engines/scumm/help.cpp:212
msgid "Look at"
msgstr "Dэvat se na"
-#: engines/scumm/help.cpp:200
+#: engines/scumm/help.cpp:201
msgid "turn oN"
msgstr "zapnouT"
-#: engines/scumm/help.cpp:201
+#: engines/scumm/help.cpp:202
msgid "turn oFf"
msgstr "vypnoUt"
-#: engines/scumm/help.cpp:217
+#: engines/scumm/help.cpp:218
msgid "KeyUp"
msgstr "KlсvesaNahoru"
-#: engines/scumm/help.cpp:217
+#: engines/scumm/help.cpp:218
msgid "Highlight prev dialogue"
msgstr "Zv§raznit pјedchozэ dialog"
-#: engines/scumm/help.cpp:218
+#: engines/scumm/help.cpp:219
msgid "KeyDown"
msgstr "KlсvesaDolљ"
-#: engines/scumm/help.cpp:218
+#: engines/scumm/help.cpp:219
msgid "Highlight next dialogue"
msgstr "Zv§raznit nсsledujэcэ dialog"
-#: engines/scumm/help.cpp:222
+#: engines/scumm/help.cpp:223
msgid "Walk"
msgstr "Jэt"
-#: engines/scumm/help.cpp:225 engines/scumm/help.cpp:234
-#: engines/scumm/help.cpp:241 engines/scumm/help.cpp:249
+#: engines/scumm/help.cpp:226 engines/scumm/help.cpp:235
+#: engines/scumm/help.cpp:242 engines/scumm/help.cpp:250
msgid "Inventory"
msgstr "Inventсј"
-#: engines/scumm/help.cpp:226
+#: engines/scumm/help.cpp:227
msgid "Object"
msgstr "Objekt"
-#: engines/scumm/help.cpp:229
+#: engines/scumm/help.cpp:230
msgid "Black and White / Color"
msgstr "Шernobэlщ / Barva"
-#: engines/scumm/help.cpp:232
+#: engines/scumm/help.cpp:233
msgid "Eyes"
msgstr "Oшi"
-#: engines/scumm/help.cpp:233
+#: engines/scumm/help.cpp:234
msgid "Tongue"
msgstr "Jazyk"
-#: engines/scumm/help.cpp:235
+#: engines/scumm/help.cpp:236
msgid "Punch"
msgstr "Udeјit"
-#: engines/scumm/help.cpp:236
+#: engines/scumm/help.cpp:237
msgid "Kick"
msgstr "Kopnout"
-#: engines/scumm/help.cpp:239 engines/scumm/help.cpp:247
+#: engines/scumm/help.cpp:240 engines/scumm/help.cpp:248
msgid "Examine"
msgstr "Prohlщdnout"
-#: engines/scumm/help.cpp:240
+#: engines/scumm/help.cpp:241
msgid "Regular cursor"
msgstr "Obyшejn§ kurzor"
#. I18N: Comm is a communication device
-#: engines/scumm/help.cpp:243
+#: engines/scumm/help.cpp:244
msgid "Comm"
msgstr "Komunikace"
-#: engines/scumm/help.cpp:246
+#: engines/scumm/help.cpp:247
msgid "Save / Load / Options"
msgstr "UloОit / Nahrсt / Volby"
-#: engines/scumm/help.cpp:255
+#: engines/scumm/help.cpp:256
msgid "Other game controls:"
msgstr "DalЙэ ovlсdacэ prvky hry"
-#: engines/scumm/help.cpp:257 engines/scumm/help.cpp:267
+#: engines/scumm/help.cpp:258 engines/scumm/help.cpp:268
msgid "Inventory:"
msgstr "Inventсј:"
-#: engines/scumm/help.cpp:258 engines/scumm/help.cpp:274
+#: engines/scumm/help.cpp:259 engines/scumm/help.cpp:275
msgid "Scroll list up"
msgstr "Posunout seznam nahoru"
-#: engines/scumm/help.cpp:259 engines/scumm/help.cpp:275
+#: engines/scumm/help.cpp:260 engines/scumm/help.cpp:276
msgid "Scroll list down"
msgstr "Posunout seznam dolu"
-#: engines/scumm/help.cpp:260 engines/scumm/help.cpp:268
+#: engines/scumm/help.cpp:261 engines/scumm/help.cpp:269
msgid "Upper left item"
msgstr "PoloОka vlevo nahoјe"
-#: engines/scumm/help.cpp:261 engines/scumm/help.cpp:270
+#: engines/scumm/help.cpp:262 engines/scumm/help.cpp:271
msgid "Lower left item"
msgstr "PoloОka vlevo dole"
-#: engines/scumm/help.cpp:262 engines/scumm/help.cpp:271
+#: engines/scumm/help.cpp:263 engines/scumm/help.cpp:272
msgid "Upper right item"
msgstr "PoloОka vpravo nahoјe"
-#: engines/scumm/help.cpp:263 engines/scumm/help.cpp:273
+#: engines/scumm/help.cpp:264 engines/scumm/help.cpp:274
msgid "Lower right item"
msgstr "PoloОka vpravo dole"
-#: engines/scumm/help.cpp:269
+#: engines/scumm/help.cpp:270
msgid "Middle left item"
msgstr "PoloОka vlevo uprostјed"
-#: engines/scumm/help.cpp:272
+#: engines/scumm/help.cpp:273
msgid "Middle right item"
msgstr "PoloОka vpravo uprostјed"
-#: engines/scumm/help.cpp:279 engines/scumm/help.cpp:284
+#: engines/scumm/help.cpp:280 engines/scumm/help.cpp:285
msgid "Switching characters:"
msgstr "Mьnьnэ postav:"
-#: engines/scumm/help.cpp:281
+#: engines/scumm/help.cpp:282
msgid "Second kid"
msgstr "Druhщ dэtь"
-#: engines/scumm/help.cpp:282
+#: engines/scumm/help.cpp:283
msgid "Third kid"
msgstr "Tјetэ dэtь"
-#: engines/scumm/help.cpp:294
+#: engines/scumm/help.cpp:292
+msgid "Toggle Inventory/IQ Points display"
+msgstr "Pјepэnat zobrazenэ inventсјe/chytrostnэch bodљ"
+
+#: engines/scumm/help.cpp:293
+msgid "Toggle Keyboard/Mouse Fighting (*)"
+msgstr "Pјepэnat bojovсnэ pomocэ klсves/myЙi (*)"
+
+#: engines/scumm/help.cpp:295
+msgid "* Keyboard Fighting is always on,"
+msgstr "* Bojovсnэ pomocэ klсvesnice je vОdy zapnuto,"
+
+#: engines/scumm/help.cpp:296
+msgid " so despite the in-game message this"
+msgstr " takОe nehledь a to, co јэkс hra,"
+
+#: engines/scumm/help.cpp:297
+msgid " actually toggles Mouse Fighting Off/On"
+msgstr " toto ve skuteшnosti ovlсdс bojovсnэ s myЙэ"
+
+#: engines/scumm/help.cpp:304
msgid "Fighting controls (numpad):"
msgstr "Ovlсdсnэ boje (num. klсv.)"
-#: engines/scumm/help.cpp:295 engines/scumm/help.cpp:296
-#: engines/scumm/help.cpp:297
+#: engines/scumm/help.cpp:305 engines/scumm/help.cpp:306
+#: engines/scumm/help.cpp:307
msgid "Step back"
msgstr "Ustoupit"
-#: engines/scumm/help.cpp:298
+#: engines/scumm/help.cpp:308
msgid "Block high"
msgstr "Brсnit nahoјe"
-#: engines/scumm/help.cpp:299
+#: engines/scumm/help.cpp:309
msgid "Block middle"
msgstr "Brсnit uprostјed"
-#: engines/scumm/help.cpp:300
+#: engines/scumm/help.cpp:310
msgid "Block low"
msgstr "Brсnit dole"
-#: engines/scumm/help.cpp:301
+#: engines/scumm/help.cpp:311
msgid "Punch high"
msgstr "Udeјit nahoru"
-#: engines/scumm/help.cpp:302
+#: engines/scumm/help.cpp:312
msgid "Punch middle"
msgstr "Udeјit doprostјed"
-#: engines/scumm/help.cpp:303
+#: engines/scumm/help.cpp:313
msgid "Punch low"
msgstr "Udeјit dolљ"
-#: engines/scumm/help.cpp:306
+#: engines/scumm/help.cpp:315
+msgid "Sucker punch"
+msgstr "Neшekanс rсna"
+
+#: engines/scumm/help.cpp:318
msgid "These are for Indy on left."
msgstr "Tyto jsou pro Indyho nalevo."
-#: engines/scumm/help.cpp:307
+#: engines/scumm/help.cpp:319
msgid "When Indy is on the right,"
msgstr "KdyО je Indy napravo,"
-#: engines/scumm/help.cpp:308
+#: engines/scumm/help.cpp:320
msgid "7, 4, and 1 are switched with"
-msgstr "71 4 a 1 jsou zamьnьny s"
+msgstr "7, 4 a 1 jsou zamьnьny s"
-#: engines/scumm/help.cpp:309
+#: engines/scumm/help.cpp:321
msgid "9, 6, and 3, respectively."
msgstr "9, 6 a 3, v tomto poјadэ."
-#: engines/scumm/help.cpp:316
+#: engines/scumm/help.cpp:328
msgid "Biplane controls (numpad):"
msgstr "Kontrola dvojploЙnэku (numerickс klсvesnice)"
-#: engines/scumm/help.cpp:317
+#: engines/scumm/help.cpp:329
msgid "Fly to upper left"
msgstr "Letьt doprava nahoru"
-#: engines/scumm/help.cpp:318
+#: engines/scumm/help.cpp:330
msgid "Fly to left"
msgstr "Letьt doleva"
-#: engines/scumm/help.cpp:319
+#: engines/scumm/help.cpp:331
msgid "Fly to lower left"
msgstr "Letьt doleva dolљ"
-#: engines/scumm/help.cpp:320
+#: engines/scumm/help.cpp:332
msgid "Fly upwards"
msgstr "Letьt nahoru"
-#: engines/scumm/help.cpp:321
+#: engines/scumm/help.cpp:333
msgid "Fly straight"
msgstr "Letьt rovnь"
-#: engines/scumm/help.cpp:322
+#: engines/scumm/help.cpp:334
msgid "Fly down"
msgstr "Letьt dolљ"
-#: engines/scumm/help.cpp:323
+#: engines/scumm/help.cpp:335
msgid "Fly to upper right"
msgstr "Letьt doprava nahoru"
-#: engines/scumm/help.cpp:324
+#: engines/scumm/help.cpp:336
msgid "Fly to right"
msgstr "Letьt doprava"
-#: engines/scumm/help.cpp:325
+#: engines/scumm/help.cpp:337
msgid "Fly to lower right"
msgstr "Letьt doprava dolљ"
-#: engines/scumm/scumm.cpp:1823
+#: engines/scumm/scumm.cpp:1832
#, c-format
msgid ""
"Native MIDI support requires the Roland Upgrade from LucasArts,\n"
@@ -3183,27 +3281,31 @@ 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:2594
+#: engines/scumm/scumm.cpp:2644
msgid ""
-"Usually, Maniac Mansion would start now. But ScummVM doesn't do that yet. To "
-"play it, go to 'Add Game' in the ScummVM start menu and select the 'Maniac' "
-"directory inside the Tentacle game directory."
+"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 ""
-"Normсlnь by teя Maniac Mansion byl spuЙtьn. Ale ScummVM toto zatэm nedьlс. "
-"Abyste toto mohli hrсt, pјejdьte do 'Pјidat Hru' v poшсteшnэm menu ScummVM a "
-"vyberte adresсј 'Maniac' uvnitј hernэho adresсјe Tentacle."
+"Normсlnь by teя byl spuЙtьn Maniac Mansion. Ale aby toto mohlo fungovat, "
+"musэ b§t soubory se hrou umэstьny do sloОky 'Maniac' uvnitј sloОky se hrou "
+"Tentacle a hra musэ b§t pјidсna 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 ""
+"Nelze najэt spustiteln§ soubor 'Loom' pro Macintosh z jehoО\n"
+"majэ b§t naшteny hudebnэ nсstroje. Hudba bude zakсzсna."
#: 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 ""
+"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/sky/compact.cpp:130
msgid ""
@@ -3315,11 +3417,67 @@ msgstr ""
#: engines/wintermute/detection.cpp:58
msgid "Show FPS-counter"
-msgstr ""
+msgstr "Zobrazit poшэtadlo FPS"
#: engines/wintermute/detection.cpp:59
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.cpp:256
+msgid "Double FPS"
+msgstr "Dvojitщ snэmky za sekundu"
+
+#: engines/zvision/detection.cpp:257
+msgid "Increase game FPS from 30 to 60"
+msgstr "Zv§Йit hernэ snэmky za sekundu z 30 na 60"
+
+#: engines/zvision/detection.cpp:266
+msgid "Enable Venus"
+msgstr "Povolit Venus"
+
+#: engines/zvision/detection.cpp:267
+msgid "Enable the Venus help system"
+msgstr "Povolit systщm nсpovьdy Venus"
+
+#: engines/zvision/detection.cpp:276
+msgid "Disable animation while turning"
+msgstr "Zakсzat animaci pјi otсшenэ"
+
+#: engines/zvision/detection.cpp:277
+msgid "Disable animation while turning in panoramic mode"
+msgstr "Zakсzat animaci pјi otсшenэ v panoramatickщm reОimu"
+
+#: engines/zvision/detection.cpp:286
+msgid "Use the hires MPEG movies"
+msgstr "PouОэt videa MPEG ve vysokщm rozliЙenэ"
+
+#: engines/zvision/detection.cpp:287
+msgid ""
+"Use the hires MPEG movies of the DVD version, instead of the lowres AVI ones"
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э."
+
+#~ msgid "EGA undithering"
+#~ msgstr "Nerozklсdсnэ EGA"
+
+#~ msgid "Enable undithering in EGA games"
+#~ msgstr "Povolit nerozklсdсnэ v EGA hrсch"
+
+#~ msgid "Are you sure you want to restart? (Y/N)"
+#~ msgstr "Jste si jisti, Оe chcete restartovat? (A/N)A"
+
+#~ msgid "Are you sure you want to quit? (Y/N)"
+#~ msgstr "Jste si jisti, Оe chcete odejэt? (A/N)A"
+
+#~ msgid ""
+#~ "Usually, Maniac Mansion would start now. But ScummVM doesn't do that yet. "
+#~ "To play it, go to 'Add Game' in the ScummVM start menu and select the "
+#~ "'Maniac' directory inside the Tentacle game directory."
+#~ msgstr ""
+#~ "Normсlnь by teя Maniac Mansion byl spuЙtьn. Ale ScummVM toto zatэm "
+#~ "nedьlс. Abyste toto mohli hrсt, pјejdьte do 'Pјidat Hru' v poшсteшnэm "
+#~ "menu ScummVM a vyberte adresсј 'Maniac' uvnitј hernэho adresсјe Tentacle."
#~ msgid "MPEG-2 cutscenes found but ScummVM has been built without MPEG-2"
#~ msgstr "Videa MPEG-2 nalezena, ale ScummVM byl sestaven bez MPEG-2"
@@ -3328,9 +3486,6 @@ msgstr ""
#~ msgid "Mass Add..."
#~ msgstr "Hromadnщ Pјidсnэ..."
-#~ msgid "Mass Add..."
-#~ msgstr "Hromadnщ Pјidсnэ..."
-
#~ msgid ""
#~ "Turns off General MIDI mapping for games with Roland MT-32 soundtrack"
#~ msgstr ""
diff --git a/po/da_DA.po b/po/da_DA.po
index 554694f66d..82760de5d8 100644
--- a/po/da_DA.po
+++ b/po/da_DA.po
@@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: ScummVM 1.3.0svn\n"
"Report-Msgid-Bugs-To: scummvm-devel@lists.sf.net\n"
-"POT-Creation-Date: 2014-10-04 00:58+0100\n"
+"POT-Creation-Date: 2015-06-30 20:57+0100\n"
"PO-Revision-Date: 2014-07-09 17:34+0100\n"
"Last-Translator: Steffen Nyeland <steffen@nyeland.dk>\n"
"Language-Team: Steffen Nyeland <steffen@nyeland.dk>\n"
@@ -54,10 +54,11 @@ msgstr "Gх op"
#: gui/browser.cpp:75 gui/chooser.cpp:46 gui/KeysDialog.cpp:43
#: gui/launcher.cpp:351 gui/massadd.cpp:95 gui/options.cpp:1239
+#: gui/recorderdialog.cpp:70 gui/recorderdialog.cpp:156
#: gui/saveload-dialog.cpp:216 gui/saveload-dialog.cpp:276
-#: gui/saveload-dialog.cpp:547 gui/saveload-dialog.cpp:922
+#: gui/saveload-dialog.cpp:547 gui/saveload-dialog.cpp:931
#: gui/themebrowser.cpp:55 gui/fluidsynth-dialog.cpp:152
-#: engines/engine.cpp:452 backends/platform/wii/options.cpp:48
+#: engines/engine.cpp:483 backends/platform/wii/options.cpp:48
#: backends/events/default/default-events.cpp:196
#: backends/events/default/default-events.cpp:218
#: engines/drascula/saveload.cpp:49 engines/parallaction/saveload.cpp:274
@@ -70,9 +71,9 @@ msgid "Choose"
msgstr "Vцlg"
#: gui/gui-manager.cpp:117 backends/keymapper/remap-dialog.cpp:53
-#: 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
+#: 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"
@@ -88,7 +89,7 @@ msgstr "Vis tastatur"
msgid "Remap keys"
msgstr "Kortlцg taster"
-#: gui/gui-manager.cpp:131 base/main.cpp:326 engines/scumm/help.cpp:86
+#: gui/gui-manager.cpp:131 base/main.cpp:326 engines/scumm/help.cpp:87
msgid "Toggle fullscreen"
msgstr "Skift fuldskцrm"
@@ -102,13 +103,13 @@ 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:1240
-#: gui/saveload-dialog.cpp:923 gui/fluidsynth-dialog.cpp:153
-#: engines/engine.cpp:371 engines/engine.cpp:382
+#: 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:399 engines/parallaction/saveload.cpp:274
-#: engines/scumm/dialogs.cpp:193 engines/scumm/scumm.cpp:1825
+#: 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
@@ -478,7 +479,7 @@ msgstr ""
#: gui/launcher.cpp:793 gui/launcher.cpp:941 gui/launcher.cpp:1000
#: gui/fluidsynth-dialog.cpp:217
-#: backends/events/symbiansdl/symbiansdl-events.cpp:184
+#: 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
@@ -488,7 +489,7 @@ 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:184
+#: 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
@@ -525,6 +526,14 @@ 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
+msgid "Mass Add..."
+msgstr "Tilfјj flere..."
+
+#: gui/launcher.cpp:1161
+msgid "Record..."
+msgstr ""
+
#: gui/massadd.cpp:79 gui/massadd.cpp:82
msgid "... progress ..."
msgstr "... fremskridt ..."
@@ -623,7 +632,7 @@ msgid "Special dithering modes supported by some games"
msgstr "Speciel farvereduceringstilstand understјttet a nogle spil"
#: gui/options.cpp:760
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2249
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2298
msgid "Fullscreen mode"
msgstr "Fuldskцrms tilstand"
@@ -937,6 +946,43 @@ msgstr ""
"Temaet du valgte understјtter ikke dit aktuelle sprog. Hvis du јnsker at "
"bruge dette tema, skal du skifte til et andet sprog fјrst."
+#: gui/recorderdialog.cpp:64
+msgid "Recorder or Playback Gameplay"
+msgstr ""
+
+#: gui/recorderdialog.cpp:69 gui/recorderdialog.cpp:156
+#: gui/saveload-dialog.cpp:220 gui/saveload-dialog.cpp:276
+msgid "Delete"
+msgstr "Slet"
+
+#: gui/recorderdialog.cpp:71
+msgid "Record"
+msgstr ""
+
+#: gui/recorderdialog.cpp:72
+#, fuzzy
+msgid "Playback"
+msgstr "Spil"
+
+#: gui/recorderdialog.cpp:74
+msgid "Edit"
+msgstr ""
+
+#: gui/recorderdialog.cpp:86 gui/recorderdialog.cpp:243
+#: gui/recorderdialog.cpp:253
+msgid "Author: "
+msgstr ""
+
+#: gui/recorderdialog.cpp:87 gui/recorderdialog.cpp:244
+#: gui/recorderdialog.cpp:254
+msgid "Notes: "
+msgstr ""
+
+#: gui/recorderdialog.cpp:155
+#, fuzzy
+msgid "Do you really want to delete this record?"
+msgstr "Vil du virkelig slette denne gemmer?"
+
#: gui/saveload-dialog.cpp:167
msgid "List view"
msgstr "Liste visning"
@@ -957,23 +1003,19 @@ msgstr "Intet tidspunkt gemt"
msgid "No playtime saved"
msgstr "Ingen spilletid gemt"
-#: gui/saveload-dialog.cpp:220 gui/saveload-dialog.cpp:276
-msgid "Delete"
-msgstr "Slet"
-
#: gui/saveload-dialog.cpp:275
msgid "Do you really want to delete this saved game?"
msgstr "Vil du virkelig slette denne gemmer?"
-#: gui/saveload-dialog.cpp:385 gui/saveload-dialog.cpp:875
+#: gui/saveload-dialog.cpp:385 gui/saveload-dialog.cpp:884
msgid "Date: "
msgstr "Dato:"
-#: gui/saveload-dialog.cpp:389 gui/saveload-dialog.cpp:881
+#: gui/saveload-dialog.cpp:389 gui/saveload-dialog.cpp:890
msgid "Time: "
msgstr "Tid:"
-#: gui/saveload-dialog.cpp:395 gui/saveload-dialog.cpp:889
+#: gui/saveload-dialog.cpp:395 gui/saveload-dialog.cpp:898
msgid "Playtime: "
msgstr "Spilletid:"
@@ -989,19 +1031,19 @@ msgstr "Nцste"
msgid "Prev"
msgstr "Forrige"
-#: gui/saveload-dialog.cpp:739
+#: gui/saveload-dialog.cpp:748
msgid "New Save"
msgstr "Ny Gemmer"
-#: gui/saveload-dialog.cpp:739
+#: gui/saveload-dialog.cpp:748
msgid "Create a new save game"
msgstr "Opret en ny gemmer"
-#: gui/saveload-dialog.cpp:868
+#: gui/saveload-dialog.cpp:877
msgid "Name: "
msgstr "Navn:"
-#: gui/saveload-dialog.cpp:940
+#: gui/saveload-dialog.cpp:949
#, c-format
msgid "Enter a description for slot %d:"
msgstr "Indtast en beskrivelse af plads %d:"
@@ -1154,7 +1196,7 @@ msgstr "Spring linje over"
msgid "Error running game:"
msgstr "Fejl ved kјrsel af spil:"
-#: base/main.cpp:536
+#: base/main.cpp:554
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"
@@ -1272,7 +1314,7 @@ 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:758
+#: engines/pegasus/pegasus.cpp:377 engines/sci/engine/kfile.cpp:759
#: engines/toltecs/menu.cpp:281 engines/tsage/scenes.cpp:598
msgid "Save game:"
msgstr "Gemmer:"
@@ -1285,7 +1327,7 @@ msgstr "Gemmer:"
#: 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:758 engines/scumm/dialogs.cpp:188
+#: engines/sci/engine/kfile.cpp:759 engines/scumm/dialogs.cpp:188
#: engines/toltecs/menu.cpp:281 engines/tsage/scenes.cpp:598
msgid "Save"
msgstr "Gem"
@@ -1323,23 +1365,23 @@ msgstr "~F~ortryd"
msgid "~K~eys"
msgstr "~T~aster"
-#: engines/engine.cpp:245
+#: engines/engine.cpp:276
msgid "Could not initialize color format."
msgstr "Kunne ikke initialisere farveformat."
-#: engines/engine.cpp:253
+#: engines/engine.cpp:284
msgid "Could not switch to video mode: '"
msgstr "Kunne ikke skifte til videotilstand: '"
-#: engines/engine.cpp:262
+#: engines/engine.cpp:293
msgid "Could not apply aspect ratio setting."
msgstr "Kunne ikke anvende billedformat korrektion indstilling."
-#: engines/engine.cpp:267
+#: engines/engine.cpp:298
msgid "Could not apply fullscreen setting."
msgstr "Kunne ikke anvende fuldskцrm indstilling."
-#: engines/engine.cpp:367
+#: engines/engine.cpp:398
msgid ""
"You appear to be playing this game directly\n"
"from the CD. This is known to cause problems,\n"
@@ -1353,7 +1395,7 @@ msgstr ""
"datafiler til din harddisk i stedet.\n"
"Se README fil for detaljer."
-#: engines/engine.cpp:378
+#: engines/engine.cpp:409
msgid ""
"This game has audio tracks in its disk. These\n"
"tracks need to be ripped from the disk using\n"
@@ -1367,7 +1409,7 @@ msgstr ""
"for at lytte til spillets musik.\n"
"Se README fil for detaljer."
-#: engines/engine.cpp:436
+#: engines/engine.cpp:467
#, c-format
msgid ""
"Gamestate load failed (%s)! Please consult the README for basic information, "
@@ -1377,7 +1419,7 @@ msgstr ""
"grundlцggende oplysninger, og for at fх instruktioner om, hvordan man fхr "
"yderligere hjцlp."
-#: engines/engine.cpp:449
+#: engines/engine.cpp:480
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 "
@@ -1387,7 +1429,7 @@ 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:452
+#: engines/engine.cpp:483
msgid "Start anyway"
msgstr "Start alligevel"
@@ -1596,11 +1638,11 @@ msgstr "Pegeplade tilstand aktiveret."
msgid "Touchpad mode disabled."
msgstr "Pegeplade tilstand deaktiveret."
-#: backends/platform/maemo/maemo.cpp:209
+#: backends/platform/maemo/maemo.cpp:208
msgid "Click Mode"
msgstr "Klik tilstand"
-#: backends/platform/maemo/maemo.cpp:215
+#: backends/platform/maemo/maemo.cpp:214
#: backends/platform/symbian/src/SymbianActions.cpp:42
#: backends/platform/wince/CEActionsPocket.cpp:60
#: backends/platform/wince/CEActionsSmartphone.cpp:43
@@ -1608,11 +1650,11 @@ msgstr "Klik tilstand"
msgid "Left Click"
msgstr "Venstre klik"
-#: backends/platform/maemo/maemo.cpp:218
+#: backends/platform/maemo/maemo.cpp:217
msgid "Middle Click"
msgstr "Miderste klik"
-#: backends/platform/maemo/maemo.cpp:221
+#: 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
@@ -1649,19 +1691,19 @@ msgctxt "lowres"
msgid "Normal (no scaling)"
msgstr "Normal (ingen skalering)"
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2148
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2197
msgid "Enabled aspect ratio correction"
msgstr "Aktivщr billedformat korrektion"
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2154
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2203
msgid "Disabled aspect ratio correction"
msgstr "Deaktivщr billedformat korrektion"
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2209
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2258
msgid "Active graphics filter:"
msgstr "Aktive grafik filtre:"
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2251
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2300
msgid "Windowed mode"
msgstr "Vindue tilstand"
@@ -1720,8 +1762,8 @@ msgstr "Hurtig tilstand"
#: 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:82
-#: engines/scumm/help.cpp:84
+#: engines/scumm/dialogs.cpp:192 engines/scumm/help.cpp:83
+#: engines/scumm/help.cpp:85
msgid "Quit"
msgstr "Afslut"
@@ -1741,7 +1783,7 @@ msgstr "Virtuelt tastatur"
msgid "Key mapper"
msgstr "Tastetildeling"
-#: backends/events/symbiansdl/symbiansdl-events.cpp:184
+#: backends/events/symbiansdl/symbiansdl-events.cpp:186
msgid "Do you want to quit ?"
msgstr "Vil du afslutte?"
@@ -2077,33 +2119,54 @@ msgstr "Klik aktiveret"
msgid "Clicking Disabled"
msgstr "Klik deaktiveret"
-#: engines/agi/detection.cpp:142 engines/drascula/detection.cpp:302
+#: 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.cpp:103
+#: engines/zvision/detection.cpp:246
msgid "Use original save/load screens"
msgstr "Brug original gem/indlцs skцrme"
-#: engines/agi/detection.cpp:143 engines/drascula/detection.cpp:303
+#: 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/zvision/detection.cpp:104
+#: engines/zvision/detection.cpp:247
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)"
+
+#: engines/agi/detection.cpp:158
+msgid ""
+"Use an alternative palette, common for all Amiga games. This was the old "
+"behavior"
+msgstr ""
+
+#: engines/agi/detection.cpp:167
+#, fuzzy
+msgid "Mouse support"
+msgstr "Spring over stј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:857 engines/toltecs/menu.cpp:256
+#: engines/sci/engine/kfile.cpp:858 engines/toltecs/menu.cpp:256
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:857 engines/toltecs/menu.cpp:256
+#: engines/sci/engine/kfile.cpp:858 engines/toltecs/menu.cpp:256
msgid "Restore"
msgstr "Gendan"
-#: engines/agos/saveload.cpp:160 engines/scumm/scumm.cpp:2368
+#: engines/agos/saveload.cpp:160 engines/scumm/scumm.cpp:2377
#, c-format
msgid ""
"Failed to load game state from file:\n"
@@ -2114,7 +2177,7 @@ msgstr ""
"\n"
"%s"
-#: engines/agos/saveload.cpp:195 engines/scumm/scumm.cpp:2361
+#: engines/agos/saveload.cpp:195 engines/scumm/scumm.cpp:2370
#, c-format
msgid ""
"Failed to save game state to file:\n"
@@ -2125,7 +2188,7 @@ msgstr ""
"\n"
"%s"
-#: engines/agos/saveload.cpp:203 engines/scumm/scumm.cpp:2379
+#: engines/agos/saveload.cpp:203 engines/scumm/scumm.cpp:2388
#, c-format
msgid ""
"Successfully saved game state in file:\n"
@@ -2141,12 +2204,12 @@ msgstr ""
msgid "Cutscene file '%s' not found!"
msgstr "Filmsekvens fil '%s' ikke fundet!"
-#: engines/cge/detection.cpp:105 engines/cge2/detection.cpp:81
+#: engines/cge/detection.cpp:105 engines/cge2/detection.cpp:101
#, fuzzy
msgid "Color Blind Mode"
msgstr "Klik tilstand"
-#: engines/cge/detection.cpp:106 engines/cge2/detection.cpp:82
+#: engines/cge/detection.cpp:106 engines/cge2/detection.cpp:102
msgid "Enable Color Blind Mode by default"
msgstr ""
@@ -2198,7 +2261,7 @@ msgstr "Hurtig film hastighed"
msgid "Play movies at an increased speed"
msgstr "Afspil film med forhјjet hastighed"
-#: engines/groovie/script.cpp:399
+#: engines/groovie/script.cpp:408
msgid "Failed to save game"
msgstr "Mislykkedes at gemme spil"
@@ -2497,12 +2560,12 @@ msgid "Use an alternative game intro (CD version only)"
msgstr "Brug en alternativ spil intro (kun CD version)"
#: engines/sci/detection.cpp:374
-msgid "EGA undithering"
-msgstr "EGA farveforјgelse"
+msgid "Skip EGA dithering pass (full color backgrounds)"
+msgstr ""
#: engines/sci/detection.cpp:375
-msgid "Enable undithering in EGA games"
-msgstr "Aktiver farveforјgelse i EGA spil"
+msgid "Skip dithering pass in EGA games, graphics are shown with full colors"
+msgstr ""
#: engines/sci/detection.cpp:384
msgid "Prefer digital sound effects"
@@ -2574,12 +2637,14 @@ msgstr "Spil sat pх pause. Tryk MELLEMRUM for at fortsцtte."
#. "Moechten Sie wirklich neu starten? (J/N)J"
#. Will react to J as 'Yes'
#: engines/scumm/dialogs.cpp:183
-msgid "Are you sure you want to restart? (Y/N)"
+#, fuzzy
+msgid "Are you sure you want to restart? (Y/N)Y"
msgstr "Er du sikker pх at du vil genstarte? (J/N) "
#. I18N: you may specify 'Yes' symbol at the end of the line. See previous comment
#: engines/scumm/dialogs.cpp:185
-msgid "Are you sure you want to quit? (Y/N)"
+#, fuzzy
+msgid "Are you sure you want to quit? (Y/N)Y"
msgstr "Er du sikker pх at du vil afslutte? (J/N) "
#: engines/scumm/dialogs.cpp:190
@@ -2667,516 +2732,541 @@ msgstr "Trцning"
msgid "Expert"
msgstr "Ekspert"
-#: engines/scumm/help.cpp:73
+#: engines/scumm/help.cpp:74
msgid "Common keyboard commands:"
msgstr "Almindelige tastatur kommandoer:"
-#: engines/scumm/help.cpp:74
+#: engines/scumm/help.cpp:75
msgid "Save / Load dialog"
msgstr "Gem / Indlцs dialog"
-#: engines/scumm/help.cpp:76
+#: engines/scumm/help.cpp:77
msgid "Skip line of text"
msgstr "Spring tekstlinje over"
-#: engines/scumm/help.cpp:77
+#: engines/scumm/help.cpp:78
msgid "Esc"
msgstr "Esc"
-#: engines/scumm/help.cpp:77
+#: engines/scumm/help.cpp:78
msgid "Skip cutscene"
msgstr "Spring mellemscene over"
-#: engines/scumm/help.cpp:78
+#: engines/scumm/help.cpp:79
msgid "Space"
msgstr "Mellemrum"
-#: engines/scumm/help.cpp:78
+#: engines/scumm/help.cpp:79
msgid "Pause game"
msgstr "Pause spil"
-#: engines/scumm/help.cpp:79 engines/scumm/help.cpp:84
-#: engines/scumm/help.cpp:95 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: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:79
+#: engines/scumm/help.cpp:80
msgid "Load game state 1-10"
msgstr "Indlцs spil tilstand 1-10"
-#: engines/scumm/help.cpp:80 engines/scumm/help.cpp:84
-#: engines/scumm/help.cpp:86 engines/scumm/help.cpp:100
-#: engines/scumm/help.cpp:101 engines/scumm/help.cpp:102
+#: 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:80
+#: engines/scumm/help.cpp:81
msgid "Save game state 1-10"
msgstr "Gem spil tilstand 1-10"
-#: engines/scumm/help.cpp:86 engines/scumm/help.cpp:89
+#: engines/scumm/help.cpp:87 engines/scumm/help.cpp:90
msgid "Enter"
msgstr "Enter"
-#: engines/scumm/help.cpp:87
+#: engines/scumm/help.cpp:88
msgid "Music volume up / down"
msgstr "Musik lydstyrke op / ned"
-#: engines/scumm/help.cpp:88
+#: engines/scumm/help.cpp:89
msgid "Text speed slower / faster"
msgstr "Tekst hastighed langsommere / hurtigere"
-#: engines/scumm/help.cpp:89
+#: engines/scumm/help.cpp:90
msgid "Simulate left mouse button"
msgstr "Simulere venstre museknap"
-#: engines/scumm/help.cpp:90
+#: engines/scumm/help.cpp:91
msgid "Tab"
msgstr "Tab"
-#: engines/scumm/help.cpp:90
+#: engines/scumm/help.cpp:91
msgid "Simulate right mouse button"
msgstr "Simulere hјjre museknap"
-#: engines/scumm/help.cpp:93
+#: engines/scumm/help.cpp:94
msgid "Special keyboard commands:"
msgstr "Specielle tastatur kommandoer:"
-#: engines/scumm/help.cpp:94
+#: engines/scumm/help.cpp:95
msgid "Show / Hide console"
msgstr "Vis / Skjul konsol"
-#: engines/scumm/help.cpp:95
+#: engines/scumm/help.cpp:96
msgid "Start the debugger"
msgstr "Start fejlfinder"
-#: engines/scumm/help.cpp:96
+#: engines/scumm/help.cpp:97
msgid "Show memory consumption"
msgstr "Vis hukommelsesforbrug"
-#: engines/scumm/help.cpp:97
+#: engines/scumm/help.cpp:98
msgid "Run in fast mode (*)"
msgstr "Kјr i hurtig tilstand (*)"
-#: engines/scumm/help.cpp:98
+#: engines/scumm/help.cpp:99
msgid "Run in really fast mode (*)"
msgstr "Kјr i meget hurtig tilstand (*)"
-#: engines/scumm/help.cpp:99
+#: engines/scumm/help.cpp:100
msgid "Toggle mouse capture"
msgstr "Skift muse fanger"
-#: engines/scumm/help.cpp:100
+#: engines/scumm/help.cpp:101
msgid "Switch between graphics filters"
msgstr "Skift mellem grafik filtre"
-#: engines/scumm/help.cpp:101
+#: engines/scumm/help.cpp:102
msgid "Increase / Decrease scale factor"
msgstr "Hцv / Sцnk skaleringsfaktor"
-#: engines/scumm/help.cpp:102
+#: engines/scumm/help.cpp:103
msgid "Toggle aspect-ratio correction"
msgstr "Skift billedformat korrektion"
-#: engines/scumm/help.cpp:107
+#: engines/scumm/help.cpp:108
msgid "* Note that using ctrl-f and"
msgstr "* Bemцrk at brug af ctrl-f og"
-#: engines/scumm/help.cpp:108
+#: engines/scumm/help.cpp:109
msgid " ctrl-g are not recommended"
msgstr " ctrl-g ikke kan ikke anbefales"
-#: engines/scumm/help.cpp:109
+#: engines/scumm/help.cpp:110
msgid " since they may cause crashes"
msgstr " siden de kan skabe nedbrud"
-#: engines/scumm/help.cpp:110
+#: engines/scumm/help.cpp:111
msgid " or incorrect game behavior."
msgstr " eller ukorrekt opfјrsel af spil."
-#: engines/scumm/help.cpp:114
+#: engines/scumm/help.cpp:115
msgid "Spinning drafts on the keyboard:"
msgstr "Spind ordspil pх tastaturet:"
-#: engines/scumm/help.cpp:116
+#: engines/scumm/help.cpp:117
msgid "Main game controls:"
msgstr "Vigtigste spilstyring:"
-#: engines/scumm/help.cpp:121 engines/scumm/help.cpp:136
-#: engines/scumm/help.cpp:161
+#: engines/scumm/help.cpp:122 engines/scumm/help.cpp:137
+#: engines/scumm/help.cpp:162
msgid "Push"
msgstr "Skub"
-#: engines/scumm/help.cpp:122 engines/scumm/help.cpp:137
-#: engines/scumm/help.cpp:162
+#: engines/scumm/help.cpp:123 engines/scumm/help.cpp:138
+#: engines/scumm/help.cpp:163
msgid "Pull"
msgstr "Trцk"
-#: engines/scumm/help.cpp:123 engines/scumm/help.cpp:138
-#: engines/scumm/help.cpp:163 engines/scumm/help.cpp:197
-#: engines/scumm/help.cpp:207
+#: 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 "Giv"
-#: engines/scumm/help.cpp:124 engines/scumm/help.cpp:139
-#: engines/scumm/help.cpp:164 engines/scumm/help.cpp:190
-#: engines/scumm/help.cpp:208
+#: 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 "Хbn"
-#: engines/scumm/help.cpp:126
+#: engines/scumm/help.cpp:127
msgid "Go to"
msgstr "Gх til"
-#: engines/scumm/help.cpp:127
+#: engines/scumm/help.cpp:128
msgid "Get"
msgstr "Tag"
-#: engines/scumm/help.cpp:128 engines/scumm/help.cpp:152
-#: engines/scumm/help.cpp:170 engines/scumm/help.cpp:198
-#: engines/scumm/help.cpp:213 engines/scumm/help.cpp:224
-#: engines/scumm/help.cpp:250
+#: 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 "Brug"
-#: engines/scumm/help.cpp:129 engines/scumm/help.cpp:141
+#: engines/scumm/help.cpp:130 engines/scumm/help.cpp:142
msgid "Read"
msgstr "Lцs"
-#: engines/scumm/help.cpp:130 engines/scumm/help.cpp:147
+#: engines/scumm/help.cpp:131 engines/scumm/help.cpp:148
msgid "New kid"
msgstr "Nyt barn"
-#: engines/scumm/help.cpp:131 engines/scumm/help.cpp:153
-#: engines/scumm/help.cpp:171
+#: engines/scumm/help.cpp:132 engines/scumm/help.cpp:154
+#: engines/scumm/help.cpp:172
msgid "Turn on"
msgstr "Tцnd"
-#: engines/scumm/help.cpp:132 engines/scumm/help.cpp:154
-#: engines/scumm/help.cpp:172
+#: engines/scumm/help.cpp:133 engines/scumm/help.cpp:155
+#: engines/scumm/help.cpp:173
msgid "Turn off"
msgstr "Sluk"
-#: engines/scumm/help.cpp:142 engines/scumm/help.cpp:167
-#: engines/scumm/help.cpp:194
+#: engines/scumm/help.cpp:143 engines/scumm/help.cpp:168
+#: engines/scumm/help.cpp:195
msgid "Walk to"
msgstr "Gх til"
-#: engines/scumm/help.cpp:143 engines/scumm/help.cpp:168
-#: engines/scumm/help.cpp:195 engines/scumm/help.cpp:210
-#: engines/scumm/help.cpp:227
+#: 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 "Tag op"
-#: engines/scumm/help.cpp:144 engines/scumm/help.cpp:169
+#: engines/scumm/help.cpp:145 engines/scumm/help.cpp:170
msgid "What is"
msgstr "Hvad er"
-#: engines/scumm/help.cpp:146
+#: engines/scumm/help.cpp:147
msgid "Unlock"
msgstr "Lхs op"
-#: engines/scumm/help.cpp:149
+#: engines/scumm/help.cpp:150
msgid "Put on"
msgstr "Tag pх"
-#: engines/scumm/help.cpp:150
+#: engines/scumm/help.cpp:151
msgid "Take off"
msgstr "Tag af"
-#: engines/scumm/help.cpp:156
+#: engines/scumm/help.cpp:157
msgid "Fix"
msgstr "Lav"
-#: engines/scumm/help.cpp:158
+#: engines/scumm/help.cpp:159
msgid "Switch"
msgstr "Skift"
-#: engines/scumm/help.cpp:166 engines/scumm/help.cpp:228
+#: engines/scumm/help.cpp:167 engines/scumm/help.cpp:229
msgid "Look"
msgstr "Se"
-#: engines/scumm/help.cpp:173 engines/scumm/help.cpp:223
+#: engines/scumm/help.cpp:174 engines/scumm/help.cpp:224
msgid "Talk"
msgstr "Tal"
-#: engines/scumm/help.cpp:174
+#: engines/scumm/help.cpp:175
msgid "Travel"
msgstr "Rejs"
-#: engines/scumm/help.cpp:175
+#: engines/scumm/help.cpp:176
msgid "To Henry / To Indy"
msgstr "Til Henry / Til Indy"
#. I18N: These are different musical notes
-#: engines/scumm/help.cpp:179
+#: engines/scumm/help.cpp:180
msgid "play C minor on distaff"
msgstr "spil C-mol pх rok"
-#: engines/scumm/help.cpp:180
+#: engines/scumm/help.cpp:181
msgid "play D on distaff"
msgstr "spil D pх rok"
-#: engines/scumm/help.cpp:181
+#: engines/scumm/help.cpp:182
msgid "play E on distaff"
msgstr "spil E pх rok"
-#: engines/scumm/help.cpp:182
+#: engines/scumm/help.cpp:183
msgid "play F on distaff"
msgstr "spil F pх rok"
-#: engines/scumm/help.cpp:183
+#: engines/scumm/help.cpp:184
msgid "play G on distaff"
msgstr "spil G pх rok"
-#: engines/scumm/help.cpp:184
+#: engines/scumm/help.cpp:185
msgid "play A on distaff"
msgstr "spil A pх rok"
-#: engines/scumm/help.cpp:185
+#: engines/scumm/help.cpp:186
msgid "play B on distaff"
msgstr "spil H pх rok"
-#: engines/scumm/help.cpp:186
+#: engines/scumm/help.cpp:187
msgid "play C major on distaff"
msgstr "spil C-dur pх rok"
-#: engines/scumm/help.cpp:192 engines/scumm/help.cpp:214
+#: engines/scumm/help.cpp:193 engines/scumm/help.cpp:215
msgid "puSh"
msgstr "Skub"
-#: engines/scumm/help.cpp:193 engines/scumm/help.cpp:215
+#: engines/scumm/help.cpp:194 engines/scumm/help.cpp:216
msgid "pull (Yank)"
msgstr "trцk (Y)"
-#: engines/scumm/help.cpp:196 engines/scumm/help.cpp:212
-#: engines/scumm/help.cpp:248
+#: engines/scumm/help.cpp:197 engines/scumm/help.cpp:213
+#: engines/scumm/help.cpp:249
msgid "Talk to"
msgstr "Tal til"
-#: engines/scumm/help.cpp:199 engines/scumm/help.cpp:211
+#: engines/scumm/help.cpp:200 engines/scumm/help.cpp:212
msgid "Look at"
msgstr "Lur pх"
-#: engines/scumm/help.cpp:200
+#: engines/scumm/help.cpp:201
msgid "turn oN"
msgstr "tцNd"
-#: engines/scumm/help.cpp:201
+#: engines/scumm/help.cpp:202
msgid "turn oFf"
msgstr "sluk (F)"
-#: engines/scumm/help.cpp:217
+#: engines/scumm/help.cpp:218
msgid "KeyUp"
msgstr "TastOp"
-#: engines/scumm/help.cpp:217
+#: engines/scumm/help.cpp:218
msgid "Highlight prev dialogue"
msgstr "Fremhцv forrige dialog"
-#: engines/scumm/help.cpp:218
+#: engines/scumm/help.cpp:219
msgid "KeyDown"
msgstr "TastNed"
-#: engines/scumm/help.cpp:218
+#: engines/scumm/help.cpp:219
msgid "Highlight next dialogue"
msgstr "Fremhцv nцste dialog"
-#: engines/scumm/help.cpp:222
+#: engines/scumm/help.cpp:223
msgid "Walk"
msgstr "Gх"
-#: engines/scumm/help.cpp:225 engines/scumm/help.cpp:234
-#: engines/scumm/help.cpp:241 engines/scumm/help.cpp:249
+#: engines/scumm/help.cpp:226 engines/scumm/help.cpp:235
+#: engines/scumm/help.cpp:242 engines/scumm/help.cpp:250
msgid "Inventory"
msgstr "Oversigt"
-#: engines/scumm/help.cpp:226
+#: engines/scumm/help.cpp:227
msgid "Object"
msgstr "Objekt"
-#: engines/scumm/help.cpp:229
+#: engines/scumm/help.cpp:230
msgid "Black and White / Color"
msgstr "Sort og hvid / Farve"
-#: engines/scumm/help.cpp:232
+#: engines/scumm/help.cpp:233
msgid "Eyes"
msgstr "иjne"
-#: engines/scumm/help.cpp:233
+#: engines/scumm/help.cpp:234
msgid "Tongue"
msgstr "Tunge"
-#: engines/scumm/help.cpp:235
+#: engines/scumm/help.cpp:236
msgid "Punch"
msgstr "Slag"
-#: engines/scumm/help.cpp:236
+#: engines/scumm/help.cpp:237
msgid "Kick"
msgstr "Spark"
-#: engines/scumm/help.cpp:239 engines/scumm/help.cpp:247
+#: engines/scumm/help.cpp:240 engines/scumm/help.cpp:248
msgid "Examine"
msgstr "Undersјg"
-#: engines/scumm/help.cpp:240
+#: engines/scumm/help.cpp:241
msgid "Regular cursor"
msgstr "Normal markјr"
#. I18N: Comm is a communication device
-#: engines/scumm/help.cpp:243
+#: engines/scumm/help.cpp:244
msgid "Comm"
msgstr "Komm"
-#: engines/scumm/help.cpp:246
+#: engines/scumm/help.cpp:247
msgid "Save / Load / Options"
msgstr "Gem / Indlцs / Indstillinger"
-#: engines/scumm/help.cpp:255
+#: engines/scumm/help.cpp:256
msgid "Other game controls:"
msgstr "Andre spil kontroller"
-#: engines/scumm/help.cpp:257 engines/scumm/help.cpp:267
+#: engines/scumm/help.cpp:258 engines/scumm/help.cpp:268
msgid "Inventory:"
msgstr "Oversigt:"
-#: engines/scumm/help.cpp:258 engines/scumm/help.cpp:274
+#: engines/scumm/help.cpp:259 engines/scumm/help.cpp:275
msgid "Scroll list up"
msgstr "Rul liste op"
-#: engines/scumm/help.cpp:259 engines/scumm/help.cpp:275
+#: engines/scumm/help.cpp:260 engines/scumm/help.cpp:276
msgid "Scroll list down"
msgstr "Rul liste ned"
-#: engines/scumm/help.cpp:260 engines/scumm/help.cpp:268
+#: engines/scumm/help.cpp:261 engines/scumm/help.cpp:269
msgid "Upper left item"
msgstr "иverste venstre punkt"
-#: engines/scumm/help.cpp:261 engines/scumm/help.cpp:270
+#: engines/scumm/help.cpp:262 engines/scumm/help.cpp:271
msgid "Lower left item"
msgstr "Nederste hјjre punkt"
-#: engines/scumm/help.cpp:262 engines/scumm/help.cpp:271
+#: engines/scumm/help.cpp:263 engines/scumm/help.cpp:272
msgid "Upper right item"
msgstr "иverste hјjre punkt"
-#: engines/scumm/help.cpp:263 engines/scumm/help.cpp:273
+#: engines/scumm/help.cpp:264 engines/scumm/help.cpp:274
msgid "Lower right item"
msgstr "Nederste venstre punkt"
-#: engines/scumm/help.cpp:269
+#: engines/scumm/help.cpp:270
msgid "Middle left item"
msgstr "Midterste hјjre punkt"
-#: engines/scumm/help.cpp:272
+#: engines/scumm/help.cpp:273
msgid "Middle right item"
msgstr "Midterste hјjre punkt"
-#: engines/scumm/help.cpp:279 engines/scumm/help.cpp:284
+#: engines/scumm/help.cpp:280 engines/scumm/help.cpp:285
msgid "Switching characters:"
msgstr "Skift personer:"
-#: engines/scumm/help.cpp:281
+#: engines/scumm/help.cpp:282
msgid "Second kid"
msgstr "Andet barn"
-#: engines/scumm/help.cpp:282
+#: engines/scumm/help.cpp:283
msgid "Third kid"
msgstr "Tredie barn"
-#: engines/scumm/help.cpp:294
+#: engines/scumm/help.cpp:292
+#, fuzzy
+msgid "Toggle Inventory/IQ Points display"
+msgstr "Skift Center Data Display"
+
+#: engines/scumm/help.cpp:293
+msgid "Toggle Keyboard/Mouse Fighting (*)"
+msgstr ""
+
+#: engines/scumm/help.cpp:295
+msgid "* Keyboard Fighting is always on,"
+msgstr ""
+
+#: engines/scumm/help.cpp:296
+msgid " so despite the in-game message this"
+msgstr ""
+
+#: engines/scumm/help.cpp:297
+msgid " actually toggles Mouse Fighting Off/On"
+msgstr ""
+
+#: engines/scumm/help.cpp:304
msgid "Fighting controls (numpad):"
msgstr "Kamp kontroller (numtast):"
-#: engines/scumm/help.cpp:295 engines/scumm/help.cpp:296
-#: engines/scumm/help.cpp:297
+#: engines/scumm/help.cpp:305 engines/scumm/help.cpp:306
+#: engines/scumm/help.cpp:307
msgid "Step back"
msgstr "Skridt tilbage"
-#: engines/scumm/help.cpp:298
+#: engines/scumm/help.cpp:308
msgid "Block high"
msgstr "Blokщr hјjt"
-#: engines/scumm/help.cpp:299
+#: engines/scumm/help.cpp:309
msgid "Block middle"
msgstr "Blokщr midtfor"
-#: engines/scumm/help.cpp:300
+#: engines/scumm/help.cpp:310
msgid "Block low"
msgstr "Blokщr lavt"
-#: engines/scumm/help.cpp:301
+#: engines/scumm/help.cpp:311
msgid "Punch high"
msgstr "Slх hјjt"
-#: engines/scumm/help.cpp:302
+#: engines/scumm/help.cpp:312
msgid "Punch middle"
msgstr "Slх midtfor"
-#: engines/scumm/help.cpp:303
+#: engines/scumm/help.cpp:313
msgid "Punch low"
msgstr "Slх lavt"
-#: engines/scumm/help.cpp:306
+#: engines/scumm/help.cpp:315
+msgid "Sucker punch"
+msgstr ""
+
+#: engines/scumm/help.cpp:318
msgid "These are for Indy on left."
msgstr "Disse er for Indy til venstre"
-#: engines/scumm/help.cpp:307
+#: engines/scumm/help.cpp:319
msgid "When Indy is on the right,"
msgstr "Nхr Indy er til hјjre,"
-#: engines/scumm/help.cpp:308
+#: engines/scumm/help.cpp:320
msgid "7, 4, and 1 are switched with"
msgstr "7, 4 og 1 bliver bytte med"
-#: engines/scumm/help.cpp:309
+#: engines/scumm/help.cpp:321
msgid "9, 6, and 3, respectively."
msgstr "repektivt 9, 6 og 3."
-#: engines/scumm/help.cpp:316
+#: engines/scumm/help.cpp:328
msgid "Biplane controls (numpad):"
msgstr "Biplan kontroller (numtast):"
-#: engines/scumm/help.cpp:317
+#: engines/scumm/help.cpp:329
msgid "Fly to upper left"
msgstr "Flyv јverst til venste"
-#: engines/scumm/help.cpp:318
+#: engines/scumm/help.cpp:330
msgid "Fly to left"
msgstr "Flyv til venstre"
-#: engines/scumm/help.cpp:319
+#: engines/scumm/help.cpp:331
msgid "Fly to lower left"
msgstr "Flyv nederst til venstre"
-#: engines/scumm/help.cpp:320
+#: engines/scumm/help.cpp:332
msgid "Fly upwards"
msgstr "Flyv opad"
-#: engines/scumm/help.cpp:321
+#: engines/scumm/help.cpp:333
msgid "Fly straight"
msgstr "Flyv ligeud"
-#: engines/scumm/help.cpp:322
+#: engines/scumm/help.cpp:334
msgid "Fly down"
msgstr "Flyv nedad"
-#: engines/scumm/help.cpp:323
+#: engines/scumm/help.cpp:335
msgid "Fly to upper right"
msgstr "Flyv јverst til hјjre"
-#: engines/scumm/help.cpp:324
+#: engines/scumm/help.cpp:336
msgid "Fly to right"
msgstr "Flyv til hјjre"
-#: engines/scumm/help.cpp:325
+#: engines/scumm/help.cpp:337
msgid "Fly to lower right"
msgstr "Flyv nederst til hјjre"
-#: engines/scumm/scumm.cpp:1823
+#: engines/scumm/scumm.cpp:1832
#, c-format
msgid ""
"Native MIDI support requires the Roland Upgrade from LucasArts,\n"
@@ -3185,11 +3275,12 @@ msgstr ""
"Indbygget MIDI understјttelse krцver Roland opgradering fra LucasArts,\n"
"men %s mangler. Bruger AdLib i stedet."
-#: engines/scumm/scumm.cpp:2594
+#: engines/scumm/scumm.cpp:2644
+#, fuzzy
msgid ""
-"Usually, Maniac Mansion would start now. But ScummVM doesn't do that yet. To "
-"play it, go to 'Add Game' in the ScummVM start menu and select the 'Maniac' "
-"directory inside the Tentacle game directory."
+"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 "
@@ -3326,6 +3417,48 @@ msgstr ""
msgid "Show the current number of frames per second in the upper left corner"
msgstr ""
+#: engines/zvision/detection.cpp:256
+msgid "Double FPS"
+msgstr ""
+
+#: engines/zvision/detection.cpp:257
+msgid "Increase game FPS from 30 to 60"
+msgstr ""
+
+#: engines/zvision/detection.cpp:266
+#, fuzzy
+msgid "Enable Venus"
+msgstr "Aktivщr helium tilstand"
+
+#: engines/zvision/detection.cpp:267
+msgid "Enable the Venus help system"
+msgstr ""
+
+#: engines/zvision/detection.cpp:276
+msgid "Disable animation while turning"
+msgstr ""
+
+#: engines/zvision/detection.cpp:277
+msgid "Disable animation while turning in panoramic mode"
+msgstr ""
+
+#: engines/zvision/detection.cpp:286
+msgid "Use the hires MPEG movies"
+msgstr ""
+
+#: engines/zvision/detection.cpp:287
+#, fuzzy
+msgid ""
+"Use the hires MPEG movies of the DVD version, instead of the lowres AVI ones"
+msgstr ""
+"Brug det alternative sцt af sјlv markјrer, i stedet for de normale gyldne"
+
+#~ msgid "EGA undithering"
+#~ msgstr "EGA farveforјgelse"
+
+#~ msgid "Enable undithering in EGA games"
+#~ msgstr "Aktiver farveforјgelse i EGA spil"
+
#~ msgid "MPEG-2 cutscenes found but ScummVM has been built without MPEG-2"
#~ msgstr "MPEG-2 filmsekvenser fundet, men ScummVM er bygget uden MPEG-2"
@@ -3333,9 +3466,6 @@ msgstr ""
#~ msgid "Mass Add..."
#~ msgstr "Tilfјj flere..."
-#~ msgid "Mass Add..."
-#~ msgstr "Tilfјj flere..."
-
#~ msgid ""
#~ "Turns off General MIDI mapping for games with Roland MT-32 soundtrack"
#~ msgstr "Sluk for Generel MIDI kortlцgning for spil med Roland MT-32 lydspor"
diff --git a/po/de_DE.po b/po/de_DE.po
index d757050d6e..0e7e5d901c 100644
--- a/po/de_DE.po
+++ b/po/de_DE.po
@@ -1,21 +1,23 @@
# German translation for ScummVM.
# Copyright (C) 2010-2015 The ScummVM Team
# This file is distributed under the same license as the ScummVM package.
-# Simon Sawatzki <SimSaw@gmx.de>, Lothar Serra Mari, 2014.
+# Simon Sawatzki <SimSaw@gmx.de>, Lothar Serra Mari <scummvm@rootfather.de>, 2015.
#
msgid ""
msgstr ""
-"Project-Id-Version: ScummVM 1.5.0git\n"
+"Project-Id-Version: ScummVM 1.8.0git\n"
"Report-Msgid-Bugs-To: scummvm-devel@lists.sf.net\n"
-"POT-Creation-Date: 2014-10-04 00:58+0100\n"
-"PO-Revision-Date: 2014-06-14 19:34+0100\n"
-"Last-Translator: Simon Sawatzki <SimSaw@gmx.de>\n"
-"Language-Team: Simon Sawatzki <SimSaw@gmx.de>, Lothar Serra Mari (retired)\n"
+"POT-Creation-Date: 2015-06-30 20:57+0100\n"
+"PO-Revision-Date: 2015-07-04 12:06+0200\n"
+"Last-Translator: Lothar Serra Mari <scummvm@rootfather.de>\n"
+"Language-Team: Simon Sawatzki <SimSaw@gmx.de>, Lothar Serra Mari "
+"<scummvm@rootfather.de>\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
@@ -36,7 +38,8 @@ msgstr "Versteckte Dateien anzeigen"
#: gui/browser.cpp:68
msgid "Show files marked with the hidden attribute"
-msgstr "Dateien mit Versteckt-Attribut anzeigen"
+msgstr ""
+"Dateien anzeigen, die mit dem \"Versteckt-Attribut\" gekennzeichnet sind"
#: gui/browser.cpp:72
msgid "Go up"
@@ -53,10 +56,11 @@ msgstr "Pfad hoch"
#: gui/browser.cpp:75 gui/chooser.cpp:46 gui/KeysDialog.cpp:43
#: gui/launcher.cpp:351 gui/massadd.cpp:95 gui/options.cpp:1239
+#: gui/recorderdialog.cpp:70 gui/recorderdialog.cpp:156
#: gui/saveload-dialog.cpp:216 gui/saveload-dialog.cpp:276
-#: gui/saveload-dialog.cpp:547 gui/saveload-dialog.cpp:922
+#: gui/saveload-dialog.cpp:547 gui/saveload-dialog.cpp:931
#: gui/themebrowser.cpp:55 gui/fluidsynth-dialog.cpp:152
-#: engines/engine.cpp:452 backends/platform/wii/options.cpp:48
+#: engines/engine.cpp:483 backends/platform/wii/options.cpp:48
#: backends/events/default/default-events.cpp:196
#: backends/events/default/default-events.cpp:218
#: engines/drascula/saveload.cpp:49 engines/parallaction/saveload.cpp:274
@@ -69,9 +73,9 @@ msgid "Choose"
msgstr "Auswфhlen"
#: gui/gui-manager.cpp:117 backends/keymapper/remap-dialog.cpp:53
-#: 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
+#: 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"
@@ -87,9 +91,9 @@ msgstr "Tastatur anzeigen"
msgid "Remap keys"
msgstr "Tasten neu zuweisen"
-#: gui/gui-manager.cpp:131 base/main.cpp:326 engines/scumm/help.cpp:86
+#: gui/gui-manager.cpp:131 base/main.cpp:326 engines/scumm/help.cpp:87
msgid "Toggle fullscreen"
-msgstr "Vollbild EIN/AUS"
+msgstr "Vollbild umschalten"
#: gui/KeysDialog.h:36 gui/KeysDialog.cpp:145
msgid "Choose an action to map"
@@ -101,13 +105,13 @@ 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:1240
-#: gui/saveload-dialog.cpp:923 gui/fluidsynth-dialog.cpp:153
-#: engines/engine.cpp:371 engines/engine.cpp:382
+#: 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:399 engines/parallaction/saveload.cpp:274
-#: engines/scumm/dialogs.cpp:193 engines/scumm/scumm.cpp:1825
+#: 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
@@ -220,12 +224,12 @@ msgstr "GFX"
#: gui/launcher.cpp:248
msgid "Override global graphic settings"
-msgstr "Globale Grafikeinstellungen ќbergehen"
+msgstr "Globale Grafik-Einstellungen ќbergehen"
#: gui/launcher.cpp:250
msgctxt "lowres"
msgid "Override global graphic settings"
-msgstr "Globale Grafikeinstellungen ќbergehen"
+msgstr "Globale Grafik-Einstellungen ќbergehen"
#: gui/launcher.cpp:257 gui/options.cpp:1096
msgid "Audio"
@@ -233,12 +237,12 @@ msgstr "Audio"
#: gui/launcher.cpp:260
msgid "Override global audio settings"
-msgstr "Globale Audioeinstellungen ќbergehen"
+msgstr "Globale Audio-Einstellungen ќbergehen"
#: gui/launcher.cpp:262
msgctxt "lowres"
msgid "Override global audio settings"
-msgstr "Globale Audioeinstellungen ќbergehen"
+msgstr "Globale Audio-Einstellungen ќbergehen"
#: gui/launcher.cpp:271 gui/options.cpp:1101
msgid "Volume"
@@ -256,7 +260,7 @@ msgstr "Globale Lautstфrke-Einstellungen ќbergehen"
#: gui/launcher.cpp:278
msgctxt "lowres"
msgid "Override global volume settings"
-msgstr "Globale Lautstфrkeeinstellungen ќbergehen"
+msgstr "Globale Lautstфrke-Einstellungen ќbergehen"
#: gui/launcher.cpp:286 gui/options.cpp:1111
msgid "MIDI"
@@ -304,7 +308,7 @@ msgstr "Spielpfad:"
#: gui/launcher.cpp:330 gui/options.cpp:1150
msgid "Extra Path:"
-msgstr "Extrapfad:"
+msgstr "Extras:"
#: gui/launcher.cpp:330 gui/launcher.cpp:332 gui/launcher.cpp:333
msgid "Specifies path to additional data used by the game"
@@ -313,7 +317,7 @@ msgstr "Legt das Verzeichnis fќr zusфtzliche Spieldateien fest."
#: gui/launcher.cpp:332 gui/options.cpp:1152
msgctxt "lowres"
msgid "Extra Path:"
-msgstr "Extrapfad:"
+msgstr "Extras:"
#: gui/launcher.cpp:339 gui/options.cpp:1134
msgid "Save Path:"
@@ -322,12 +326,12 @@ msgstr "Spielstфnde:"
#: gui/launcher.cpp:339 gui/launcher.cpp:341 gui/launcher.cpp:342
#: gui/options.cpp:1134 gui/options.cpp:1136 gui/options.cpp:1137
msgid "Specifies where your saved games are put"
-msgstr "Legt fest, wo die Spielstфnde abgelegt werden."
+msgstr "Legt fest, wo die Spielstфnde gespeichert werden."
#: gui/launcher.cpp:341 gui/options.cpp:1136
msgctxt "lowres"
msgid "Save Path:"
-msgstr "Speichern:"
+msgstr "Spielstфnde:"
#: gui/launcher.cpp:360 gui/launcher.cpp:459 gui/launcher.cpp:517
#: gui/launcher.cpp:571 gui/options.cpp:1145 gui/options.cpp:1153
@@ -387,7 +391,7 @@ msgstr "~O~ptionen"
#: gui/launcher.cpp:628
msgid "Change global ScummVM options"
-msgstr "Globale ScummVM-Einstellungen bearbeiten"
+msgstr "Globale ScummVM-Einstellungen фndern"
#: gui/launcher.cpp:630
msgid "~S~tart"
@@ -479,7 +483,7 @@ msgstr ""
#: gui/launcher.cpp:793 gui/launcher.cpp:941 gui/launcher.cpp:1000
#: gui/fluidsynth-dialog.cpp:217
-#: backends/events/symbiansdl/symbiansdl-events.cpp:184
+#: 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
@@ -489,7 +493,7 @@ 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:184
+#: 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
@@ -526,9 +530,17 @@ msgstr ""
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
+msgid "Mass Add..."
+msgstr "Durchsuchen"
+
+#: gui/launcher.cpp:1161
+msgid "Record..."
+msgstr "Aufzeichnen"
+
#: gui/massadd.cpp:79 gui/massadd.cpp:82
msgid "... progress ..."
-msgstr "... lфuft..."
+msgstr "... lфuft ..."
#: gui/massadd.cpp:259
msgid "Scan complete!"
@@ -593,11 +605,11 @@ msgstr "48 kHz"
#: gui/options.cpp:651 gui/options.cpp:859
msgctxt "soundfont"
msgid "None"
-msgstr "-"
+msgstr "Kein SoundFont"
#: gui/options.cpp:389
msgid "Failed to apply some of the graphic options changes:"
-msgstr "Fehler bei einigen Фnderungen in Grafikoptionen:"
+msgstr "Folgende Grafikoptionen konnten nicht geфndert werden:"
#: gui/options.cpp:401
msgid "the video mode could not be changed."
@@ -626,7 +638,7 @@ msgstr ""
"Spezielle Farbmischungsmethoden werden von manchen Spielen unterstќtzt."
#: gui/options.cpp:760
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2249
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2298
msgid "Fullscreen mode"
msgstr "Vollbildmodus"
@@ -640,7 +652,7 @@ msgstr "Seitenverhфltnis fќr Spiele mit der Auflіsung 320x200 korrigieren"
#: gui/options.cpp:771
msgid "Preferred Device:"
-msgstr "Standard-Gerфt:"
+msgstr "Bevorzugtes Gerфt:"
#: gui/options.cpp:771
msgid "Music Device:"
@@ -718,11 +730,11 @@ msgstr "SoundFont:"
#: gui/options.cpp:864
msgid "Mixed AdLib/MIDI mode"
-msgstr "AdLib-/MIDI-Modus"
+msgstr "Gemischter AdLib/MIDI-Modus"
#: gui/options.cpp:864
msgid "Use both MIDI and AdLib sound generation"
-msgstr "Benutzt MIDI und AdLib zur Sounderzeugung."
+msgstr "Kombiniert MIDI-Musik mit AdLib-Soundeffekten"
#: gui/options.cpp:867
msgid "MIDI gain:"
@@ -744,24 +756,24 @@ msgstr ""
#: gui/options.cpp:886
msgid "True Roland MT-32 (disable GM emulation)"
-msgstr "Echte Roland-MT-32-Emulation (GM-Emulation deaktiviert)"
+msgstr "Echte Roland MT-32 (GM-Emulation deaktiviert)"
#: 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 ""
-"Wфhlen Sie dies aus, wenn Sie Ihre echte Hardware, die mit einer Roland-"
-"kompatiblen Soundkarte verbunden ist, verwenden mіchten."
+"Wфhlen Sie dies aus, wenn Sie ein echtes Roland-kompatibles Soundgerфt "
+"verwenden"
#: gui/options.cpp:888
msgctxt "lowres"
msgid "True Roland MT-32 (no GM emulation)"
-msgstr "Echte Roland-MT-32-Emulation (kein GM)"
+msgstr "Echte Roland MT-32 (keine GM-Emulation)"
#: gui/options.cpp:891
msgid "Roland GS Device (enable MT-32 mappings)"
-msgstr "Roland-GS-Modus (MT-32-Zuweisungen aktivieren)"
+msgstr "Roland-GS-Gerфt (MT-32-Zuweisungen aktivieren)"
#: gui/options.cpp:891
msgid ""
@@ -798,7 +810,7 @@ msgstr "Untertitel-Tempo:"
#: gui/options.cpp:937
msgctxt "lowres"
msgid "Text and Speech:"
-msgstr "Sprache + Text:"
+msgstr "Text u. Sprache:"
#: gui/options.cpp:941
msgid "Spch"
@@ -833,7 +845,7 @@ msgstr "Musiklautstфrke:"
#: gui/options.cpp:970
msgid "Mute All"
-msgstr "Alles aus"
+msgstr "Alles stumm"
#: gui/options.cpp:973
msgid "SFX volume:"
@@ -859,12 +871,12 @@ msgstr "Sprachlautst.:"
#: gui/options.cpp:1142
msgid "Theme Path:"
-msgstr "Themenpfad:"
+msgstr "Themen:"
#: gui/options.cpp:1144
msgctxt "lowres"
msgid "Theme Path:"
-msgstr "Themenpfad:"
+msgstr "Themen:"
#: gui/options.cpp:1150 gui/options.cpp:1152 gui/options.cpp:1153
msgid "Specifies path to additional data used by all games or ScummVM"
@@ -874,12 +886,12 @@ msgstr ""
#: gui/options.cpp:1159
msgid "Plugins Path:"
-msgstr "Plugin-Pfad:"
+msgstr "Plugins:"
#: gui/options.cpp:1161
msgctxt "lowres"
msgid "Plugins Path:"
-msgstr "Plugin-Pfad:"
+msgstr "Plugins:"
#: gui/options.cpp:1170 gui/fluidsynth-dialog.cpp:138
msgid "Misc"
@@ -905,7 +917,7 @@ msgstr "Autom. Speichern:"
#: gui/options.cpp:1192
msgctxt "lowres"
msgid "Autosave:"
-msgstr "Speich.(auto)"
+msgstr "Autospeichern:"
#: gui/options.cpp:1200
msgid "Keys"
@@ -951,6 +963,41 @@ msgstr ""
"dieses Thema benutzen wollen, mќssen Sie erst zu einer anderen Sprache "
"wechseln."
+#: gui/recorderdialog.cpp:64
+msgid "Recorder or Playback Gameplay"
+msgstr "Spiel aufzeichnen oder wiedergeben"
+
+#: gui/recorderdialog.cpp:69 gui/recorderdialog.cpp:156
+#: gui/saveload-dialog.cpp:220 gui/saveload-dialog.cpp:276
+msgid "Delete"
+msgstr "Lіschen"
+
+#: gui/recorderdialog.cpp:71
+msgid "Record"
+msgstr "Aufnahme"
+
+#: gui/recorderdialog.cpp:72
+msgid "Playback"
+msgstr "Wiedergabe"
+
+#: gui/recorderdialog.cpp:74
+msgid "Edit"
+msgstr "Bearbeiten"
+
+#: gui/recorderdialog.cpp:86 gui/recorderdialog.cpp:243
+#: gui/recorderdialog.cpp:253
+msgid "Author: "
+msgstr "Autor:"
+
+#: gui/recorderdialog.cpp:87 gui/recorderdialog.cpp:244
+#: gui/recorderdialog.cpp:254
+msgid "Notes: "
+msgstr "Notizen:"
+
+#: gui/recorderdialog.cpp:155
+msgid "Do you really want to delete this record?"
+msgstr "Mіchten Sie diese Aufnahme wirklich lіschen?"
+
#: gui/saveload-dialog.cpp:167
msgid "List view"
msgstr "Listenansicht"
@@ -971,23 +1018,19 @@ msgstr "Keine Zeit gespeichert"
msgid "No playtime saved"
msgstr "Keine Spielzeit gespeichert"
-#: gui/saveload-dialog.cpp:220 gui/saveload-dialog.cpp:276
-msgid "Delete"
-msgstr "Lіschen"
-
#: gui/saveload-dialog.cpp:275
msgid "Do you really want to delete this saved game?"
msgstr "Diesen Spielstand wirklich lіschen?"
-#: gui/saveload-dialog.cpp:385 gui/saveload-dialog.cpp:875
+#: gui/saveload-dialog.cpp:385 gui/saveload-dialog.cpp:884
msgid "Date: "
msgstr "Datum: "
-#: gui/saveload-dialog.cpp:389 gui/saveload-dialog.cpp:881
+#: gui/saveload-dialog.cpp:389 gui/saveload-dialog.cpp:890
msgid "Time: "
msgstr "Zeit: "
-#: gui/saveload-dialog.cpp:395 gui/saveload-dialog.cpp:889
+#: gui/saveload-dialog.cpp:395 gui/saveload-dialog.cpp:898
msgid "Playtime: "
msgstr "Spieldauer: "
@@ -1003,19 +1046,19 @@ msgstr "Vor"
msgid "Prev"
msgstr "Zurќck"
-#: gui/saveload-dialog.cpp:739
+#: gui/saveload-dialog.cpp:748
msgid "New Save"
msgstr "Neuer Spielstand"
-#: gui/saveload-dialog.cpp:739
+#: gui/saveload-dialog.cpp:748
msgid "Create a new save game"
msgstr "Erstellt einen neuen Spielstand."
-#: gui/saveload-dialog.cpp:868
+#: gui/saveload-dialog.cpp:877
msgid "Name: "
msgstr "Name: "
-#: gui/saveload-dialog.cpp:940
+#: gui/saveload-dialog.cpp:949
#, c-format
msgid "Enter a description for slot %d:"
msgstr "Geben Sie eine Beschreibung fќr Speicherplatz %d ein:"
@@ -1168,7 +1211,7 @@ msgstr "Zeile ќberspringen"
msgid "Error running game:"
msgstr "Fehler beim Ausfќhren des Spiels:"
-#: base/main.cpp:536
+#: base/main.cpp:554
msgid "Could not find any engine capable of running the selected game"
msgstr "Konnte keine Spiel-Engine finden, die dieses Spiel starten kann."
@@ -1178,7 +1221,7 @@ msgstr "Kein Fehler"
#: common/error.cpp:40
msgid "Game data not found"
-msgstr "Spieldaten nicht gefunden"
+msgstr "Spieldateien nicht gefunden"
#: common/error.cpp:42
msgid "Game id not supported"
@@ -1289,7 +1332,7 @@ 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:758
+#: engines/pegasus/pegasus.cpp:377 engines/sci/engine/kfile.cpp:759
#: engines/toltecs/menu.cpp:281 engines/tsage/scenes.cpp:598
msgid "Save game:"
msgstr "Speichern:"
@@ -1302,7 +1345,7 @@ msgstr "Speichern:"
#: 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:758 engines/scumm/dialogs.cpp:188
+#: engines/sci/engine/kfile.cpp:759 engines/scumm/dialogs.cpp:188
#: engines/toltecs/menu.cpp:281 engines/tsage/scenes.cpp:598
msgid "Save"
msgstr "Speichern"
@@ -1339,23 +1382,23 @@ msgstr "~A~bbrechen"
msgid "~K~eys"
msgstr "~T~asten"
-#: engines/engine.cpp:245
+#: engines/engine.cpp:276
msgid "Could not initialize color format."
msgstr "Konnte Farbenformat nicht initialisieren."
-#: engines/engine.cpp:253
+#: engines/engine.cpp:284
msgid "Could not switch to video mode: '"
-msgstr "Konnte nicht zu Grafikmodus wechseln: '"
+msgstr "Konnte nicht zu Grafikmodus wechseln: \""
-#: engines/engine.cpp:262
+#: engines/engine.cpp:293
msgid "Could not apply aspect ratio setting."
msgstr "Konnte Einstellung fќr Seitenverhфltniskorrektur nicht anwenden."
-#: engines/engine.cpp:267
+#: engines/engine.cpp:298
msgid "Could not apply fullscreen setting."
msgstr "Konnte Einstellung fќr Vollbildmodus nicht anwenden."
-#: engines/engine.cpp:367
+#: engines/engine.cpp:398
msgid ""
"You appear to be playing this game directly\n"
"from the CD. This is known to cause problems,\n"
@@ -1371,7 +1414,7 @@ msgstr ""
"Lesen Sie die Liesmich-Datei fќr\n"
"weitere Informationen."
-#: engines/engine.cpp:378
+#: engines/engine.cpp:409
msgid ""
"This game has audio tracks in its disk. These\n"
"tracks need to be ripped from the disk using\n"
@@ -1386,7 +1429,7 @@ msgstr ""
"Spiel hіren zu kіnnen. Lesen Sie die\n"
"Liesmich-Datei fќr weitere Informationen."
-#: engines/engine.cpp:436
+#: engines/engine.cpp:467
#, c-format
msgid ""
"Gamestate load failed (%s)! Please consult the README for basic information, "
@@ -1395,7 +1438,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:449
+#: engines/engine.cpp:480
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 "
@@ -1406,7 +1449,7 @@ msgstr ""
"und jegliche Spielstфnde, die Sie erstellen, kіnnten in zukќnftigen "
"Versionen von ScummVM nicht mehr funktionieren."
-#: engines/engine.cpp:452
+#: engines/engine.cpp:483
msgid "Start anyway"
msgstr "Trotzdem starten"
@@ -1558,7 +1601,7 @@ msgstr "Zu Y-Position gehen"
#: backends/platform/ds/arm9/source/dsoptions.cpp:87
msgid "Use laptop trackpad-style cursor control"
-msgstr "Den Trackpad-Style fќr Maussteuerung benutzen"
+msgstr "Den Trackpad-Modus fќr Maussteuerung benutzen"
#: backends/platform/ds/arm9/source/dsoptions.cpp:88
msgid "Tap for left click, double tap right click"
@@ -1570,7 +1613,7 @@ msgstr "Empfindlichkeit"
#: backends/platform/ds/arm9/source/dsoptions.cpp:99
msgid "Initial top screen scale:"
-msgstr "Vergіпerung des oberen Bildschirms:"
+msgstr "Vergrіпerung des oberen Bildschirms:"
#: backends/platform/ds/arm9/source/dsoptions.cpp:105
msgid "Main screen scaling:"
@@ -1616,11 +1659,11 @@ msgstr "Touchpad-Modus aktiviert."
msgid "Touchpad mode disabled."
msgstr "Touchpad-Modus ausgeschaltet."
-#: backends/platform/maemo/maemo.cpp:209
+#: backends/platform/maemo/maemo.cpp:208
msgid "Click Mode"
msgstr "Klickmodus"
-#: backends/platform/maemo/maemo.cpp:215
+#: backends/platform/maemo/maemo.cpp:214
#: backends/platform/symbian/src/SymbianActions.cpp:42
#: backends/platform/wince/CEActionsPocket.cpp:60
#: backends/platform/wince/CEActionsSmartphone.cpp:43
@@ -1628,11 +1671,11 @@ msgstr "Klickmodus"
msgid "Left Click"
msgstr "Linksklick"
-#: backends/platform/maemo/maemo.cpp:218
+#: backends/platform/maemo/maemo.cpp:217
msgid "Middle Click"
msgstr "Mittelklick"
-#: backends/platform/maemo/maemo.cpp:221
+#: 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
@@ -1658,7 +1701,7 @@ msgstr "Fenster"
#: backends/platform/sdl/macosx/appmenu_osx.mm:114
msgid "Minimize"
-msgstr "Im Dock ablegen"
+msgstr "Minimieren"
#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:46
msgid "Normal (no scaling)"
@@ -1669,19 +1712,19 @@ msgctxt "lowres"
msgid "Normal (no scaling)"
msgstr "Normal ohn.Skalieren"
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2148
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2197
msgid "Enabled aspect ratio correction"
msgstr "Seitenverhфltniskorrektur an"
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2154
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2203
msgid "Disabled aspect ratio correction"
msgstr "Seitenverhфltniskorrektur aus"
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2209
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2258
msgid "Active graphics filter:"
msgstr "Aktiver Grafikfilter:"
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2251
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2300
msgid "Windowed mode"
msgstr "Fenstermodus"
@@ -1740,8 +1783,8 @@ msgstr "Schneller Modus"
#: 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:82
-#: engines/scumm/help.cpp:84
+#: engines/scumm/dialogs.cpp:192 engines/scumm/help.cpp:83
+#: engines/scumm/help.cpp:85
msgid "Quit"
msgstr "Beenden"
@@ -1761,7 +1804,7 @@ msgstr "Virtuelle Tastatur"
msgid "Key mapper"
msgstr "Tasten zuordnen"
-#: backends/events/symbiansdl/symbiansdl-events.cpp:184
+#: backends/events/symbiansdl/symbiansdl-events.cpp:186
msgid "Do you want to quit ?"
msgstr "Mіchten Sie beenden?"
@@ -2098,34 +2141,57 @@ msgstr "Klicken aktiviert"
msgid "Clicking Disabled"
msgstr "Klicken deaktiviert"
-#: engines/agi/detection.cpp:142 engines/drascula/detection.cpp:302
+#: 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.cpp:103
+#: engines/zvision/detection.cpp:246
msgid "Use original save/load screens"
msgstr "Originale Spielstand-Menќs"
-#: engines/agi/detection.cpp:143 engines/drascula/detection.cpp:303
+#: 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/zvision/detection.cpp:104
+#: engines/zvision/detection.cpp:247
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."
+#: engines/agi/detection.cpp:157
+msgid "Use an alternative palette"
+msgstr "Alternative Farbpalette verwenden"
+
+#: engines/agi/detection.cpp:158
+msgid ""
+"Use an alternative palette, common for all Amiga games. This was the old "
+"behavior"
+msgstr ""
+"Verwende eine alternative Farbpalette fќr alle Amiga-Spiele. Dies war das "
+"alte Verhalten."
+
+#: engines/agi/detection.cpp:167
+msgid "Mouse support"
+msgstr "Maus-Unterstќtzung"
+
+#: engines/agi/detection.cpp:168
+msgid ""
+"Enables mouse support. Allows to use mouse for movement and in game menus."
+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:857 engines/toltecs/menu.cpp:256
+#: engines/sci/engine/kfile.cpp:858 engines/toltecs/menu.cpp:256
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:857 engines/toltecs/menu.cpp:256
+#: engines/sci/engine/kfile.cpp:858 engines/toltecs/menu.cpp:256
msgid "Restore"
msgstr "Laden"
-#: engines/agos/saveload.cpp:160 engines/scumm/scumm.cpp:2368
+#: engines/agos/saveload.cpp:160 engines/scumm/scumm.cpp:2377
#, c-format
msgid ""
"Failed to load game state from file:\n"
@@ -2136,7 +2202,7 @@ msgstr ""
"\n"
"%s"
-#: engines/agos/saveload.cpp:195 engines/scumm/scumm.cpp:2361
+#: engines/agos/saveload.cpp:195 engines/scumm/scumm.cpp:2370
#, c-format
msgid ""
"Failed to save game state to file:\n"
@@ -2147,7 +2213,7 @@ msgstr ""
"\n"
"%s"
-#: engines/agos/saveload.cpp:203 engines/scumm/scumm.cpp:2379
+#: engines/agos/saveload.cpp:203 engines/scumm/scumm.cpp:2388
#, c-format
msgid ""
"Successfully saved game state in file:\n"
@@ -2163,14 +2229,13 @@ msgstr ""
msgid "Cutscene file '%s' not found!"
msgstr "Zwischensequenz \"%s\" nicht gefunden!"
-#: engines/cge/detection.cpp:105 engines/cge2/detection.cpp:81
-#, fuzzy
+#: engines/cge/detection.cpp:105 engines/cge2/detection.cpp:101
msgid "Color Blind Mode"
-msgstr "Klickmodus"
+msgstr "Modus fќr Farbenblinde"
-#: engines/cge/detection.cpp:106 engines/cge2/detection.cpp:82
+#: engines/cge/detection.cpp:106 engines/cge2/detection.cpp:102
msgid "Enable Color Blind Mode by default"
-msgstr ""
+msgstr "Modus fќr Farbenblinde standardmфпig einschalten"
#: engines/drascula/saveload.cpp:47
msgid ""
@@ -2220,17 +2285,17 @@ msgstr "Schnelles Film-Tempo"
msgid "Play movies at an increased speed"
msgstr "Spielt Filme mit erhіhter Geschwindigkeit ab."
-#: engines/groovie/script.cpp:399
+#: engines/groovie/script.cpp:408
msgid "Failed to save game"
msgstr "Konnte Spielstand nicht speichern."
#: engines/hopkins/detection.cpp:76 engines/hopkins/detection.cpp:86
msgid "Gore Mode"
-msgstr ""
+msgstr "Blutmodus"
#: engines/hopkins/detection.cpp:77 engines/hopkins/detection.cpp:87
msgid "Enable Gore Mode when available"
-msgstr ""
+msgstr "Blutmodus aktivieren, wenn verfќgbar"
#. I18N: Studio audience adds an applause and cheering sounds whenever
#. Malcolm makes a joke.
@@ -2245,7 +2310,7 @@ msgstr "Aktiviert Studio-Publikum."
#. I18N: This option allows the user to skip text and cutscenes.
#: engines/kyra/detection.cpp:73
msgid "Skip support"
-msgstr "мberspring-Unterstќtzung"
+msgstr "Erlaube мberspringen"
#: engines/kyra/detection.cpp:74
msgid "Allow text and cutscenes to be skipped"
@@ -2364,6 +2429,13 @@ msgid ""
"Do you wish to use this save game file with ScummVM?\n"
"\n"
msgstr ""
+"Die folgende originale Spielstand-Datei wurde in Ihrem Spieleverzeichnis "
+"gefunden:\n"
+"\n"
+"%s %s\n"
+"\n"
+"Mіchten Sie diese Spielstand-Datei in ScummVM verwenden?\n"
+"\n"
#: engines/kyra/saveload_eob.cpp:590
#, c-format
@@ -2371,6 +2443,9 @@ msgid ""
"A save game file was found in the specified slot %d. Overwrite?\n"
"\n"
msgstr ""
+"Eine Spielstand-Datei wurde im gewфhlten Speicherplatz %d gefunden. "
+"мberschreiben?\n"
+"\n"
#: engines/kyra/saveload_eob.cpp:623
#, c-format
@@ -2382,6 +2457,12 @@ msgid ""
"'import_savefile'.\n"
"\n"
msgstr ""
+"%d originale Spielstand-Dateien wurden erfolgreich nach ScummVM\n"
+"importiert. Wenn Sie weitere Spielstand-Dateien spфter manuell importieren "
+"wollen,\n"
+"mќssen Sie die ScummVM-Entwicklerkonsole іffnen und den Befehl "
+"\"import_savefile\" verwenden.\n"
+"\n"
#. I18N: Option for fast scene switching
#: engines/mohawk/dialogs.cpp:92 engines/mohawk/dialogs.cpp:167
@@ -2523,12 +2604,14 @@ msgid "Use an alternative game intro (CD version only)"
msgstr "Verwendet einen alternativen Vorspann (nur bei CD-Version)."
#: engines/sci/detection.cpp:374
-msgid "EGA undithering"
-msgstr "Antifehlerdiffusion fќr EGA"
+msgid "Skip EGA dithering pass (full color backgrounds)"
+msgstr "мberspringe EGA-Fehlerdiffusion (Vollfarbige Hintergrќnde)"
#: engines/sci/detection.cpp:375
-msgid "Enable undithering in EGA games"
-msgstr "Aktiviert die Aufhebung der Fehlerdiffusion in EGA-Spielen."
+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
msgid "Prefer digital sound effects"
@@ -2603,12 +2686,12 @@ msgstr "Spielpause. Zum Weiterspielen Leertaste drќcken."
#. "Moechten Sie wirklich neu starten? (J/N)J"
#. Will react to J as 'Yes'
#: engines/scumm/dialogs.cpp:183
-msgid "Are you sure you want to restart? (Y/N)"
+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
-msgid "Are you sure you want to quit? (Y/N)"
+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
@@ -2665,7 +2748,7 @@ msgstr "~W~eiter"
#: engines/scumm/dialogs.cpp:600
msgid "Speech Only"
-msgstr "Nur Sprachausgabe"
+msgstr "Nur Sprache"
#: engines/scumm/dialogs.cpp:601
msgid "Speech and Subtitles"
@@ -2686,7 +2769,7 @@ msgstr "Wфhle einen Schwierigkeitsgrad."
#: engines/scumm/dialogs.cpp:658
msgid "Refer to your Loom(TM) manual for help."
-msgstr "Fќr Hilfe schaue ins Loom-Handbuch."
+msgstr "Fќr Hilfe schauen Sie ins Loom-Handbuch."
#: engines/scumm/dialogs.cpp:662
msgid "Practice"
@@ -2696,516 +2779,540 @@ msgstr "Anfфnger"
msgid "Expert"
msgstr "Experte"
-#: engines/scumm/help.cpp:73
+#: engines/scumm/help.cpp:74
msgid "Common keyboard commands:"
msgstr "Allgemeine Tastenbefehle:"
-#: engines/scumm/help.cpp:74
+#: engines/scumm/help.cpp:75
msgid "Save / Load dialog"
msgstr "Menќ zum Speichern/Laden"
-#: engines/scumm/help.cpp:76
+#: engines/scumm/help.cpp:77
msgid "Skip line of text"
msgstr "Textzeile ќberspringen"
-#: engines/scumm/help.cpp:77
+#: engines/scumm/help.cpp:78
msgid "Esc"
msgstr "Esc"
-#: engines/scumm/help.cpp:77
+#: engines/scumm/help.cpp:78
msgid "Skip cutscene"
msgstr "Zwischensequenz ќberspringen"
-#: engines/scumm/help.cpp:78
+#: engines/scumm/help.cpp:79
msgid "Space"
msgstr "Leertaste"
-#: engines/scumm/help.cpp:78
+#: engines/scumm/help.cpp:79
msgid "Pause game"
msgstr "Spielpause"
-#: engines/scumm/help.cpp:79 engines/scumm/help.cpp:84
-#: engines/scumm/help.cpp:95 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: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 "Strg"
-#: engines/scumm/help.cpp:79
+#: engines/scumm/help.cpp:80
msgid "Load game state 1-10"
msgstr "Spielstand 1-10 laden"
-#: engines/scumm/help.cpp:80 engines/scumm/help.cpp:84
-#: engines/scumm/help.cpp:86 engines/scumm/help.cpp:100
-#: engines/scumm/help.cpp:101 engines/scumm/help.cpp:102
+#: 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:80
+#: engines/scumm/help.cpp:81
msgid "Save game state 1-10"
msgstr "Spielstand 1-10 speichern"
-#: engines/scumm/help.cpp:86 engines/scumm/help.cpp:89
+#: engines/scumm/help.cpp:87 engines/scumm/help.cpp:90
msgid "Enter"
msgstr "Enter"
-#: engines/scumm/help.cpp:87
+#: engines/scumm/help.cpp:88
msgid "Music volume up / down"
msgstr "Musiklautstфrke hіher/niedriger"
-#: engines/scumm/help.cpp:88
+#: engines/scumm/help.cpp:89
msgid "Text speed slower / faster"
msgstr "Texttempo langsamer/schneller"
-#: engines/scumm/help.cpp:89
+#: engines/scumm/help.cpp:90
msgid "Simulate left mouse button"
msgstr "Linke Maustaste simulieren"
-#: engines/scumm/help.cpp:90
+#: engines/scumm/help.cpp:91
msgid "Tab"
msgstr "Tabulator"
-#: engines/scumm/help.cpp:90
+#: engines/scumm/help.cpp:91
msgid "Simulate right mouse button"
msgstr "Rechte Maustaste simulieren"
-#: engines/scumm/help.cpp:93
+#: engines/scumm/help.cpp:94
msgid "Special keyboard commands:"
msgstr "Spezielle Tastenbefehle:"
-#: engines/scumm/help.cpp:94
+#: engines/scumm/help.cpp:95
msgid "Show / Hide console"
msgstr "Konsole zeigen/verbergen"
-#: engines/scumm/help.cpp:95
+#: engines/scumm/help.cpp:96
msgid "Start the debugger"
msgstr "Debugger starten"
-#: engines/scumm/help.cpp:96
+#: engines/scumm/help.cpp:97
msgid "Show memory consumption"
msgstr "Speicherverbrauch anzeigen"
-#: engines/scumm/help.cpp:97
+#: engines/scumm/help.cpp:98
msgid "Run in fast mode (*)"
msgstr "Schneller Modus (*)"
-#: engines/scumm/help.cpp:98
+#: engines/scumm/help.cpp:99
msgid "Run in really fast mode (*)"
msgstr "Sehr schneller Modus (*)"
-#: engines/scumm/help.cpp:99
+#: engines/scumm/help.cpp:100
msgid "Toggle mouse capture"
msgstr "Mauseingrenzung in Fenster EIN/AUS"
-#: engines/scumm/help.cpp:100
+#: engines/scumm/help.cpp:101
msgid "Switch between graphics filters"
msgstr "Zwischen Grafikfiltern wechseln"
-#: engines/scumm/help.cpp:101
+#: engines/scumm/help.cpp:102
msgid "Increase / Decrease scale factor"
msgstr "Grіпenverhфtlnis hіher/niedriger"
-#: engines/scumm/help.cpp:102
+#: engines/scumm/help.cpp:103
msgid "Toggle aspect-ratio correction"
msgstr "Seitenverhфltnis anpassen: EIN/AUS"
-#: engines/scumm/help.cpp:107
+#: engines/scumm/help.cpp:108
msgid "* Note that using ctrl-f and"
msgstr "* Es wird davon abgeraten,"
-#: engines/scumm/help.cpp:108
+#: engines/scumm/help.cpp:109
msgid " ctrl-g are not recommended"
-msgstr " Strg+f und Strg+g zu verwenden,"
+msgstr " Strg+F und Strg+G zu verwenden,"
-#: engines/scumm/help.cpp:109
+#: engines/scumm/help.cpp:110
msgid " since they may cause crashes"
msgstr " da dies Abstќrze oder fehlerhaftes"
-#: engines/scumm/help.cpp:110
+#: engines/scumm/help.cpp:111
msgid " or incorrect game behavior."
msgstr " Spielverhalten verursachen kann."
-#: engines/scumm/help.cpp:114
+#: engines/scumm/help.cpp:115
msgid "Spinning drafts on the keyboard:"
msgstr "Sprќche mit Tastatur spinnen:"
-#: engines/scumm/help.cpp:116
+#: engines/scumm/help.cpp:117
msgid "Main game controls:"
msgstr "Hauptspielsteuerung:"
-#: engines/scumm/help.cpp:121 engines/scumm/help.cpp:136
-#: engines/scumm/help.cpp:161
+#: engines/scumm/help.cpp:122 engines/scumm/help.cpp:137
+#: engines/scumm/help.cpp:162
msgid "Push"
msgstr "Drќcke"
-#: engines/scumm/help.cpp:122 engines/scumm/help.cpp:137
-#: engines/scumm/help.cpp:162
+#: engines/scumm/help.cpp:123 engines/scumm/help.cpp:138
+#: engines/scumm/help.cpp:163
msgid "Pull"
msgstr "Ziehe"
-#: engines/scumm/help.cpp:123 engines/scumm/help.cpp:138
-#: engines/scumm/help.cpp:163 engines/scumm/help.cpp:197
-#: engines/scumm/help.cpp:207
+#: 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 "Gib"
-#: engines/scumm/help.cpp:124 engines/scumm/help.cpp:139
-#: engines/scumm/help.cpp:164 engines/scumm/help.cpp:190
-#: engines/scumm/help.cpp:208
+#: 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 "жffne"
-#: engines/scumm/help.cpp:126
+#: engines/scumm/help.cpp:127
msgid "Go to"
msgstr "Gehe zu"
-#: engines/scumm/help.cpp:127
+#: engines/scumm/help.cpp:128
msgid "Get"
msgstr "Nimm"
-#: engines/scumm/help.cpp:128 engines/scumm/help.cpp:152
-#: engines/scumm/help.cpp:170 engines/scumm/help.cpp:198
-#: engines/scumm/help.cpp:213 engines/scumm/help.cpp:224
-#: engines/scumm/help.cpp:250
+#: 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 "Benutze"
-#: engines/scumm/help.cpp:129 engines/scumm/help.cpp:141
+#: engines/scumm/help.cpp:130 engines/scumm/help.cpp:142
msgid "Read"
msgstr "Lies"
-#: engines/scumm/help.cpp:130 engines/scumm/help.cpp:147
+#: engines/scumm/help.cpp:131 engines/scumm/help.cpp:148
msgid "New kid"
msgstr "Person"
-#: engines/scumm/help.cpp:131 engines/scumm/help.cpp:153
-#: engines/scumm/help.cpp:171
+#: engines/scumm/help.cpp:132 engines/scumm/help.cpp:154
+#: engines/scumm/help.cpp:172
msgid "Turn on"
msgstr "Schalt ein"
-#: engines/scumm/help.cpp:132 engines/scumm/help.cpp:154
-#: engines/scumm/help.cpp:172
+#: engines/scumm/help.cpp:133 engines/scumm/help.cpp:155
+#: engines/scumm/help.cpp:173
msgid "Turn off"
msgstr "Schalt aus"
-#: engines/scumm/help.cpp:142 engines/scumm/help.cpp:167
-#: engines/scumm/help.cpp:194
+#: engines/scumm/help.cpp:143 engines/scumm/help.cpp:168
+#: engines/scumm/help.cpp:195
msgid "Walk to"
msgstr "Gehe zu"
-#: engines/scumm/help.cpp:143 engines/scumm/help.cpp:168
-#: engines/scumm/help.cpp:195 engines/scumm/help.cpp:210
-#: engines/scumm/help.cpp:227
+#: 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 "Nimm"
-#: engines/scumm/help.cpp:144 engines/scumm/help.cpp:169
+#: engines/scumm/help.cpp:145 engines/scumm/help.cpp:170
msgid "What is"
msgstr "Was ist"
-#: engines/scumm/help.cpp:146
+#: engines/scumm/help.cpp:147
msgid "Unlock"
msgstr "Schlieп auf"
-#: engines/scumm/help.cpp:149
+#: engines/scumm/help.cpp:150
msgid "Put on"
msgstr "Zieh an"
-#: engines/scumm/help.cpp:150
+#: engines/scumm/help.cpp:151
msgid "Take off"
msgstr "Nimm ab"
-#: engines/scumm/help.cpp:156
+#: engines/scumm/help.cpp:157
msgid "Fix"
msgstr "Reparier"
-#: engines/scumm/help.cpp:158
+#: engines/scumm/help.cpp:159
msgid "Switch"
msgstr "Wechsle"
-#: engines/scumm/help.cpp:166 engines/scumm/help.cpp:228
+#: engines/scumm/help.cpp:167 engines/scumm/help.cpp:229
msgid "Look"
msgstr "Schau"
-#: engines/scumm/help.cpp:173 engines/scumm/help.cpp:223
+#: engines/scumm/help.cpp:174 engines/scumm/help.cpp:224
msgid "Talk"
msgstr "Rede"
-#: engines/scumm/help.cpp:174
+#: engines/scumm/help.cpp:175
msgid "Travel"
msgstr "Reise"
-#: engines/scumm/help.cpp:175
+#: engines/scumm/help.cpp:176
msgid "To Henry / To Indy"
msgstr "Zu Henry/Zu Indy"
#. I18N: These are different musical notes
-#: engines/scumm/help.cpp:179
+#: engines/scumm/help.cpp:180
msgid "play C minor on distaff"
msgstr "spiele tiefes C auf Stab"
-#: engines/scumm/help.cpp:180
+#: engines/scumm/help.cpp:181
msgid "play D on distaff"
msgstr "spiele D auf Stab"
-#: engines/scumm/help.cpp:181
+#: engines/scumm/help.cpp:182
msgid "play E on distaff"
msgstr "spiele E auf Stab"
-#: engines/scumm/help.cpp:182
+#: engines/scumm/help.cpp:183
msgid "play F on distaff"
msgstr "spiele F auf Stab"
-#: engines/scumm/help.cpp:183
+#: engines/scumm/help.cpp:184
msgid "play G on distaff"
msgstr "spiele G auf Stab"
-#: engines/scumm/help.cpp:184
+#: engines/scumm/help.cpp:185
msgid "play A on distaff"
msgstr "spiele A auf Stab"
-#: engines/scumm/help.cpp:185
+#: engines/scumm/help.cpp:186
msgid "play B on distaff"
msgstr "spiele B auf Stab"
-#: engines/scumm/help.cpp:186
+#: engines/scumm/help.cpp:187
msgid "play C major on distaff"
msgstr "spiele hohes C auf Stab"
-#: engines/scumm/help.cpp:192 engines/scumm/help.cpp:214
+#: engines/scumm/help.cpp:193 engines/scumm/help.cpp:215
msgid "puSh"
msgstr "Drќcke"
-#: engines/scumm/help.cpp:193 engines/scumm/help.cpp:215
+#: engines/scumm/help.cpp:194 engines/scumm/help.cpp:216
msgid "pull (Yank)"
msgstr "Ziehe"
-#: engines/scumm/help.cpp:196 engines/scumm/help.cpp:212
-#: engines/scumm/help.cpp:248
+#: engines/scumm/help.cpp:197 engines/scumm/help.cpp:213
+#: engines/scumm/help.cpp:249
msgid "Talk to"
msgstr "Rede mit"
-#: engines/scumm/help.cpp:199 engines/scumm/help.cpp:211
+#: engines/scumm/help.cpp:200 engines/scumm/help.cpp:212
msgid "Look at"
msgstr "Schau an"
-#: engines/scumm/help.cpp:200
+#: engines/scumm/help.cpp:201
msgid "turn oN"
msgstr "Mach an"
-#: engines/scumm/help.cpp:201
+#: engines/scumm/help.cpp:202
msgid "turn oFf"
msgstr "Mach aus"
-#: engines/scumm/help.cpp:217
+#: engines/scumm/help.cpp:218
msgid "KeyUp"
msgstr "Hoch-Taste"
-#: engines/scumm/help.cpp:217
+#: engines/scumm/help.cpp:218
msgid "Highlight prev dialogue"
msgstr "Vorige Dialogwahl markieren"
-#: engines/scumm/help.cpp:218
+#: engines/scumm/help.cpp:219
msgid "KeyDown"
msgstr "Runter-Taste"
-#: engines/scumm/help.cpp:218
+#: engines/scumm/help.cpp:219
msgid "Highlight next dialogue"
msgstr "Nфchste Dialogwahl markieren"
-#: engines/scumm/help.cpp:222
+#: engines/scumm/help.cpp:223
msgid "Walk"
msgstr "Gehe"
-#: engines/scumm/help.cpp:225 engines/scumm/help.cpp:234
-#: engines/scumm/help.cpp:241 engines/scumm/help.cpp:249
+#: engines/scumm/help.cpp:226 engines/scumm/help.cpp:235
+#: engines/scumm/help.cpp:242 engines/scumm/help.cpp:250
msgid "Inventory"
msgstr "Inventar"
-#: engines/scumm/help.cpp:226
+#: engines/scumm/help.cpp:227
msgid "Object"
msgstr "Objekt"
-#: engines/scumm/help.cpp:229
+#: engines/scumm/help.cpp:230
msgid "Black and White / Color"
msgstr "Graustufen-Modus/Farbe"
-#: engines/scumm/help.cpp:232
+#: engines/scumm/help.cpp:233
msgid "Eyes"
msgstr "Augen"
-#: engines/scumm/help.cpp:233
+#: engines/scumm/help.cpp:234
msgid "Tongue"
msgstr "Zunge"
-#: engines/scumm/help.cpp:235
+#: engines/scumm/help.cpp:236
msgid "Punch"
msgstr "Schlage"
-#: engines/scumm/help.cpp:236
+#: engines/scumm/help.cpp:237
msgid "Kick"
msgstr "Tritt"
-#: engines/scumm/help.cpp:239 engines/scumm/help.cpp:247
+#: engines/scumm/help.cpp:240 engines/scumm/help.cpp:248
msgid "Examine"
msgstr "Betrachte"
-#: engines/scumm/help.cpp:240
+#: engines/scumm/help.cpp:241
msgid "Regular cursor"
msgstr "Normaler Mauszeiger"
#. I18N: Comm is a communication device
-#: engines/scumm/help.cpp:243
+#: engines/scumm/help.cpp:244
msgid "Comm"
msgstr "Kommunikation"
-#: engines/scumm/help.cpp:246
+#: engines/scumm/help.cpp:247
msgid "Save / Load / Options"
msgstr "Speichern / Laden / Optionen"
-#: engines/scumm/help.cpp:255
+#: engines/scumm/help.cpp:256
msgid "Other game controls:"
msgstr "Weitere Steuerung:"
-#: engines/scumm/help.cpp:257 engines/scumm/help.cpp:267
+#: engines/scumm/help.cpp:258 engines/scumm/help.cpp:268
msgid "Inventory:"
msgstr "Inventar:"
-#: engines/scumm/help.cpp:258 engines/scumm/help.cpp:274
+#: engines/scumm/help.cpp:259 engines/scumm/help.cpp:275
msgid "Scroll list up"
msgstr "Liste hochblфttern"
-#: engines/scumm/help.cpp:259 engines/scumm/help.cpp:275
+#: engines/scumm/help.cpp:260 engines/scumm/help.cpp:276
msgid "Scroll list down"
msgstr "Liste runterblфttern"
-#: engines/scumm/help.cpp:260 engines/scumm/help.cpp:268
+#: engines/scumm/help.cpp:261 engines/scumm/help.cpp:269
msgid "Upper left item"
msgstr "Oberer linker Gegenstand"
-#: engines/scumm/help.cpp:261 engines/scumm/help.cpp:270
+#: engines/scumm/help.cpp:262 engines/scumm/help.cpp:271
msgid "Lower left item"
msgstr "Unterer linker Gegenstand"
-#: engines/scumm/help.cpp:262 engines/scumm/help.cpp:271
+#: engines/scumm/help.cpp:263 engines/scumm/help.cpp:272
msgid "Upper right item"
msgstr "Oberer rechter Gegenstand"
-#: engines/scumm/help.cpp:263 engines/scumm/help.cpp:273
+#: engines/scumm/help.cpp:264 engines/scumm/help.cpp:274
msgid "Lower right item"
msgstr "Unterer rechter Gegenstand"
-#: engines/scumm/help.cpp:269
+#: engines/scumm/help.cpp:270
msgid "Middle left item"
msgstr "Mittlerer linker Gegenstand"
-#: engines/scumm/help.cpp:272
+#: engines/scumm/help.cpp:273
msgid "Middle right item"
msgstr "Mittlerer rechter Gegenstand"
-#: engines/scumm/help.cpp:279 engines/scumm/help.cpp:284
+#: engines/scumm/help.cpp:280 engines/scumm/help.cpp:285
msgid "Switching characters:"
msgstr "Figuren wechseln:"
-#: engines/scumm/help.cpp:281
+#: engines/scumm/help.cpp:282
msgid "Second kid"
msgstr "Zweites Kind"
-#: engines/scumm/help.cpp:282
+#: engines/scumm/help.cpp:283
msgid "Third kid"
msgstr "Drittes Kind"
-#: engines/scumm/help.cpp:294
+#: engines/scumm/help.cpp:292
+msgid "Toggle Inventory/IQ Points display"
+msgstr "Inventar-/IQ-Punkt-Anzeige umschalten"
+
+#: engines/scumm/help.cpp:293
+msgid "Toggle Keyboard/Mouse Fighting (*)"
+msgstr "Schalte zwischen Tastatur-/Maus-Kфmpfen um (*)"
+
+#: engines/scumm/help.cpp:295
+msgid "* Keyboard Fighting is always on,"
+msgstr "* Tastatur-Steuerung der Kфmpfe ist immer an,"
+
+#: engines/scumm/help.cpp:296
+msgid " so despite the in-game message this"
+msgstr " demnach wird trotz der Meldung im Spiel"
+
+#: engines/scumm/help.cpp:297
+msgid " actually toggles Mouse Fighting Off/On"
+msgstr " die Maus-Steuerung der Kфmpfe ein-/ausgeschaltet"
+
+#: engines/scumm/help.cpp:304
msgid "Fighting controls (numpad):"
msgstr "Kampfsteuerung (Ziffernblock):"
-#: engines/scumm/help.cpp:295 engines/scumm/help.cpp:296
-#: engines/scumm/help.cpp:297
+#: engines/scumm/help.cpp:305 engines/scumm/help.cpp:306
+#: engines/scumm/help.cpp:307
msgid "Step back"
msgstr "Schritt zurќck"
-#: engines/scumm/help.cpp:298
+#: engines/scumm/help.cpp:308
msgid "Block high"
msgstr "Deckung oben"
-#: engines/scumm/help.cpp:299
+#: engines/scumm/help.cpp:309
msgid "Block middle"
msgstr "Deckung Mitte"
-#: engines/scumm/help.cpp:300
+#: engines/scumm/help.cpp:310
msgid "Block low"
msgstr "Deckung unten"
-#: engines/scumm/help.cpp:301
+#: engines/scumm/help.cpp:311
msgid "Punch high"
msgstr "Schlag oben"
-#: engines/scumm/help.cpp:302
+#: engines/scumm/help.cpp:312
msgid "Punch middle"
msgstr "Schlag Mitte"
-#: engines/scumm/help.cpp:303
+#: engines/scumm/help.cpp:313
msgid "Punch low"
msgstr "Schlag unten"
-#: engines/scumm/help.cpp:306
+#: engines/scumm/help.cpp:315
+msgid "Sucker punch"
+msgstr "Unerwarteter Schlag"
+
+#: engines/scumm/help.cpp:318
msgid "These are for Indy on left."
msgstr "Dies gilt fќr Indy links."
-#: engines/scumm/help.cpp:307
+#: engines/scumm/help.cpp:319
msgid "When Indy is on the right,"
msgstr "Wenn Indy rechts steht,"
-#: engines/scumm/help.cpp:308
+#: engines/scumm/help.cpp:320
msgid "7, 4, and 1 are switched with"
msgstr "werden 7, 4 und 1 je mit"
-#: engines/scumm/help.cpp:309
+#: engines/scumm/help.cpp:321
msgid "9, 6, and 3, respectively."
msgstr "9, 6 und 3 vertauscht."
-#: engines/scumm/help.cpp:316
+#: engines/scumm/help.cpp:328
msgid "Biplane controls (numpad):"
msgstr "Doppeldecker (Ziffernblock):"
-#: engines/scumm/help.cpp:317
+#: engines/scumm/help.cpp:329
msgid "Fly to upper left"
msgstr "Nach oben links fliegen"
-#: engines/scumm/help.cpp:318
+#: engines/scumm/help.cpp:330
msgid "Fly to left"
msgstr "Nach links fliegen"
-#: engines/scumm/help.cpp:319
+#: engines/scumm/help.cpp:331
msgid "Fly to lower left"
msgstr "Nach unten links fliegen"
-#: engines/scumm/help.cpp:320
+#: engines/scumm/help.cpp:332
msgid "Fly upwards"
msgstr "Nach oben fliegen"
-#: engines/scumm/help.cpp:321
+#: engines/scumm/help.cpp:333
msgid "Fly straight"
msgstr "Geradeaus fliegen"
-#: engines/scumm/help.cpp:322
+#: engines/scumm/help.cpp:334
msgid "Fly down"
msgstr "Nach unten fliegen"
-#: engines/scumm/help.cpp:323
+#: engines/scumm/help.cpp:335
msgid "Fly to upper right"
msgstr "Nach oben rechts fliegen"
-#: engines/scumm/help.cpp:324
+#: engines/scumm/help.cpp:336
msgid "Fly to right"
msgstr "Nach rechts fliegen"
-#: engines/scumm/help.cpp:325
+#: engines/scumm/help.cpp:337
msgid "Fly to lower right"
msgstr "Nach unten rechts fliegen"
-#: engines/scumm/scumm.cpp:1823
+#: engines/scumm/scumm.cpp:1832
#, c-format
msgid ""
"Native MIDI support requires the Roland Upgrade from LucasArts,\n"
@@ -3215,11 +3322,11 @@ msgstr ""
"Roland-Upgrade von LucasArts, aber %s\n"
"fehlt. Stattdessen wird AdLib verwendet."
-#: engines/scumm/scumm.cpp:2594
+#: engines/scumm/scumm.cpp:2644
msgid ""
-"Usually, Maniac Mansion would start now. But ScummVM doesn't do that yet. To "
-"play it, go to 'Add Game' in the ScummVM start menu and select the 'Maniac' "
-"directory inside the Tentacle game directory."
+"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 ""
"Normalerweise wќrde jetzt Maniac Mansion starten. ScummVM kann das jedoch "
"noch nicht. Um dieses Spiel zu spielen, klicken Sie auf \"Spiel hinzufќgen\" "
@@ -3231,12 +3338,16 @@ msgid ""
"Could not find the 'Loom' Macintosh executable to read the\n"
"instruments from. Music will be disabled."
msgstr ""
+"Macintosh-Programmdatei fќr Instrumente in \"Loom\" nicht\n"
+"gefunden. Musik wird abgeschaltet."
#: 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 ""
+"Macintosh-Programmdatei fќr Instrumente in \"Monkey Island\" nicht\n"
+"gefunden. Musik wird abgeschaltet."
#: engines/sky/compact.cpp:130
msgid ""
@@ -3286,7 +3397,7 @@ msgstr ""
#: engines/sword1/animation.cpp:568 engines/sword2/animation.cpp:470
#, c-format
msgid "Cutscene '%s' not found"
-msgstr "Zwischensequenz \"%s\" gefunden"
+msgstr "Zwischensequenz \"%s\" nicht gefunden"
#: engines/sword1/control.cpp:863
msgid ""
@@ -3346,24 +3457,66 @@ msgstr "Zeigt Objektbeschriftungen bei Mausberќhrung an."
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."
+"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
msgid ""
"The teenagent.dat file is compressed and zlib hasn't been included in this "
"executable. Please decompress it"
msgstr ""
-"Die Datei teenagent.dat ist gepackt und zlib zum Entpacken wurde in dieser "
-"ausfќhrbaren Datei nicht miteingebunden. Bitte entpacken Sie die Datei."
+"Die Datei \"teenagent.dat\" ist gepackt und zlib zum Entpacken wurde in "
+"dieser ausfќhrbaren Datei nicht miteingebunden. Bitte entpacken Sie die "
+"Datei."
#: engines/wintermute/detection.cpp:58
msgid "Show FPS-counter"
-msgstr ""
+msgstr "Zфhler fќr Bilder pro Sekunde anzeigen"
#: engines/wintermute/detection.cpp:59
msgid "Show the current number of frames per second in the upper left corner"
msgstr ""
+"Zeige die aktuelle Anzahl von Bildern pro Sekunde in der oberen linken Ecke"
+
+#: engines/zvision/detection.cpp:256
+msgid "Double FPS"
+msgstr "FPS verdoppeln"
+
+#: engines/zvision/detection.cpp:257
+msgid "Increase game FPS from 30 to 60"
+msgstr "Bilder pro Sekunde im Spiel von 30 auf 60 erhіhen"
+
+#: engines/zvision/detection.cpp:266
+msgid "Enable Venus"
+msgstr "Venus aktivieren"
+
+#: engines/zvision/detection.cpp:267
+msgid "Enable the Venus help system"
+msgstr "Aktiviere das Venus-Hilfesystem"
+
+#: engines/zvision/detection.cpp:276
+msgid "Disable animation while turning"
+msgstr "Animation wфhrend Drehen ausschalten"
+
+#: engines/zvision/detection.cpp:277
+msgid "Disable animation while turning in panoramic mode"
+msgstr "Animation wфhrend Drehen im Panorama-Modus ausschalten"
+
+#: engines/zvision/detection.cpp:286
+msgid "Use the hires MPEG movies"
+msgstr "Nutze hochauflіsende MPEG-Filme"
+
+#: engines/zvision/detection.cpp:287
+msgid ""
+"Use the hires MPEG movies of the DVD version, instead of the lowres AVI ones"
+msgstr ""
+"Verwende hochauflіsende MPEG-Filme der DVD-Version anstelle der AVI-Filme"
+
+#~ msgid "EGA undithering"
+#~ msgstr "Antifehlerdiffusion fќr EGA"
+
+#~ msgid "Enable undithering in EGA games"
+#~ msgstr "Aktiviert die Aufhebung der Fehlerdiffusion in EGA-Spielen."
#~ msgid "MPEG-2 cutscenes found but ScummVM has been built without MPEG-2"
#~ msgstr ""
@@ -3374,9 +3527,6 @@ msgstr ""
#~ msgid "Mass Add..."
#~ msgstr "Durchsuchen"
-#~ msgid "Mass Add..."
-#~ msgstr "Durchsuchen"
-
#~ msgid ""
#~ "Turns off General MIDI mapping for games with Roland MT-32 soundtrack"
#~ msgstr ""
diff --git a/po/es_ES.po b/po/es_ES.po
index 9f070de306..32f3aba74e 100644
--- a/po/es_ES.po
+++ b/po/es_ES.po
@@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: ScummVM 1.4.0svn\n"
"Report-Msgid-Bugs-To: scummvm-devel@lists.sf.net\n"
-"POT-Creation-Date: 2014-10-04 00:58+0100\n"
+"POT-Creation-Date: 2015-06-30 20:57+0100\n"
"PO-Revision-Date: 2014-07-06 20:39+0100\n"
"Last-Translator: \n"
"Language-Team: \n"
@@ -53,10 +53,11 @@ msgstr "Arriba"
#: gui/browser.cpp:75 gui/chooser.cpp:46 gui/KeysDialog.cpp:43
#: gui/launcher.cpp:351 gui/massadd.cpp:95 gui/options.cpp:1239
+#: gui/recorderdialog.cpp:70 gui/recorderdialog.cpp:156
#: gui/saveload-dialog.cpp:216 gui/saveload-dialog.cpp:276
-#: gui/saveload-dialog.cpp:547 gui/saveload-dialog.cpp:922
+#: gui/saveload-dialog.cpp:547 gui/saveload-dialog.cpp:931
#: gui/themebrowser.cpp:55 gui/fluidsynth-dialog.cpp:152
-#: engines/engine.cpp:452 backends/platform/wii/options.cpp:48
+#: engines/engine.cpp:483 backends/platform/wii/options.cpp:48
#: backends/events/default/default-events.cpp:196
#: backends/events/default/default-events.cpp:218
#: engines/drascula/saveload.cpp:49 engines/parallaction/saveload.cpp:274
@@ -69,9 +70,9 @@ msgid "Choose"
msgstr "Aceptar"
#: gui/gui-manager.cpp:117 backends/keymapper/remap-dialog.cpp:53
-#: 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
+#: 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"
@@ -87,7 +88,7 @@ msgstr "Mostrar el teclado"
msgid "Remap keys"
msgstr "Asignar teclas"
-#: gui/gui-manager.cpp:131 base/main.cpp:326 engines/scumm/help.cpp:86
+#: gui/gui-manager.cpp:131 base/main.cpp:326 engines/scumm/help.cpp:87
msgid "Toggle fullscreen"
msgstr "Activar/Desactivar pantalla completa"
@@ -101,13 +102,13 @@ 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:1240
-#: gui/saveload-dialog.cpp:923 gui/fluidsynth-dialog.cpp:153
-#: engines/engine.cpp:371 engines/engine.cpp:382
+#: 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:399 engines/parallaction/saveload.cpp:274
-#: engines/scumm/dialogs.cpp:193 engines/scumm/scumm.cpp:1825
+#: 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
@@ -477,7 +478,7 @@ msgstr ""
#: gui/launcher.cpp:793 gui/launcher.cpp:941 gui/launcher.cpp:1000
#: gui/fluidsynth-dialog.cpp:217
-#: backends/events/symbiansdl/symbiansdl-events.cpp:184
+#: 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
@@ -487,7 +488,7 @@ 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:184
+#: 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
@@ -524,6 +525,14 @@ 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
+msgid "Mass Add..."
+msgstr "Aёadir varios..."
+
+#: gui/launcher.cpp:1161
+msgid "Record..."
+msgstr ""
+
#: gui/massadd.cpp:79 gui/massadd.cpp:82
msgid "... progress ..."
msgstr "... progreso..."
@@ -622,7 +631,7 @@ msgid "Special dithering modes supported by some games"
msgstr "Modos especiales de expansiѓn compatibles con algunos juegos"
#: gui/options.cpp:760
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2249
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2298
msgid "Fullscreen mode"
msgstr "Pantalla completa"
@@ -944,6 +953,43 @@ msgstr ""
"El tema seleccionado no es compatible con el idioma actual. Si quieres usar "
"este tema debes cambiar a otro idioma primero."
+#: gui/recorderdialog.cpp:64
+msgid "Recorder or Playback Gameplay"
+msgstr ""
+
+#: gui/recorderdialog.cpp:69 gui/recorderdialog.cpp:156
+#: gui/saveload-dialog.cpp:220 gui/saveload-dialog.cpp:276
+msgid "Delete"
+msgstr "Borrar"
+
+#: gui/recorderdialog.cpp:71
+msgid "Record"
+msgstr ""
+
+#: gui/recorderdialog.cpp:72
+#, fuzzy
+msgid "Playback"
+msgstr "Jugar"
+
+#: gui/recorderdialog.cpp:74
+msgid "Edit"
+msgstr ""
+
+#: gui/recorderdialog.cpp:86 gui/recorderdialog.cpp:243
+#: gui/recorderdialog.cpp:253
+msgid "Author: "
+msgstr ""
+
+#: gui/recorderdialog.cpp:87 gui/recorderdialog.cpp:244
+#: gui/recorderdialog.cpp:254
+msgid "Notes: "
+msgstr ""
+
+#: gui/recorderdialog.cpp:155
+#, fuzzy
+msgid "Do you really want to delete this record?"
+msgstr "ПSeguro que quieres borrar esta partida?"
+
#: gui/saveload-dialog.cpp:167
msgid "List view"
msgstr "Modo lista"
@@ -964,23 +1010,19 @@ msgstr "No hay hora guardada"
msgid "No playtime saved"
msgstr "No hay tiempo guardado"
-#: gui/saveload-dialog.cpp:220 gui/saveload-dialog.cpp:276
-msgid "Delete"
-msgstr "Borrar"
-
#: gui/saveload-dialog.cpp:275
msgid "Do you really want to delete this saved game?"
msgstr "ПSeguro que quieres borrar esta partida?"
-#: gui/saveload-dialog.cpp:385 gui/saveload-dialog.cpp:875
+#: gui/saveload-dialog.cpp:385 gui/saveload-dialog.cpp:884
msgid "Date: "
msgstr "Fecha: "
-#: gui/saveload-dialog.cpp:389 gui/saveload-dialog.cpp:881
+#: gui/saveload-dialog.cpp:389 gui/saveload-dialog.cpp:890
msgid "Time: "
msgstr "Hora: "
-#: gui/saveload-dialog.cpp:395 gui/saveload-dialog.cpp:889
+#: gui/saveload-dialog.cpp:395 gui/saveload-dialog.cpp:898
msgid "Playtime: "
msgstr "Tiempo: "
@@ -996,19 +1038,19 @@ msgstr "Siguiente"
msgid "Prev"
msgstr "Anterior"
-#: gui/saveload-dialog.cpp:739
+#: gui/saveload-dialog.cpp:748
msgid "New Save"
msgstr "Guardar"
-#: gui/saveload-dialog.cpp:739
+#: gui/saveload-dialog.cpp:748
msgid "Create a new save game"
msgstr "Guarda una nueva partida"
-#: gui/saveload-dialog.cpp:868
+#: gui/saveload-dialog.cpp:877
msgid "Name: "
msgstr "Nombre:"
-#: gui/saveload-dialog.cpp:940
+#: gui/saveload-dialog.cpp:949
#, c-format
msgid "Enter a description for slot %d:"
msgstr "Introduce una descripciѓn para la ranura %d:"
@@ -1161,7 +1203,7 @@ msgstr "Saltar frase"
msgid "Error running game:"
msgstr "Error al ejecutar el juego:"
-#: base/main.cpp:536
+#: base/main.cpp:554
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"
@@ -1278,7 +1320,7 @@ 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:758
+#: engines/pegasus/pegasus.cpp:377 engines/sci/engine/kfile.cpp:759
#: engines/toltecs/menu.cpp:281 engines/tsage/scenes.cpp:598
msgid "Save game:"
msgstr "Guardar partida"
@@ -1291,7 +1333,7 @@ msgstr "Guardar partida"
#: 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:758 engines/scumm/dialogs.cpp:188
+#: engines/sci/engine/kfile.cpp:759 engines/scumm/dialogs.cpp:188
#: engines/toltecs/menu.cpp:281 engines/tsage/scenes.cpp:598
msgid "Save"
msgstr "Guardar"
@@ -1330,23 +1372,23 @@ msgstr "~C~ancelar"
msgid "~K~eys"
msgstr "~T~eclas"
-#: engines/engine.cpp:245
+#: engines/engine.cpp:276
msgid "Could not initialize color format."
msgstr "No se ha podido iniciar el formato de color."
-#: engines/engine.cpp:253
+#: engines/engine.cpp:284
msgid "Could not switch to video mode: '"
msgstr "No se ha podido cambiar al modo de video: '"
-#: engines/engine.cpp:262
+#: engines/engine.cpp:293
msgid "Could not apply aspect ratio setting."
msgstr "No se ha podido aplicar el ajuste de correcciѓn de aspecto"
-#: engines/engine.cpp:267
+#: engines/engine.cpp:298
msgid "Could not apply fullscreen setting."
msgstr "No se ha podido aplicar el ajuste de pantalla completa."
-#: engines/engine.cpp:367
+#: engines/engine.cpp:398
msgid ""
"You appear to be playing this game directly\n"
"from the CD. This is known to cause problems,\n"
@@ -1360,7 +1402,7 @@ msgstr ""
"copiar los archivos del juego al disco duro.\n"
"Consulta el archivo README para mсs detalles."
-#: engines/engine.cpp:378
+#: engines/engine.cpp:409
msgid ""
"This game has audio tracks in its disk. These\n"
"tracks need to be ripped from the disk using\n"
@@ -1374,7 +1416,7 @@ msgstr ""
"poder escuchar la mњsica del juego.\n"
"Consulta el archivo README para mсs detalles."
-#: engines/engine.cpp:436
+#: engines/engine.cpp:467
#, c-format
msgid ""
"Gamestate load failed (%s)! Please consult the README for basic information, "
@@ -1384,7 +1426,7 @@ msgstr ""
"README para encontrar informaciѓn bсsica e instrucciones sobre cѓmo obtener "
"mсs ayuda."
-#: engines/engine.cpp:449
+#: engines/engine.cpp:480
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 "
@@ -1394,7 +1436,7 @@ 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:452
+#: engines/engine.cpp:483
msgid "Start anyway"
msgstr "Jugar aun asэ"
@@ -1604,11 +1646,11 @@ msgstr "Modo Touchpad activado."
msgid "Touchpad mode disabled."
msgstr "Modo Touchpad desactivado."
-#: backends/platform/maemo/maemo.cpp:209
+#: backends/platform/maemo/maemo.cpp:208
msgid "Click Mode"
msgstr "Modo clic"
-#: backends/platform/maemo/maemo.cpp:215
+#: backends/platform/maemo/maemo.cpp:214
#: backends/platform/symbian/src/SymbianActions.cpp:42
#: backends/platform/wince/CEActionsPocket.cpp:60
#: backends/platform/wince/CEActionsSmartphone.cpp:43
@@ -1616,11 +1658,11 @@ msgstr "Modo clic"
msgid "Left Click"
msgstr "Clic izquierdo"
-#: backends/platform/maemo/maemo.cpp:218
+#: backends/platform/maemo/maemo.cpp:217
msgid "Middle Click"
msgstr "Clic central"
-#: backends/platform/maemo/maemo.cpp:221
+#: 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
@@ -1657,19 +1699,19 @@ msgctxt "lowres"
msgid "Normal (no scaling)"
msgstr "Normal"
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2148
+#: 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:2154
+#: 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:2209
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2258
msgid "Active graphics filter:"
msgstr "Filtro de grсficos activo:"
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2251
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2300
msgid "Windowed mode"
msgstr "Modo ventana"
@@ -1728,8 +1770,8 @@ msgstr "Modo rсpido"
#: 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:82
-#: engines/scumm/help.cpp:84
+#: engines/scumm/dialogs.cpp:192 engines/scumm/help.cpp:83
+#: engines/scumm/help.cpp:85
msgid "Quit"
msgstr "Salir"
@@ -1749,7 +1791,7 @@ msgstr "Teclado virtual"
msgid "Key mapper"
msgstr "Asignaciѓn de teclas"
-#: backends/events/symbiansdl/symbiansdl-events.cpp:184
+#: backends/events/symbiansdl/symbiansdl-events.cpp:186
msgid "Do you want to quit ?"
msgstr "ПQuieres salir?"
@@ -2085,34 +2127,56 @@ msgstr "Clic activado"
msgid "Clicking Disabled"
msgstr "Clic desactivado"
-#: engines/agi/detection.cpp:142 engines/drascula/detection.cpp:302
+#: 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.cpp:103
+#: engines/zvision/detection.cpp:246
msgid "Use original save/load screens"
msgstr "Usar pantallas de guardar/cargar originales"
-#: engines/agi/detection.cpp:143 engines/drascula/detection.cpp:303
+#: 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/zvision/detection.cpp:104
+#: engines/zvision/detection.cpp:247
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)"
+
+#: engines/agi/detection.cpp:158
+msgid ""
+"Use an alternative palette, common for all Amiga games. This was the old "
+"behavior"
+msgstr ""
+
+#: engines/agi/detection.cpp:167
+#, fuzzy
+msgid "Mouse support"
+msgstr "Permitir omisiones"
+
+#: 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:857 engines/toltecs/menu.cpp:256
+#: engines/sci/engine/kfile.cpp:858 engines/toltecs/menu.cpp:256
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:857 engines/toltecs/menu.cpp:256
+#: engines/sci/engine/kfile.cpp:858 engines/toltecs/menu.cpp:256
msgid "Restore"
msgstr "Cargar"
-#: engines/agos/saveload.cpp:160 engines/scumm/scumm.cpp:2368
+#: engines/agos/saveload.cpp:160 engines/scumm/scumm.cpp:2377
#, c-format
msgid ""
"Failed to load game state from file:\n"
@@ -2123,7 +2187,7 @@ msgstr ""
"\n"
"%s"
-#: engines/agos/saveload.cpp:195 engines/scumm/scumm.cpp:2361
+#: engines/agos/saveload.cpp:195 engines/scumm/scumm.cpp:2370
#, c-format
msgid ""
"Failed to save game state to file:\n"
@@ -2134,7 +2198,7 @@ msgstr ""
"\n"
"%s"
-#: engines/agos/saveload.cpp:203 engines/scumm/scumm.cpp:2379
+#: engines/agos/saveload.cpp:203 engines/scumm/scumm.cpp:2388
#, c-format
msgid ""
"Successfully saved game state in file:\n"
@@ -2150,12 +2214,12 @@ msgstr ""
msgid "Cutscene file '%s' not found!"
msgstr "No se ha encontrado el vэdeo '%s'"
-#: engines/cge/detection.cpp:105 engines/cge2/detection.cpp:81
+#: engines/cge/detection.cpp:105 engines/cge2/detection.cpp:101
#, fuzzy
msgid "Color Blind Mode"
msgstr "Modo clic"
-#: engines/cge/detection.cpp:106 engines/cge2/detection.cpp:82
+#: engines/cge/detection.cpp:106 engines/cge2/detection.cpp:102
msgid "Enable Color Blind Mode by default"
msgstr ""
@@ -2207,7 +2271,7 @@ msgstr "Velocidad rсpida de vэdeos"
msgid "Play movies at an increased speed"
msgstr "Reproducir vэdeos a mayor velocidad"
-#: engines/groovie/script.cpp:399
+#: engines/groovie/script.cpp:408
msgid "Failed to save game"
msgstr "Fallo al guardar la partida"
@@ -2507,12 +2571,12 @@ msgstr ""
"Usa una introducciѓn alternativa para el juego (solo para la versiѓn CD)"
#: engines/sci/detection.cpp:374
-msgid "EGA undithering"
-msgstr "Difuminado EGA"
+msgid "Skip EGA dithering pass (full color backgrounds)"
+msgstr ""
#: engines/sci/detection.cpp:375
-msgid "Enable undithering in EGA games"
-msgstr "Activar difuminado en los juegos EGA"
+msgid "Skip dithering pass in EGA games, graphics are shown with full colors"
+msgstr ""
#: engines/sci/detection.cpp:384
msgid "Prefer digital sound effects"
@@ -2585,12 +2649,14 @@ msgstr "Juego pausado. Pulsa Espacio para continuar."
#. "Moechten Sie wirklich neu starten? (J/N)J"
#. Will react to J as 'Yes'
#: engines/scumm/dialogs.cpp:183
-msgid "Are you sure you want to restart? (Y/N)"
+#, fuzzy
+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
-msgid "Are you sure you want to quit? (Y/N)"
+#, fuzzy
+msgid "Are you sure you want to quit? (Y/N)Y"
msgstr "ПSeguro que quieres salir? (S/N)S"
#: engines/scumm/dialogs.cpp:190
@@ -2678,516 +2744,541 @@ msgstr "Prсctica"
msgid "Expert"
msgstr "Experto"
-#: engines/scumm/help.cpp:73
+#: engines/scumm/help.cpp:74
msgid "Common keyboard commands:"
msgstr "Comandos bсsicos de teclado:"
-#: engines/scumm/help.cpp:74
+#: engines/scumm/help.cpp:75
msgid "Save / Load dialog"
msgstr "Pantalla de guardar / cargar"
-#: engines/scumm/help.cpp:76
+#: engines/scumm/help.cpp:77
msgid "Skip line of text"
msgstr "Saltar frase"
-#: engines/scumm/help.cpp:77
+#: engines/scumm/help.cpp:78
msgid "Esc"
msgstr "Esc"
-#: engines/scumm/help.cpp:77
+#: engines/scumm/help.cpp:78
msgid "Skip cutscene"
msgstr "Saltar escena"
-#: engines/scumm/help.cpp:78
+#: engines/scumm/help.cpp:79
msgid "Space"
msgstr "Espacio"
-#: engines/scumm/help.cpp:78
+#: engines/scumm/help.cpp:79
msgid "Pause game"
msgstr "Pausar el juego"
-#: engines/scumm/help.cpp:79 engines/scumm/help.cpp:84
-#: engines/scumm/help.cpp:95 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: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:79
+#: engines/scumm/help.cpp:80
msgid "Load game state 1-10"
msgstr "Cargar partida 1-10"
-#: engines/scumm/help.cpp:80 engines/scumm/help.cpp:84
-#: engines/scumm/help.cpp:86 engines/scumm/help.cpp:100
-#: engines/scumm/help.cpp:101 engines/scumm/help.cpp:102
+#: 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:80
+#: engines/scumm/help.cpp:81
msgid "Save game state 1-10"
msgstr "Guardar partida 1-10"
-#: engines/scumm/help.cpp:86 engines/scumm/help.cpp:89
+#: engines/scumm/help.cpp:87 engines/scumm/help.cpp:90
msgid "Enter"
msgstr "Enter"
-#: engines/scumm/help.cpp:87
+#: engines/scumm/help.cpp:88
msgid "Music volume up / down"
msgstr "Subir / Bajar el volumen de la mњsica"
-#: engines/scumm/help.cpp:88
+#: engines/scumm/help.cpp:89
msgid "Text speed slower / faster"
msgstr "Aumentar / Disminuir la vel. de texto"
-#: engines/scumm/help.cpp:89
+#: engines/scumm/help.cpp:90
msgid "Simulate left mouse button"
msgstr "Simular botѓn izquierdo del ratѓn"
-#: engines/scumm/help.cpp:90
+#: engines/scumm/help.cpp:91
msgid "Tab"
msgstr "Tab"
-#: engines/scumm/help.cpp:90
+#: engines/scumm/help.cpp:91
msgid "Simulate right mouse button"
msgstr "Simular botѓn derecho del ratѓn"
-#: engines/scumm/help.cpp:93
+#: engines/scumm/help.cpp:94
msgid "Special keyboard commands:"
msgstr "Comandos especiales de teclado:"
-#: engines/scumm/help.cpp:94
+#: engines/scumm/help.cpp:95
msgid "Show / Hide console"
msgstr "Mostrar / Ocultar consola"
-#: engines/scumm/help.cpp:95
+#: engines/scumm/help.cpp:96
msgid "Start the debugger"
msgstr "Iniciar debugger"
-#: engines/scumm/help.cpp:96
+#: engines/scumm/help.cpp:97
msgid "Show memory consumption"
msgstr "Mostrar consumo de memoria"
-#: engines/scumm/help.cpp:97
+#: engines/scumm/help.cpp:98
msgid "Run in fast mode (*)"
msgstr "Ejecutar en modo rсpido (*)"
-#: engines/scumm/help.cpp:98
+#: engines/scumm/help.cpp:99
msgid "Run in really fast mode (*)"
msgstr "Ejecutar en modo muy rсpido (*)"
-#: engines/scumm/help.cpp:99
+#: engines/scumm/help.cpp:100
msgid "Toggle mouse capture"
msgstr "Activar/Desactivar captura de ratѓn"
-#: engines/scumm/help.cpp:100
+#: engines/scumm/help.cpp:101
msgid "Switch between graphics filters"
msgstr "Alternar entre filtros grсficos"
-#: engines/scumm/help.cpp:101
+#: engines/scumm/help.cpp:102
msgid "Increase / Decrease scale factor"
msgstr "Aumentar / Disminuir factor de escalado"
-#: engines/scumm/help.cpp:102
+#: engines/scumm/help.cpp:103
msgid "Toggle aspect-ratio correction"
msgstr "Activar/Desactivar correcciѓn de aspecto"
-#: engines/scumm/help.cpp:107
+#: engines/scumm/help.cpp:108
msgid "* Note that using ctrl-f and"
msgstr "* No se recomienda utilizar"
-#: engines/scumm/help.cpp:108
+#: engines/scumm/help.cpp:109
msgid " ctrl-g are not recommended"
msgstr " ctrl-f y ctrl-g, ya que pueden"
-#: engines/scumm/help.cpp:109
+#: engines/scumm/help.cpp:110
msgid " since they may cause crashes"
msgstr " provocar cuelgues o un"
-#: engines/scumm/help.cpp:110
+#: engines/scumm/help.cpp:111
msgid " or incorrect game behavior."
msgstr " funcionamiento incorrecto del juego."
-#: engines/scumm/help.cpp:114
+#: engines/scumm/help.cpp:115
msgid "Spinning drafts on the keyboard:"
msgstr "Tejer hechizos con el teclado:"
-#: engines/scumm/help.cpp:116
+#: engines/scumm/help.cpp:117
msgid "Main game controls:"
msgstr "Controles bсsicos:"
-#: engines/scumm/help.cpp:121 engines/scumm/help.cpp:136
-#: engines/scumm/help.cpp:161
+#: engines/scumm/help.cpp:122 engines/scumm/help.cpp:137
+#: engines/scumm/help.cpp:162
msgid "Push"
msgstr "Empujar"
-#: engines/scumm/help.cpp:122 engines/scumm/help.cpp:137
-#: engines/scumm/help.cpp:162
+#: engines/scumm/help.cpp:123 engines/scumm/help.cpp:138
+#: engines/scumm/help.cpp:163
msgid "Pull"
msgstr "Tirar"
-#: engines/scumm/help.cpp:123 engines/scumm/help.cpp:138
-#: engines/scumm/help.cpp:163 engines/scumm/help.cpp:197
-#: engines/scumm/help.cpp:207
+#: 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 "Dar"
-#: engines/scumm/help.cpp:124 engines/scumm/help.cpp:139
-#: engines/scumm/help.cpp:164 engines/scumm/help.cpp:190
-#: engines/scumm/help.cpp:208
+#: 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 "Abrir"
-#: engines/scumm/help.cpp:126
+#: engines/scumm/help.cpp:127
msgid "Go to"
msgstr "Ir a"
-#: engines/scumm/help.cpp:127
+#: engines/scumm/help.cpp:128
msgid "Get"
msgstr "Coger"
-#: engines/scumm/help.cpp:128 engines/scumm/help.cpp:152
-#: engines/scumm/help.cpp:170 engines/scumm/help.cpp:198
-#: engines/scumm/help.cpp:213 engines/scumm/help.cpp:224
-#: engines/scumm/help.cpp:250
+#: 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 "Usar"
-#: engines/scumm/help.cpp:129 engines/scumm/help.cpp:141
+#: engines/scumm/help.cpp:130 engines/scumm/help.cpp:142
msgid "Read"
msgstr "Leer"
-#: engines/scumm/help.cpp:130 engines/scumm/help.cpp:147
+#: engines/scumm/help.cpp:131 engines/scumm/help.cpp:148
msgid "New kid"
msgstr "Cambiar personaje"
-#: engines/scumm/help.cpp:131 engines/scumm/help.cpp:153
-#: engines/scumm/help.cpp:171
+#: engines/scumm/help.cpp:132 engines/scumm/help.cpp:154
+#: engines/scumm/help.cpp:172
msgid "Turn on"
msgstr "Encender"
-#: engines/scumm/help.cpp:132 engines/scumm/help.cpp:154
-#: engines/scumm/help.cpp:172
+#: engines/scumm/help.cpp:133 engines/scumm/help.cpp:155
+#: engines/scumm/help.cpp:173
msgid "Turn off"
msgstr "Apagar"
-#: engines/scumm/help.cpp:142 engines/scumm/help.cpp:167
-#: engines/scumm/help.cpp:194
+#: engines/scumm/help.cpp:143 engines/scumm/help.cpp:168
+#: engines/scumm/help.cpp:195
msgid "Walk to"
msgstr "Ir a"
-#: engines/scumm/help.cpp:143 engines/scumm/help.cpp:168
-#: engines/scumm/help.cpp:195 engines/scumm/help.cpp:210
-#: engines/scumm/help.cpp:227
+#: 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 "Recoger"
-#: engines/scumm/help.cpp:144 engines/scumm/help.cpp:169
+#: engines/scumm/help.cpp:145 engines/scumm/help.cpp:170
msgid "What is"
msgstr "Quщ es"
-#: engines/scumm/help.cpp:146
+#: engines/scumm/help.cpp:147
msgid "Unlock"
msgstr "Abrir con llave"
-#: engines/scumm/help.cpp:149
+#: engines/scumm/help.cpp:150
msgid "Put on"
msgstr "Ponerse"
-#: engines/scumm/help.cpp:150
+#: engines/scumm/help.cpp:151
msgid "Take off"
msgstr "Quitarse"
-#: engines/scumm/help.cpp:156
+#: engines/scumm/help.cpp:157
msgid "Fix"
msgstr "Arreglar"
-#: engines/scumm/help.cpp:158
+#: engines/scumm/help.cpp:159
msgid "Switch"
msgstr "Cambiar"
-#: engines/scumm/help.cpp:166 engines/scumm/help.cpp:228
+#: engines/scumm/help.cpp:167 engines/scumm/help.cpp:229
msgid "Look"
msgstr "Mirar"
-#: engines/scumm/help.cpp:173 engines/scumm/help.cpp:223
+#: engines/scumm/help.cpp:174 engines/scumm/help.cpp:224
msgid "Talk"
msgstr "Hablar"
-#: engines/scumm/help.cpp:174
+#: engines/scumm/help.cpp:175
msgid "Travel"
msgstr "Viajar"
-#: engines/scumm/help.cpp:175
+#: engines/scumm/help.cpp:176
msgid "To Henry / To Indy"
msgstr "Henry / Indy"
#. I18N: These are different musical notes
-#: engines/scumm/help.cpp:179
+#: engines/scumm/help.cpp:180
msgid "play C minor on distaff"
msgstr "Tocar do menor con el bastѓn"
-#: engines/scumm/help.cpp:180
+#: engines/scumm/help.cpp:181
msgid "play D on distaff"
msgstr "Tocar re con el bastѓn"
-#: engines/scumm/help.cpp:181
+#: engines/scumm/help.cpp:182
msgid "play E on distaff"
msgstr "Tocar mi con el bastѓn"
-#: engines/scumm/help.cpp:182
+#: engines/scumm/help.cpp:183
msgid "play F on distaff"
msgstr "Tocar fa con el bastѓn"
-#: engines/scumm/help.cpp:183
+#: engines/scumm/help.cpp:184
msgid "play G on distaff"
msgstr "Tocar sol con el bastѓn"
-#: engines/scumm/help.cpp:184
+#: engines/scumm/help.cpp:185
msgid "play A on distaff"
msgstr "Tocar la con el bastѓn"
-#: engines/scumm/help.cpp:185
+#: engines/scumm/help.cpp:186
msgid "play B on distaff"
msgstr "Tocar si con el bastѓn"
-#: engines/scumm/help.cpp:186
+#: engines/scumm/help.cpp:187
msgid "play C major on distaff"
msgstr "Tocar do mayor con el bastѓn"
-#: engines/scumm/help.cpp:192 engines/scumm/help.cpp:214
+#: engines/scumm/help.cpp:193 engines/scumm/help.cpp:215
msgid "puSh"
msgstr "Empujar"
-#: engines/scumm/help.cpp:193 engines/scumm/help.cpp:215
+#: engines/scumm/help.cpp:194 engines/scumm/help.cpp:216
msgid "pull (Yank)"
msgstr "Tirar"
-#: engines/scumm/help.cpp:196 engines/scumm/help.cpp:212
-#: engines/scumm/help.cpp:248
+#: engines/scumm/help.cpp:197 engines/scumm/help.cpp:213
+#: engines/scumm/help.cpp:249
msgid "Talk to"
msgstr "Hablar con"
-#: engines/scumm/help.cpp:199 engines/scumm/help.cpp:211
+#: engines/scumm/help.cpp:200 engines/scumm/help.cpp:212
msgid "Look at"
msgstr "Mirar"
-#: engines/scumm/help.cpp:200
+#: engines/scumm/help.cpp:201
msgid "turn oN"
msgstr "Encender"
-#: engines/scumm/help.cpp:201
+#: engines/scumm/help.cpp:202
msgid "turn oFf"
msgstr "Apagar"
-#: engines/scumm/help.cpp:217
+#: engines/scumm/help.cpp:218
msgid "KeyUp"
msgstr "Arriba"
-#: engines/scumm/help.cpp:217
+#: engines/scumm/help.cpp:218
msgid "Highlight prev dialogue"
msgstr "Seleccionar diсlogo anterior"
-#: engines/scumm/help.cpp:218
+#: engines/scumm/help.cpp:219
msgid "KeyDown"
msgstr "Abajo"
-#: engines/scumm/help.cpp:218
+#: engines/scumm/help.cpp:219
msgid "Highlight next dialogue"
msgstr "Seleccionar diсlogo siguiente"
-#: engines/scumm/help.cpp:222
+#: engines/scumm/help.cpp:223
msgid "Walk"
msgstr "Caminar"
-#: engines/scumm/help.cpp:225 engines/scumm/help.cpp:234
-#: engines/scumm/help.cpp:241 engines/scumm/help.cpp:249
+#: engines/scumm/help.cpp:226 engines/scumm/help.cpp:235
+#: engines/scumm/help.cpp:242 engines/scumm/help.cpp:250
msgid "Inventory"
msgstr "Inventario"
-#: engines/scumm/help.cpp:226
+#: engines/scumm/help.cpp:227
msgid "Object"
msgstr "Objeto"
-#: engines/scumm/help.cpp:229
+#: engines/scumm/help.cpp:230
msgid "Black and White / Color"
msgstr "Blanco y negro / Color"
-#: engines/scumm/help.cpp:232
+#: engines/scumm/help.cpp:233
msgid "Eyes"
msgstr "Ojos"
-#: engines/scumm/help.cpp:233
+#: engines/scumm/help.cpp:234
msgid "Tongue"
msgstr "Lengua"
-#: engines/scumm/help.cpp:235
+#: engines/scumm/help.cpp:236
msgid "Punch"
msgstr "Puёetazo"
-#: engines/scumm/help.cpp:236
+#: engines/scumm/help.cpp:237
msgid "Kick"
msgstr "Patada"
-#: engines/scumm/help.cpp:239 engines/scumm/help.cpp:247
+#: engines/scumm/help.cpp:240 engines/scumm/help.cpp:248
msgid "Examine"
msgstr "Examinar"
-#: engines/scumm/help.cpp:240
+#: engines/scumm/help.cpp:241
msgid "Regular cursor"
msgstr "Cursor normal"
#. I18N: Comm is a communication device
-#: engines/scumm/help.cpp:243
+#: engines/scumm/help.cpp:244
msgid "Comm"
msgstr "Comm"
-#: engines/scumm/help.cpp:246
+#: engines/scumm/help.cpp:247
msgid "Save / Load / Options"
msgstr "Guardar / Cargar / Opciones"
-#: engines/scumm/help.cpp:255
+#: engines/scumm/help.cpp:256
msgid "Other game controls:"
msgstr "Otros controles:"
-#: engines/scumm/help.cpp:257 engines/scumm/help.cpp:267
+#: engines/scumm/help.cpp:258 engines/scumm/help.cpp:268
msgid "Inventory:"
msgstr "Inventario:"
-#: engines/scumm/help.cpp:258 engines/scumm/help.cpp:274
+#: engines/scumm/help.cpp:259 engines/scumm/help.cpp:275
msgid "Scroll list up"
msgstr "Subir"
-#: engines/scumm/help.cpp:259 engines/scumm/help.cpp:275
+#: engines/scumm/help.cpp:260 engines/scumm/help.cpp:276
msgid "Scroll list down"
msgstr "Bajar"
-#: engines/scumm/help.cpp:260 engines/scumm/help.cpp:268
+#: engines/scumm/help.cpp:261 engines/scumm/help.cpp:269
msgid "Upper left item"
msgstr "Objeto superior izquierdo"
-#: engines/scumm/help.cpp:261 engines/scumm/help.cpp:270
+#: engines/scumm/help.cpp:262 engines/scumm/help.cpp:271
msgid "Lower left item"
msgstr "Objeto inferior izquierdo"
-#: engines/scumm/help.cpp:262 engines/scumm/help.cpp:271
+#: engines/scumm/help.cpp:263 engines/scumm/help.cpp:272
msgid "Upper right item"
msgstr "Objeto superior derecho"
-#: engines/scumm/help.cpp:263 engines/scumm/help.cpp:273
+#: engines/scumm/help.cpp:264 engines/scumm/help.cpp:274
msgid "Lower right item"
msgstr "Objeto inferior derecho"
-#: engines/scumm/help.cpp:269
+#: engines/scumm/help.cpp:270
msgid "Middle left item"
msgstr "Objeto izquierdo del medio"
-#: engines/scumm/help.cpp:272
+#: engines/scumm/help.cpp:273
msgid "Middle right item"
msgstr "Objeto derecho del medio"
-#: engines/scumm/help.cpp:279 engines/scumm/help.cpp:284
+#: engines/scumm/help.cpp:280 engines/scumm/help.cpp:285
msgid "Switching characters:"
msgstr "Cambiar personaje:"
-#: engines/scumm/help.cpp:281
+#: engines/scumm/help.cpp:282
msgid "Second kid"
msgstr "Segundo chaval"
-#: engines/scumm/help.cpp:282
+#: engines/scumm/help.cpp:283
msgid "Third kid"
msgstr "Tercer chaval"
-#: engines/scumm/help.cpp:294
+#: engines/scumm/help.cpp:292
+#, fuzzy
+msgid "Toggle Inventory/IQ Points display"
+msgstr "Activar/Desactivar pantalla de datos"
+
+#: engines/scumm/help.cpp:293
+msgid "Toggle Keyboard/Mouse Fighting (*)"
+msgstr ""
+
+#: engines/scumm/help.cpp:295
+msgid "* Keyboard Fighting is always on,"
+msgstr ""
+
+#: engines/scumm/help.cpp:296
+msgid " so despite the in-game message this"
+msgstr ""
+
+#: engines/scumm/help.cpp:297
+msgid " actually toggles Mouse Fighting Off/On"
+msgstr ""
+
+#: engines/scumm/help.cpp:304
msgid "Fighting controls (numpad):"
msgstr "Controles de lucha (tecl. num.):"
-#: engines/scumm/help.cpp:295 engines/scumm/help.cpp:296
-#: engines/scumm/help.cpp:297
+#: engines/scumm/help.cpp:305 engines/scumm/help.cpp:306
+#: engines/scumm/help.cpp:307
msgid "Step back"
msgstr "Retroceder"
-#: engines/scumm/help.cpp:298
+#: engines/scumm/help.cpp:308
msgid "Block high"
msgstr "Bloqueo alto"
-#: engines/scumm/help.cpp:299
+#: engines/scumm/help.cpp:309
msgid "Block middle"
msgstr "Bloqueo medio"
-#: engines/scumm/help.cpp:300
+#: engines/scumm/help.cpp:310
msgid "Block low"
msgstr "Bloqueo bajo"
-#: engines/scumm/help.cpp:301
+#: engines/scumm/help.cpp:311
msgid "Punch high"
msgstr "Puёetazo alto"
-#: engines/scumm/help.cpp:302
+#: engines/scumm/help.cpp:312
msgid "Punch middle"
msgstr "Puёetazo medio"
-#: engines/scumm/help.cpp:303
+#: engines/scumm/help.cpp:313
msgid "Punch low"
msgstr "Puёetazo bajo"
-#: engines/scumm/help.cpp:306
+#: engines/scumm/help.cpp:315
+msgid "Sucker punch"
+msgstr ""
+
+#: engines/scumm/help.cpp:318
msgid "These are for Indy on left."
msgstr "Vсlidos cuando Indy estс a la izquierda."
-#: engines/scumm/help.cpp:307
+#: engines/scumm/help.cpp:319
msgid "When Indy is on the right,"
msgstr "Cuando Indy estс a la derecha,"
-#: engines/scumm/help.cpp:308
+#: engines/scumm/help.cpp:320
msgid "7, 4, and 1 are switched with"
msgstr "7, 4 y 1 se cambian por"
-#: engines/scumm/help.cpp:309
+#: engines/scumm/help.cpp:321
msgid "9, 6, and 3, respectively."
msgstr "9, 6 y 3, respectivamente."
-#: engines/scumm/help.cpp:316
+#: engines/scumm/help.cpp:328
msgid "Biplane controls (numpad):"
msgstr "Controles del biplano (tecl. num.)"
-#: engines/scumm/help.cpp:317
+#: engines/scumm/help.cpp:329
msgid "Fly to upper left"
msgstr "Volar arriba y a la izquierda"
-#: engines/scumm/help.cpp:318
+#: engines/scumm/help.cpp:330
msgid "Fly to left"
msgstr "Volar a la izquierda"
-#: engines/scumm/help.cpp:319
+#: engines/scumm/help.cpp:331
msgid "Fly to lower left"
msgstr "Volar abajo y a la izquierda"
-#: engines/scumm/help.cpp:320
+#: engines/scumm/help.cpp:332
msgid "Fly upwards"
msgstr "Volar arriba"
-#: engines/scumm/help.cpp:321
+#: engines/scumm/help.cpp:333
msgid "Fly straight"
msgstr "Volar recto"
-#: engines/scumm/help.cpp:322
+#: engines/scumm/help.cpp:334
msgid "Fly down"
msgstr "Volar abajo"
-#: engines/scumm/help.cpp:323
+#: engines/scumm/help.cpp:335
msgid "Fly to upper right"
msgstr "Volar arriba y a la derecha"
-#: engines/scumm/help.cpp:324
+#: engines/scumm/help.cpp:336
msgid "Fly to right"
msgstr "Volar a la derecha"
-#: engines/scumm/help.cpp:325
+#: engines/scumm/help.cpp:337
msgid "Fly to lower right"
msgstr "Volar abajo y a la derecha"
-#: engines/scumm/scumm.cpp:1823
+#: engines/scumm/scumm.cpp:1832
#, c-format
msgid ""
"Native MIDI support requires the Roland Upgrade from LucasArts,\n"
@@ -3196,11 +3287,12 @@ 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:2594
+#: engines/scumm/scumm.cpp:2644
+#, fuzzy
msgid ""
-"Usually, Maniac Mansion would start now. But ScummVM doesn't do that yet. To "
-"play it, go to 'Add Game' in the ScummVM start menu and select the 'Maniac' "
-"directory inside the Tentacle game directory."
+"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 "
@@ -3343,6 +3435,48 @@ msgstr ""
msgid "Show the current number of frames per second in the upper left corner"
msgstr ""
+#: engines/zvision/detection.cpp:256
+msgid "Double FPS"
+msgstr ""
+
+#: engines/zvision/detection.cpp:257
+msgid "Increase game FPS from 30 to 60"
+msgstr ""
+
+#: engines/zvision/detection.cpp:266
+#, fuzzy
+msgid "Enable Venus"
+msgstr "Activar el modo helio"
+
+#: engines/zvision/detection.cpp:267
+msgid "Enable the Venus help system"
+msgstr ""
+
+#: engines/zvision/detection.cpp:276
+msgid "Disable animation while turning"
+msgstr ""
+
+#: engines/zvision/detection.cpp:277
+msgid "Disable animation while turning in panoramic mode"
+msgstr ""
+
+#: engines/zvision/detection.cpp:286
+msgid "Use the hires MPEG movies"
+msgstr ""
+
+#: engines/zvision/detection.cpp:287
+#, fuzzy
+msgid ""
+"Use the hires MPEG movies of the DVD version, instead of the lowres AVI ones"
+msgstr ""
+"Usar los cursores plateados alternativos, en vez de los dorados normales"
+
+#~ msgid "EGA undithering"
+#~ msgstr "Difuminado EGA"
+
+#~ msgid "Enable undithering in EGA games"
+#~ msgstr "Activar difuminado en los juegos EGA"
+
#~ msgid "MPEG-2 cutscenes found but ScummVM has been built without MPEG-2"
#~ msgstr ""
#~ "Se han encontrado vэdeos MPEG-2, pero se ha compilado ScummVM sin MPEG-2"
@@ -3351,9 +3485,6 @@ msgstr ""
#~ msgid "Mass Add..."
#~ msgstr "Aёad. varios"
-#~ msgid "Mass Add..."
-#~ msgstr "Aёadir varios..."
-
#~ msgid ""
#~ "Turns off General MIDI mapping for games with Roland MT-32 soundtrack"
#~ msgstr ""
diff --git a/po/eu.po b/po/eu.po
index 41318f72b6..9381f0576c 100644
--- a/po/eu.po
+++ b/po/eu.po
@@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: ScummVM 1.5.0git\n"
"Report-Msgid-Bugs-To: scummvm-devel@lists.sf.net\n"
-"POT-Creation-Date: 2014-10-04 00:58+0100\n"
+"POT-Creation-Date: 2015-06-30 20:57+0100\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"
@@ -53,10 +53,11 @@ msgstr "Joan gora"
#: gui/browser.cpp:75 gui/chooser.cpp:46 gui/KeysDialog.cpp:43
#: gui/launcher.cpp:351 gui/massadd.cpp:95 gui/options.cpp:1239
+#: gui/recorderdialog.cpp:70 gui/recorderdialog.cpp:156
#: gui/saveload-dialog.cpp:216 gui/saveload-dialog.cpp:276
-#: gui/saveload-dialog.cpp:547 gui/saveload-dialog.cpp:922
+#: gui/saveload-dialog.cpp:547 gui/saveload-dialog.cpp:931
#: gui/themebrowser.cpp:55 gui/fluidsynth-dialog.cpp:152
-#: engines/engine.cpp:452 backends/platform/wii/options.cpp:48
+#: engines/engine.cpp:483 backends/platform/wii/options.cpp:48
#: backends/events/default/default-events.cpp:196
#: backends/events/default/default-events.cpp:218
#: engines/drascula/saveload.cpp:49 engines/parallaction/saveload.cpp:274
@@ -69,9 +70,9 @@ msgid "Choose"
msgstr "Aukeratu"
#: gui/gui-manager.cpp:117 backends/keymapper/remap-dialog.cpp:53
-#: 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
+#: 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"
@@ -87,7 +88,7 @@ msgstr "Teklatua erakutsi"
msgid "Remap keys"
msgstr "Teklak esleitu"
-#: gui/gui-manager.cpp:131 base/main.cpp:326 engines/scumm/help.cpp:86
+#: gui/gui-manager.cpp:131 base/main.cpp:326 engines/scumm/help.cpp:87
msgid "Toggle fullscreen"
msgstr "Txandakatu pantaila osoa"
@@ -101,13 +102,13 @@ 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:1240
-#: gui/saveload-dialog.cpp:923 gui/fluidsynth-dialog.cpp:153
-#: engines/engine.cpp:371 engines/engine.cpp:382
+#: 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:399 engines/parallaction/saveload.cpp:274
-#: engines/scumm/dialogs.cpp:193 engines/scumm/scumm.cpp:1825
+#: 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
@@ -477,7 +478,7 @@ msgstr ""
#: gui/launcher.cpp:793 gui/launcher.cpp:941 gui/launcher.cpp:1000
#: gui/fluidsynth-dialog.cpp:217
-#: backends/events/symbiansdl/symbiansdl-events.cpp:184
+#: 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
@@ -487,7 +488,7 @@ 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:184
+#: 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
@@ -526,6 +527,14 @@ msgstr ""
"ScummVM-k ezin izan du aukeraturiko jokoa exekutatzeko gai den motorerik "
"aurkitu!"
+#: gui/launcher.cpp:1159
+msgid "Mass Add..."
+msgstr "Hainbat gehitu..."
+
+#: gui/launcher.cpp:1161
+msgid "Record..."
+msgstr ""
+
#: gui/massadd.cpp:79 gui/massadd.cpp:82
msgid "... progress ..."
msgstr "... aurrerapena ..."
@@ -626,7 +635,7 @@ msgid "Special dithering modes supported by some games"
msgstr "Joko batzuk onarturiko lausotze-modu bereziak"
#: gui/options.cpp:760
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2249
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2298
msgid "Fullscreen mode"
msgstr "Pantaila osoa"
@@ -944,6 +953,43 @@ msgstr ""
"Aukeraturiko gaia ez da zure hizkuntzarekin bateragarria. Gai hau erabili "
"nahi baduzu, aurretik beste hizkuntza batera pasa behar duzu."
+#: gui/recorderdialog.cpp:64
+msgid "Recorder or Playback Gameplay"
+msgstr ""
+
+#: gui/recorderdialog.cpp:69 gui/recorderdialog.cpp:156
+#: gui/saveload-dialog.cpp:220 gui/saveload-dialog.cpp:276
+msgid "Delete"
+msgstr "Ezabatu"
+
+#: gui/recorderdialog.cpp:71
+msgid "Record"
+msgstr ""
+
+#: gui/recorderdialog.cpp:72
+#, fuzzy
+msgid "Playback"
+msgstr "Jolastu"
+
+#: gui/recorderdialog.cpp:74
+msgid "Edit"
+msgstr ""
+
+#: gui/recorderdialog.cpp:86 gui/recorderdialog.cpp:243
+#: gui/recorderdialog.cpp:253
+msgid "Author: "
+msgstr ""
+
+#: gui/recorderdialog.cpp:87 gui/recorderdialog.cpp:244
+#: gui/recorderdialog.cpp:254
+msgid "Notes: "
+msgstr ""
+
+#: gui/recorderdialog.cpp:155
+#, fuzzy
+msgid "Do you really want to delete this record?"
+msgstr "Ezabatu partida gorde hau?"
+
#: gui/saveload-dialog.cpp:167
msgid "List view"
msgstr ""
@@ -964,23 +1010,19 @@ msgstr "Ez dago ordurik gordeta"
msgid "No playtime saved"
msgstr "Ez dago denborarik gordeta"
-#: gui/saveload-dialog.cpp:220 gui/saveload-dialog.cpp:276
-msgid "Delete"
-msgstr "Ezabatu"
-
#: gui/saveload-dialog.cpp:275
msgid "Do you really want to delete this saved game?"
msgstr "Ezabatu partida gorde hau?"
-#: gui/saveload-dialog.cpp:385 gui/saveload-dialog.cpp:875
+#: gui/saveload-dialog.cpp:385 gui/saveload-dialog.cpp:884
msgid "Date: "
msgstr "Data:"
-#: gui/saveload-dialog.cpp:389 gui/saveload-dialog.cpp:881
+#: gui/saveload-dialog.cpp:389 gui/saveload-dialog.cpp:890
msgid "Time: "
msgstr "Ordua"
-#: gui/saveload-dialog.cpp:395 gui/saveload-dialog.cpp:889
+#: gui/saveload-dialog.cpp:395 gui/saveload-dialog.cpp:898
msgid "Playtime: "
msgstr "Denbora:"
@@ -996,22 +1038,22 @@ msgstr ""
msgid "Prev"
msgstr ""
-#: gui/saveload-dialog.cpp:739
+#: gui/saveload-dialog.cpp:748
#, fuzzy
msgid "New Save"
msgstr "Gorde"
-#: gui/saveload-dialog.cpp:739
+#: gui/saveload-dialog.cpp:748
#, fuzzy
msgid "Create a new save game"
msgstr "Ezin izan da jokoa gorde"
-#: gui/saveload-dialog.cpp:868
+#: gui/saveload-dialog.cpp:877
#, fuzzy
msgid "Name: "
msgstr "Izena:"
-#: gui/saveload-dialog.cpp:940
+#: gui/saveload-dialog.cpp:949
#, c-format
msgid "Enter a description for slot %d:"
msgstr ""
@@ -1169,7 +1211,7 @@ msgstr "Lerroa saltatu"
msgid "Error running game:"
msgstr "Jokoa exekutatzean errorea:"
-#: base/main.cpp:536
+#: base/main.cpp:554
msgid "Could not find any engine capable of running the selected game"
msgstr "Ezin izan da aukeraturiko jokoa exekutatzeko gai den motorerik aurkitu"
@@ -1286,7 +1328,7 @@ 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:758
+#: engines/pegasus/pegasus.cpp:377 engines/sci/engine/kfile.cpp:759
#: engines/toltecs/menu.cpp:281 engines/tsage/scenes.cpp:598
msgid "Save game:"
msgstr "Gorde jokoa:"
@@ -1299,7 +1341,7 @@ msgstr "Gorde jokoa:"
#: 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:758 engines/scumm/dialogs.cpp:188
+#: engines/sci/engine/kfile.cpp:759 engines/scumm/dialogs.cpp:188
#: engines/toltecs/menu.cpp:281 engines/tsage/scenes.cpp:598
msgid "Save"
msgstr "Gorde"
@@ -1336,23 +1378,23 @@ msgstr "~U~tzi"
msgid "~K~eys"
msgstr "~T~eklak"
-#: engines/engine.cpp:245
+#: engines/engine.cpp:276
msgid "Could not initialize color format."
msgstr "Kolore formatua ezin izan da hasieratu."
-#: engines/engine.cpp:253
+#: engines/engine.cpp:284
msgid "Could not switch to video mode: '"
msgstr "Ezin izan da aldatu bideo modura : '"
-#: engines/engine.cpp:262
+#: engines/engine.cpp:293
msgid "Could not apply aspect ratio setting."
msgstr "Ezin izan da formatu-ratio ezarpena aplikatu."
-#: engines/engine.cpp:267
+#: engines/engine.cpp:298
msgid "Could not apply fullscreen setting."
msgstr "Ezin izan da pantaila-osoa ezarpena aplikatu."
-#: engines/engine.cpp:367
+#: engines/engine.cpp:398
msgid ""
"You appear to be playing this game directly\n"
"from the CD. This is known to cause problems,\n"
@@ -1366,7 +1408,7 @@ msgstr ""
"fitxategiak disko gogorrera kopiatzea.\n"
"Jo README fitxategira xehetasunetarako."
-#: engines/engine.cpp:378
+#: engines/engine.cpp:409
msgid ""
"This game has audio tracks in its disk. These\n"
"tracks need to be ripped from the disk using\n"
@@ -1380,7 +1422,7 @@ msgstr ""
"izateko. Jo README fitxategira\n"
"xehetasunetarako."
-#: engines/engine.cpp:436
+#: engines/engine.cpp:467
#, c-format
msgid ""
"Gamestate load failed (%s)! Please consult the README for basic information, "
@@ -1389,7 +1431,7 @@ msgstr ""
"Jokoaren egoera kargatzeak huts egin du (%s)! Jo ezazu README-ra oinarrizko "
"informaziorako eta laguntza gehiago nola jaso jakiteko."
-#: engines/engine.cpp:449
+#: engines/engine.cpp:480
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 "
@@ -1399,7 +1441,7 @@ msgstr ""
"Hori dela eta, ezegonkorra izan daiteke eta gerta daiteke gordeta izan "
"ditzakezun partidan ez ibiltzea ScummVM-ren etorkizuneko bertsioetan."
-#: engines/engine.cpp:452
+#: engines/engine.cpp:483
msgid "Start anyway"
msgstr "Jolastu berdin-berdin"
@@ -1609,11 +1651,11 @@ msgstr "Touchpad modua gaituta."
msgid "Touchpad mode disabled."
msgstr "Touchpad modua desgaituta."
-#: backends/platform/maemo/maemo.cpp:209
+#: backends/platform/maemo/maemo.cpp:208
msgid "Click Mode"
msgstr "Klikatzeko modua"
-#: backends/platform/maemo/maemo.cpp:215
+#: backends/platform/maemo/maemo.cpp:214
#: backends/platform/symbian/src/SymbianActions.cpp:42
#: backends/platform/wince/CEActionsPocket.cpp:60
#: backends/platform/wince/CEActionsSmartphone.cpp:43
@@ -1621,11 +1663,11 @@ msgstr "Klikatzeko modua"
msgid "Left Click"
msgstr "Ezker-klika"
-#: backends/platform/maemo/maemo.cpp:218
+#: backends/platform/maemo/maemo.cpp:217
msgid "Middle Click"
msgstr "Erdiko klika"
-#: backends/platform/maemo/maemo.cpp:221
+#: 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
@@ -1662,19 +1704,19 @@ msgctxt "lowres"
msgid "Normal (no scaling)"
msgstr "Normala"
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2148
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2197
msgid "Enabled aspect ratio correction"
msgstr "Formatu-ratio zuzenketa gaituta"
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2154
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2203
msgid "Disabled aspect ratio correction"
msgstr "Formatu-ratio zuzenketa desgaituta"
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2209
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2258
msgid "Active graphics filter:"
msgstr "Filtro grafiko aktiboa:"
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2251
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2300
msgid "Windowed mode"
msgstr "Leiho modua"
@@ -1734,8 +1776,8 @@ msgstr "Modu bizkorra"
#: 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:82
-#: engines/scumm/help.cpp:84
+#: engines/scumm/dialogs.cpp:192 engines/scumm/help.cpp:83
+#: engines/scumm/help.cpp:85
msgid "Quit"
msgstr "Irten"
@@ -1755,7 +1797,7 @@ msgstr "Teklatu birtuala"
msgid "Key mapper"
msgstr "Teklen esleipena"
-#: backends/events/symbiansdl/symbiansdl-events.cpp:184
+#: backends/events/symbiansdl/symbiansdl-events.cpp:186
msgid "Do you want to quit ?"
msgstr "Irten nahi al duzu?"
@@ -2092,33 +2134,52 @@ msgstr "Klikatzea gaituta"
msgid "Clicking Disabled"
msgstr "Klikatzea desgaituta"
-#: engines/agi/detection.cpp:142 engines/drascula/detection.cpp:302
+#: 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.cpp:103
+#: engines/zvision/detection.cpp:246
msgid "Use original save/load screens"
msgstr ""
-#: engines/agi/detection.cpp:143 engines/drascula/detection.cpp:303
+#: 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/zvision/detection.cpp:104
+#: engines/zvision/detection.cpp:247
msgid "Use the original save/load screens, instead of the ScummVM ones"
msgstr ""
+#: engines/agi/detection.cpp:157
+msgid "Use an alternative palette"
+msgstr ""
+
+#: engines/agi/detection.cpp:158
+msgid ""
+"Use an alternative palette, common for all Amiga games. This was the old "
+"behavior"
+msgstr ""
+
+#: engines/agi/detection.cpp:167
+msgid "Mouse support"
+msgstr ""
+
+#: 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:857 engines/toltecs/menu.cpp:256
+#: engines/sci/engine/kfile.cpp:858 engines/toltecs/menu.cpp:256
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:857 engines/toltecs/menu.cpp:256
+#: engines/sci/engine/kfile.cpp:858 engines/toltecs/menu.cpp:256
msgid "Restore"
msgstr "Kargatu"
-#: engines/agos/saveload.cpp:160 engines/scumm/scumm.cpp:2368
+#: engines/agos/saveload.cpp:160 engines/scumm/scumm.cpp:2377
#, c-format
msgid ""
"Failed to load game state from file:\n"
@@ -2129,7 +2190,7 @@ msgstr ""
"\n"
"%s"
-#: engines/agos/saveload.cpp:195 engines/scumm/scumm.cpp:2361
+#: engines/agos/saveload.cpp:195 engines/scumm/scumm.cpp:2370
#, c-format
msgid ""
"Failed to save game state to file:\n"
@@ -2140,7 +2201,7 @@ msgstr ""
"\n"
"%s"
-#: engines/agos/saveload.cpp:203 engines/scumm/scumm.cpp:2379
+#: engines/agos/saveload.cpp:203 engines/scumm/scumm.cpp:2388
#, c-format
msgid ""
"Successfully saved game state in file:\n"
@@ -2156,12 +2217,12 @@ msgstr ""
msgid "Cutscene file '%s' not found!"
msgstr "'%s' bideo fitxategia ez da aurkitu!"
-#: engines/cge/detection.cpp:105 engines/cge2/detection.cpp:81
+#: engines/cge/detection.cpp:105 engines/cge2/detection.cpp:101
#, fuzzy
msgid "Color Blind Mode"
msgstr "Klikatzeko modua"
-#: engines/cge/detection.cpp:106 engines/cge2/detection.cpp:82
+#: engines/cge/detection.cpp:106 engines/cge2/detection.cpp:102
msgid "Enable Color Blind Mode by default"
msgstr ""
@@ -2216,7 +2277,7 @@ msgstr "Modu bizkorra"
msgid "Play movies at an increased speed"
msgstr ""
-#: engines/groovie/script.cpp:399
+#: engines/groovie/script.cpp:408
msgid "Failed to save game"
msgstr "Ezin izan da jokoa gorde"
@@ -2518,13 +2579,12 @@ msgid "Use an alternative game intro (CD version only)"
msgstr ""
#: engines/sci/detection.cpp:374
-msgid "EGA undithering"
-msgstr "EGA lausotzea"
+msgid "Skip EGA dithering pass (full color backgrounds)"
+msgstr ""
#: engines/sci/detection.cpp:375
-#, fuzzy
-msgid "Enable undithering in EGA games"
-msgstr "EGA lausotzea gaitu joko bateragarrietan"
+msgid "Skip dithering pass in EGA games, graphics are shown with full colors"
+msgstr ""
#: engines/sci/detection.cpp:384
#, fuzzy
@@ -2595,12 +2655,14 @@ msgstr "Joko pausatua. Sakatu ZURIUNEA jarraitzeko."
#. "Moechten Sie wirklich neu starten? (J/N)J"
#. Will react to J as 'Yes'
#: engines/scumm/dialogs.cpp:183
-msgid "Are you sure you want to restart? (Y/N)"
+#, fuzzy
+msgid "Are you sure you want to restart? (Y/N)Y"
msgstr "Ziur zaude berrabiarazi nahi duzula (B/E)B"
#. I18N: you may specify 'Yes' symbol at the end of the line. See previous comment
#: engines/scumm/dialogs.cpp:185
-msgid "Are you sure you want to quit? (Y/N)"
+#, fuzzy
+msgid "Are you sure you want to quit? (Y/N)Y"
msgstr "Ziur zaude irten nahi duzula? (B/E)B"
#: engines/scumm/dialogs.cpp:190
@@ -2688,516 +2750,540 @@ msgstr "Entrenamendua"
msgid "Expert"
msgstr "Aditua"
-#: engines/scumm/help.cpp:73
+#: engines/scumm/help.cpp:74
msgid "Common keyboard commands:"
msgstr "Teklatuko komando oinarrizkoak:"
-#: engines/scumm/help.cpp:74
+#: engines/scumm/help.cpp:75
msgid "Save / Load dialog"
msgstr "Gorde / Kargatu pantaila"
-#: engines/scumm/help.cpp:76
+#: engines/scumm/help.cpp:77
msgid "Skip line of text"
msgstr "Esaldia saltatu"
-#: engines/scumm/help.cpp:77
+#: engines/scumm/help.cpp:78
msgid "Esc"
msgstr "Ihes"
-#: engines/scumm/help.cpp:77
+#: engines/scumm/help.cpp:78
msgid "Skip cutscene"
msgstr "Eszena saltatu"
-#: engines/scumm/help.cpp:78
+#: engines/scumm/help.cpp:79
msgid "Space"
msgstr "Zuriunea"
-#: engines/scumm/help.cpp:78
+#: engines/scumm/help.cpp:79
msgid "Pause game"
msgstr "Jokoa pausatu"
-#: engines/scumm/help.cpp:79 engines/scumm/help.cpp:84
-#: engines/scumm/help.cpp:95 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: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 "Ktrl"
-#: engines/scumm/help.cpp:79
+#: engines/scumm/help.cpp:80
msgid "Load game state 1-10"
msgstr "1-10 jokoa kargatu"
-#: engines/scumm/help.cpp:80 engines/scumm/help.cpp:84
-#: engines/scumm/help.cpp:86 engines/scumm/help.cpp:100
-#: engines/scumm/help.cpp:101 engines/scumm/help.cpp:102
+#: 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:80
+#: engines/scumm/help.cpp:81
msgid "Save game state 1-10"
msgstr "1-10 partida gorde"
-#: engines/scumm/help.cpp:86 engines/scumm/help.cpp:89
+#: engines/scumm/help.cpp:87 engines/scumm/help.cpp:90
msgid "Enter"
msgstr "Sartu"
-#: engines/scumm/help.cpp:87
+#: engines/scumm/help.cpp:88
msgid "Music volume up / down"
msgstr "Musikaren bolumena gora / behera"
-#: engines/scumm/help.cpp:88
+#: engines/scumm/help.cpp:89
msgid "Text speed slower / faster"
msgstr "Testu-abiadura astiroago / bizkorrago"
-#: engines/scumm/help.cpp:89
+#: engines/scumm/help.cpp:90
msgid "Simulate left mouse button"
msgstr "Saguaren ezker botoia simulatu"
-#: engines/scumm/help.cpp:90
+#: engines/scumm/help.cpp:91
msgid "Tab"
msgstr "Tab"
-#: engines/scumm/help.cpp:90
+#: engines/scumm/help.cpp:91
msgid "Simulate right mouse button"
msgstr "Saguaren eskuin botoia simulatu"
-#: engines/scumm/help.cpp:93
+#: engines/scumm/help.cpp:94
msgid "Special keyboard commands:"
msgstr "Teklatuko komando bereziak:"
-#: engines/scumm/help.cpp:94
+#: engines/scumm/help.cpp:95
msgid "Show / Hide console"
msgstr "Kontsola erakutsi / ezkutatu"
-#: engines/scumm/help.cpp:95
+#: engines/scumm/help.cpp:96
msgid "Start the debugger"
msgstr "Araztailea abiarazi"
-#: engines/scumm/help.cpp:96
+#: engines/scumm/help.cpp:97
msgid "Show memory consumption"
msgstr "Memoria kontsumoa erakutsi"
-#: engines/scumm/help.cpp:97
+#: engines/scumm/help.cpp:98
msgid "Run in fast mode (*)"
msgstr "Modu azkarrean exekutatu (*)"
-#: engines/scumm/help.cpp:98
+#: engines/scumm/help.cpp:99
msgid "Run in really fast mode (*)"
msgstr "Era oso azkarrean exekutatu (*)"
-#: engines/scumm/help.cpp:99
+#: engines/scumm/help.cpp:100
msgid "Toggle mouse capture"
msgstr "Saguaren kaptura"
-#: engines/scumm/help.cpp:100
+#: engines/scumm/help.cpp:101
msgid "Switch between graphics filters"
msgstr "Filtro grafikoen artean txandakatu"
-#: engines/scumm/help.cpp:101
+#: engines/scumm/help.cpp:102
msgid "Increase / Decrease scale factor"
msgstr "Eskala faktorea handitu / txikitu"
-#: engines/scumm/help.cpp:102
+#: engines/scumm/help.cpp:103
msgid "Toggle aspect-ratio correction"
msgstr "Txandakatu fFormatu-ratioaren zuzenketa"
-#: engines/scumm/help.cpp:107
+#: engines/scumm/help.cpp:108
msgid "* Note that using ctrl-f and"
msgstr "* Ktrl-F eta Ktrl-G"
-#: engines/scumm/help.cpp:108
+#: engines/scumm/help.cpp:109
msgid " ctrl-g are not recommended"
msgstr "erabiltzea ez da gomendagarria"
-#: engines/scumm/help.cpp:109
+#: engines/scumm/help.cpp:110
msgid " since they may cause crashes"
msgstr "kraskadurak eta jokoaren jokabide"
-#: engines/scumm/help.cpp:110
+#: engines/scumm/help.cpp:111
msgid " or incorrect game behavior."
msgstr "desegokia sor dezaketelako."
-#: engines/scumm/help.cpp:114
+#: engines/scumm/help.cpp:115
msgid "Spinning drafts on the keyboard:"
msgstr "Sorginkeriak teklatuarekin egin:"
-#: engines/scumm/help.cpp:116
+#: engines/scumm/help.cpp:117
msgid "Main game controls:"
msgstr "Joko kontrol nagusiak:"
-#: engines/scumm/help.cpp:121 engines/scumm/help.cpp:136
-#: engines/scumm/help.cpp:161
+#: engines/scumm/help.cpp:122 engines/scumm/help.cpp:137
+#: engines/scumm/help.cpp:162
msgid "Push"
msgstr "Bultzatu"
-#: engines/scumm/help.cpp:122 engines/scumm/help.cpp:137
-#: engines/scumm/help.cpp:162
+#: engines/scumm/help.cpp:123 engines/scumm/help.cpp:138
+#: engines/scumm/help.cpp:163
msgid "Pull"
msgstr "Tiratu"
-#: engines/scumm/help.cpp:123 engines/scumm/help.cpp:138
-#: engines/scumm/help.cpp:163 engines/scumm/help.cpp:197
-#: engines/scumm/help.cpp:207
+#: 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 "Eman"
-#: engines/scumm/help.cpp:124 engines/scumm/help.cpp:139
-#: engines/scumm/help.cpp:164 engines/scumm/help.cpp:190
-#: engines/scumm/help.cpp:208
+#: 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 "Ireki"
-#: engines/scumm/help.cpp:126
+#: engines/scumm/help.cpp:127
msgid "Go to"
msgstr "Joan"
-#: engines/scumm/help.cpp:127
+#: engines/scumm/help.cpp:128
msgid "Get"
msgstr "Jaso"
-#: engines/scumm/help.cpp:128 engines/scumm/help.cpp:152
-#: engines/scumm/help.cpp:170 engines/scumm/help.cpp:198
-#: engines/scumm/help.cpp:213 engines/scumm/help.cpp:224
-#: engines/scumm/help.cpp:250
+#: 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 "Erabili"
-#: engines/scumm/help.cpp:129 engines/scumm/help.cpp:141
+#: engines/scumm/help.cpp:130 engines/scumm/help.cpp:142
msgid "Read"
msgstr "Irakurri"
-#: engines/scumm/help.cpp:130 engines/scumm/help.cpp:147
+#: engines/scumm/help.cpp:131 engines/scumm/help.cpp:148
msgid "New kid"
msgstr "Pertsonaia aldatu"
-#: engines/scumm/help.cpp:131 engines/scumm/help.cpp:153
-#: engines/scumm/help.cpp:171
+#: engines/scumm/help.cpp:132 engines/scumm/help.cpp:154
+#: engines/scumm/help.cpp:172
msgid "Turn on"
msgstr "Piztu"
-#: engines/scumm/help.cpp:132 engines/scumm/help.cpp:154
-#: engines/scumm/help.cpp:172
+#: engines/scumm/help.cpp:133 engines/scumm/help.cpp:155
+#: engines/scumm/help.cpp:173
msgid "Turn off"
msgstr "Itzali"
-#: engines/scumm/help.cpp:142 engines/scumm/help.cpp:167
-#: engines/scumm/help.cpp:194
+#: engines/scumm/help.cpp:143 engines/scumm/help.cpp:168
+#: engines/scumm/help.cpp:195
msgid "Walk to"
msgstr "Joan"
-#: engines/scumm/help.cpp:143 engines/scumm/help.cpp:168
-#: engines/scumm/help.cpp:195 engines/scumm/help.cpp:210
-#: engines/scumm/help.cpp:227
+#: 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 "Jaso"
-#: engines/scumm/help.cpp:144 engines/scumm/help.cpp:169
+#: engines/scumm/help.cpp:145 engines/scumm/help.cpp:170
msgid "What is"
msgstr "Zer da"
-#: engines/scumm/help.cpp:146
+#: engines/scumm/help.cpp:147
msgid "Unlock"
msgstr "Ireki"
-#: engines/scumm/help.cpp:149
+#: engines/scumm/help.cpp:150
msgid "Put on"
msgstr "Ipini"
-#: engines/scumm/help.cpp:150
+#: engines/scumm/help.cpp:151
msgid "Take off"
msgstr "Kendu"
-#: engines/scumm/help.cpp:156
+#: engines/scumm/help.cpp:157
msgid "Fix"
msgstr "Konpondu"
-#: engines/scumm/help.cpp:158
+#: engines/scumm/help.cpp:159
msgid "Switch"
msgstr "Aldatu"
-#: engines/scumm/help.cpp:166 engines/scumm/help.cpp:228
+#: engines/scumm/help.cpp:167 engines/scumm/help.cpp:229
msgid "Look"
msgstr "Begiratu"
-#: engines/scumm/help.cpp:173 engines/scumm/help.cpp:223
+#: engines/scumm/help.cpp:174 engines/scumm/help.cpp:224
msgid "Talk"
msgstr "Hitz egin"
-#: engines/scumm/help.cpp:174
+#: engines/scumm/help.cpp:175
msgid "Travel"
msgstr "Bidaiatu"
-#: engines/scumm/help.cpp:175
+#: engines/scumm/help.cpp:176
msgid "To Henry / To Indy"
msgstr "Henry / Indy"
#. I18N: These are different musical notes
-#: engines/scumm/help.cpp:179
+#: engines/scumm/help.cpp:180
msgid "play C minor on distaff"
msgstr "Jo C minor bastoiarekin"
-#: engines/scumm/help.cpp:180
+#: engines/scumm/help.cpp:181
msgid "play D on distaff"
msgstr "Jo D bastoiarekin"
-#: engines/scumm/help.cpp:181
+#: engines/scumm/help.cpp:182
msgid "play E on distaff"
msgstr "Jo E bastoiarekin"
-#: engines/scumm/help.cpp:182
+#: engines/scumm/help.cpp:183
msgid "play F on distaff"
msgstr "Jo F bastoiarekin"
-#: engines/scumm/help.cpp:183
+#: engines/scumm/help.cpp:184
msgid "play G on distaff"
msgstr "Jo G bastoiarekin"
-#: engines/scumm/help.cpp:184
+#: engines/scumm/help.cpp:185
msgid "play A on distaff"
msgstr "Jo A bastoiarekin"
-#: engines/scumm/help.cpp:185
+#: engines/scumm/help.cpp:186
msgid "play B on distaff"
msgstr "Jo B bastoiarekin"
-#: engines/scumm/help.cpp:186
+#: engines/scumm/help.cpp:187
msgid "play C major on distaff"
msgstr "Jo C maior bastoiarekin"
-#: engines/scumm/help.cpp:192 engines/scumm/help.cpp:214
+#: engines/scumm/help.cpp:193 engines/scumm/help.cpp:215
msgid "puSh"
msgstr "Bultzatu"
-#: engines/scumm/help.cpp:193 engines/scumm/help.cpp:215
+#: engines/scumm/help.cpp:194 engines/scumm/help.cpp:216
msgid "pull (Yank)"
msgstr "Tiratu"
-#: engines/scumm/help.cpp:196 engines/scumm/help.cpp:212
-#: engines/scumm/help.cpp:248
+#: engines/scumm/help.cpp:197 engines/scumm/help.cpp:213
+#: engines/scumm/help.cpp:249
msgid "Talk to"
msgstr "Hitz egin"
-#: engines/scumm/help.cpp:199 engines/scumm/help.cpp:211
+#: engines/scumm/help.cpp:200 engines/scumm/help.cpp:212
msgid "Look at"
msgstr "Begiratu"
-#: engines/scumm/help.cpp:200
+#: engines/scumm/help.cpp:201
msgid "turn oN"
msgstr "Piztu"
-#: engines/scumm/help.cpp:201
+#: engines/scumm/help.cpp:202
msgid "turn oFf"
msgstr "Itzali"
-#: engines/scumm/help.cpp:217
+#: engines/scumm/help.cpp:218
msgid "KeyUp"
msgstr "Gora"
-#: engines/scumm/help.cpp:217
+#: engines/scumm/help.cpp:218
msgid "Highlight prev dialogue"
msgstr "Aurreko elkarrizketa aukeratu"
-#: engines/scumm/help.cpp:218
+#: engines/scumm/help.cpp:219
msgid "KeyDown"
msgstr "Behera"
-#: engines/scumm/help.cpp:218
+#: engines/scumm/help.cpp:219
msgid "Highlight next dialogue"
msgstr "Hurrengo elkarrizketa aukeratu"
-#: engines/scumm/help.cpp:222
+#: engines/scumm/help.cpp:223
msgid "Walk"
msgstr "Ibili"
-#: engines/scumm/help.cpp:225 engines/scumm/help.cpp:234
-#: engines/scumm/help.cpp:241 engines/scumm/help.cpp:249
+#: engines/scumm/help.cpp:226 engines/scumm/help.cpp:235
+#: engines/scumm/help.cpp:242 engines/scumm/help.cpp:250
msgid "Inventory"
msgstr "Inbentarioa"
-#: engines/scumm/help.cpp:226
+#: engines/scumm/help.cpp:227
msgid "Object"
msgstr "Objektua"
-#: engines/scumm/help.cpp:229
+#: engines/scumm/help.cpp:230
msgid "Black and White / Color"
msgstr "Zuri Beltza / Koloretan"
-#: engines/scumm/help.cpp:232
+#: engines/scumm/help.cpp:233
msgid "Eyes"
msgstr "Begiak"
-#: engines/scumm/help.cpp:233
+#: engines/scumm/help.cpp:234
msgid "Tongue"
msgstr "Mihia"
-#: engines/scumm/help.cpp:235
+#: engines/scumm/help.cpp:236
msgid "Punch"
msgstr "Ukabilkada"
-#: engines/scumm/help.cpp:236
+#: engines/scumm/help.cpp:237
msgid "Kick"
msgstr "Ostikada"
-#: engines/scumm/help.cpp:239 engines/scumm/help.cpp:247
+#: engines/scumm/help.cpp:240 engines/scumm/help.cpp:248
msgid "Examine"
msgstr "Aztertu"
-#: engines/scumm/help.cpp:240
+#: engines/scumm/help.cpp:241
msgid "Regular cursor"
msgstr "Kurtsore normala"
#. I18N: Comm is a communication device
-#: engines/scumm/help.cpp:243
+#: engines/scumm/help.cpp:244
msgid "Comm"
msgstr "Comm"
-#: engines/scumm/help.cpp:246
+#: engines/scumm/help.cpp:247
msgid "Save / Load / Options"
msgstr "Gorde / Kargatu / Aukerak"
-#: engines/scumm/help.cpp:255
+#: engines/scumm/help.cpp:256
msgid "Other game controls:"
msgstr "Beste kontrol batzuk:"
-#: engines/scumm/help.cpp:257 engines/scumm/help.cpp:267
+#: engines/scumm/help.cpp:258 engines/scumm/help.cpp:268
msgid "Inventory:"
msgstr "Inbentarioa:"
-#: engines/scumm/help.cpp:258 engines/scumm/help.cpp:274
+#: engines/scumm/help.cpp:259 engines/scumm/help.cpp:275
msgid "Scroll list up"
msgstr "Gora"
-#: engines/scumm/help.cpp:259 engines/scumm/help.cpp:275
+#: engines/scumm/help.cpp:260 engines/scumm/help.cpp:276
msgid "Scroll list down"
msgstr "Behera"
-#: engines/scumm/help.cpp:260 engines/scumm/help.cpp:268
+#: engines/scumm/help.cpp:261 engines/scumm/help.cpp:269
msgid "Upper left item"
msgstr "Goiko ezkerreko objektua"
-#: engines/scumm/help.cpp:261 engines/scumm/help.cpp:270
+#: engines/scumm/help.cpp:262 engines/scumm/help.cpp:271
msgid "Lower left item"
msgstr "Beheko ezkerreko objektua"
-#: engines/scumm/help.cpp:262 engines/scumm/help.cpp:271
+#: engines/scumm/help.cpp:263 engines/scumm/help.cpp:272
msgid "Upper right item"
msgstr "Goiko eskuineko objektua"
-#: engines/scumm/help.cpp:263 engines/scumm/help.cpp:273
+#: engines/scumm/help.cpp:264 engines/scumm/help.cpp:274
msgid "Lower right item"
msgstr "Beheko eskuineko objektua"
-#: engines/scumm/help.cpp:269
+#: engines/scumm/help.cpp:270
msgid "Middle left item"
msgstr "Erdiko ezkereko objektua"
-#: engines/scumm/help.cpp:272
+#: engines/scumm/help.cpp:273
msgid "Middle right item"
msgstr "Erdiko eskuineko objektua"
-#: engines/scumm/help.cpp:279 engines/scumm/help.cpp:284
+#: engines/scumm/help.cpp:280 engines/scumm/help.cpp:285
msgid "Switching characters:"
msgstr "Pertsonaia aldatu:"
-#: engines/scumm/help.cpp:281
+#: engines/scumm/help.cpp:282
msgid "Second kid"
msgstr "Bigarren gaztea"
-#: engines/scumm/help.cpp:282
+#: engines/scumm/help.cpp:283
msgid "Third kid"
msgstr "Hirugarren gaztea"
-#: engines/scumm/help.cpp:294
+#: engines/scumm/help.cpp:292
+msgid "Toggle Inventory/IQ Points display"
+msgstr ""
+
+#: engines/scumm/help.cpp:293
+msgid "Toggle Keyboard/Mouse Fighting (*)"
+msgstr ""
+
+#: engines/scumm/help.cpp:295
+msgid "* Keyboard Fighting is always on,"
+msgstr ""
+
+#: engines/scumm/help.cpp:296
+msgid " so despite the in-game message this"
+msgstr ""
+
+#: engines/scumm/help.cpp:297
+msgid " actually toggles Mouse Fighting Off/On"
+msgstr ""
+
+#: engines/scumm/help.cpp:304
msgid "Fighting controls (numpad):"
msgstr "Borroka-kontrolak (tekl. num.)"
-#: engines/scumm/help.cpp:295 engines/scumm/help.cpp:296
-#: engines/scumm/help.cpp:297
+#: engines/scumm/help.cpp:305 engines/scumm/help.cpp:306
+#: engines/scumm/help.cpp:307
msgid "Step back"
msgstr "Atzera egin"
-#: engines/scumm/help.cpp:298
+#: engines/scumm/help.cpp:308
msgid "Block high"
msgstr "Blokeo garaia"
-#: engines/scumm/help.cpp:299
+#: engines/scumm/help.cpp:309
msgid "Block middle"
msgstr "Erdiko blokeoa"
-#: engines/scumm/help.cpp:300
+#: engines/scumm/help.cpp:310
msgid "Block low"
msgstr "Blokeo baxua"
-#: engines/scumm/help.cpp:301
+#: engines/scumm/help.cpp:311
msgid "Punch high"
msgstr "Ukabilkada altua"
-#: engines/scumm/help.cpp:302
+#: engines/scumm/help.cpp:312
msgid "Punch middle"
msgstr "Ukabilkada erdira"
-#: engines/scumm/help.cpp:303
+#: engines/scumm/help.cpp:313
msgid "Punch low"
msgstr "Ukabilkada baxua"
-#: engines/scumm/help.cpp:306
+#: engines/scumm/help.cpp:315
+msgid "Sucker punch"
+msgstr ""
+
+#: engines/scumm/help.cpp:318
msgid "These are for Indy on left."
msgstr "Indy ezkerrean dagoenerako dira,"
-#: engines/scumm/help.cpp:307
+#: engines/scumm/help.cpp:319
msgid "When Indy is on the right,"
msgstr "Indy eskuinean dagoenean,"
-#: engines/scumm/help.cpp:308
+#: engines/scumm/help.cpp:320
msgid "7, 4, and 1 are switched with"
msgstr "7, 4 eta 1 aldatuak dira"
-#: engines/scumm/help.cpp:309
+#: engines/scumm/help.cpp:321
msgid "9, 6, and 3, respectively."
msgstr "9, 6 eta 3rekin, hurrenez hurren."
-#: engines/scumm/help.cpp:316
+#: engines/scumm/help.cpp:328
msgid "Biplane controls (numpad):"
msgstr "Biplanoaren kontrolak (tekl. num.)"
-#: engines/scumm/help.cpp:317
+#: engines/scumm/help.cpp:329
msgid "Fly to upper left"
msgstr "Gora eta ezkerrera hegan egin"
-#: engines/scumm/help.cpp:318
+#: engines/scumm/help.cpp:330
msgid "Fly to left"
msgstr "Ezkerrera hegan egin"
-#: engines/scumm/help.cpp:319
+#: engines/scumm/help.cpp:331
msgid "Fly to lower left"
msgstr "Behera eta ezkerrera hegan egin"
-#: engines/scumm/help.cpp:320
+#: engines/scumm/help.cpp:332
msgid "Fly upwards"
msgstr "Gorantz hegan egin"
-#: engines/scumm/help.cpp:321
+#: engines/scumm/help.cpp:333
msgid "Fly straight"
msgstr "Zuzen hegan egin"
-#: engines/scumm/help.cpp:322
+#: engines/scumm/help.cpp:334
msgid "Fly down"
msgstr "Behera hegan egin"
-#: engines/scumm/help.cpp:323
+#: engines/scumm/help.cpp:335
msgid "Fly to upper right"
msgstr "Gora eta eskuinera hegan egin"
-#: engines/scumm/help.cpp:324
+#: engines/scumm/help.cpp:336
msgid "Fly to right"
msgstr "Eskuinera hegan egin"
-#: engines/scumm/help.cpp:325
+#: engines/scumm/help.cpp:337
msgid "Fly to lower right"
msgstr "Behera eta eskuinera hegan egin"
-#: engines/scumm/scumm.cpp:1823
+#: engines/scumm/scumm.cpp:1832
#, c-format
msgid ""
"Native MIDI support requires the Roland Upgrade from LucasArts,\n"
@@ -3206,11 +3292,12 @@ msgstr ""
"MIDI euskarri natiboak LucasArts-en Roland eguneraketa behar du,\n"
"baina %s ez dago eskuragarri. AdLib erabiliko da."
-#: engines/scumm/scumm.cpp:2594
+#: engines/scumm/scumm.cpp:2644
+#, fuzzy
msgid ""
-"Usually, Maniac Mansion would start now. But ScummVM doesn't do that yet. To "
-"play it, go to 'Add Game' in the ScummVM start menu and select the 'Maniac' "
-"directory inside the Tentacle game directory."
+"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 "
@@ -3347,6 +3434,47 @@ msgstr ""
msgid "Show the current number of frames per second in the upper left corner"
msgstr ""
+#: engines/zvision/detection.cpp:256
+msgid "Double FPS"
+msgstr ""
+
+#: engines/zvision/detection.cpp:257
+msgid "Increase game FPS from 30 to 60"
+msgstr ""
+
+#: engines/zvision/detection.cpp:266
+#, fuzzy
+msgid "Enable Venus"
+msgstr "Roland GS modua gaitu"
+
+#: engines/zvision/detection.cpp:267
+msgid "Enable the Venus help system"
+msgstr ""
+
+#: engines/zvision/detection.cpp:276
+msgid "Disable animation while turning"
+msgstr ""
+
+#: engines/zvision/detection.cpp:277
+msgid "Disable animation while turning in panoramic mode"
+msgstr ""
+
+#: engines/zvision/detection.cpp:286
+msgid "Use the hires MPEG movies"
+msgstr ""
+
+#: engines/zvision/detection.cpp:287
+msgid ""
+"Use the hires MPEG movies of the DVD version, instead of the lowres AVI ones"
+msgstr ""
+
+#~ msgid "EGA undithering"
+#~ msgstr "EGA lausotzea"
+
+#, fuzzy
+#~ msgid "Enable undithering in EGA games"
+#~ msgstr "EGA lausotzea gaitu joko bateragarrietan"
+
#, fuzzy
#~ msgid "MPEG-2 cutscenes found but ScummVM has been built without MPEG-2"
#~ msgstr ""
@@ -3357,9 +3485,6 @@ msgstr ""
#~ msgid "Mass Add..."
#~ msgstr "Hainbat gehitu..."
-#~ msgid "Mass Add..."
-#~ msgstr "Hainbat gehitu..."
-
#~ msgid ""
#~ "Turns off General MIDI mapping for games with Roland MT-32 soundtrack"
#~ msgstr ""
diff --git a/po/fi_FI.po b/po/fi_FI.po
index e00799e1d6..04aea37268 100644
--- a/po/fi_FI.po
+++ b/po/fi_FI.po
@@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: ScummVM 1.6.0git\n"
"Report-Msgid-Bugs-To: scummvm-devel@lists.sf.net\n"
-"POT-Creation-Date: 2014-10-04 00:58+0100\n"
+"POT-Creation-Date: 2015-06-30 20:57+0100\n"
"PO-Revision-Date: 2012-12-01 19:37+0200\n"
"Last-Translator: Toni Saarela <saarela@gmail.com>\n"
"Language-Team: Finnish\n"
@@ -54,10 +54,11 @@ msgstr "Siirry ylіs"
#: gui/browser.cpp:75 gui/chooser.cpp:46 gui/KeysDialog.cpp:43
#: gui/launcher.cpp:351 gui/massadd.cpp:95 gui/options.cpp:1239
+#: gui/recorderdialog.cpp:70 gui/recorderdialog.cpp:156
#: gui/saveload-dialog.cpp:216 gui/saveload-dialog.cpp:276
-#: gui/saveload-dialog.cpp:547 gui/saveload-dialog.cpp:922
+#: gui/saveload-dialog.cpp:547 gui/saveload-dialog.cpp:931
#: gui/themebrowser.cpp:55 gui/fluidsynth-dialog.cpp:152
-#: engines/engine.cpp:452 backends/platform/wii/options.cpp:48
+#: engines/engine.cpp:483 backends/platform/wii/options.cpp:48
#: backends/events/default/default-events.cpp:196
#: backends/events/default/default-events.cpp:218
#: engines/drascula/saveload.cpp:49 engines/parallaction/saveload.cpp:274
@@ -70,9 +71,9 @@ msgid "Choose"
msgstr "Valitse"
#: gui/gui-manager.cpp:117 backends/keymapper/remap-dialog.cpp:53
-#: 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
+#: 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"
@@ -88,7 +89,7 @@ msgstr "Nфytф nфppфimistі"
msgid "Remap keys"
msgstr "Mффritф nфppфimet uudelleen"
-#: gui/gui-manager.cpp:131 base/main.cpp:326 engines/scumm/help.cpp:86
+#: gui/gui-manager.cpp:131 base/main.cpp:326 engines/scumm/help.cpp:87
msgid "Toggle fullscreen"
msgstr "Kokoruututilan vaihto"
@@ -102,13 +103,13 @@ 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:1240
-#: gui/saveload-dialog.cpp:923 gui/fluidsynth-dialog.cpp:153
-#: engines/engine.cpp:371 engines/engine.cpp:382
+#: 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:399 engines/parallaction/saveload.cpp:274
-#: engines/scumm/dialogs.cpp:193 engines/scumm/scumm.cpp:1825
+#: 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
@@ -478,7 +479,7 @@ msgstr ""
#: gui/launcher.cpp:793 gui/launcher.cpp:941 gui/launcher.cpp:1000
#: gui/fluidsynth-dialog.cpp:217
-#: backends/events/symbiansdl/symbiansdl-events.cpp:184
+#: 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
@@ -488,7 +489,7 @@ 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:184
+#: 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
@@ -525,6 +526,14 @@ msgstr "Tфmф peli ei tue pelitallennuksien lataamista pelin ulkopuolelta."
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
+msgid "Mass Add..."
+msgstr "Lisфф monta..."
+
+#: gui/launcher.cpp:1161
+msgid "Record..."
+msgstr ""
+
#: gui/massadd.cpp:79 gui/massadd.cpp:82
msgid "... progress ..."
msgstr "... skannaa ..."
@@ -627,7 +636,7 @@ msgid "Special dithering modes supported by some games"
msgstr "Erityiset dithering asetukset joita jotkut pelit tukevat"
#: gui/options.cpp:760
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2249
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2298
msgid "Fullscreen mode"
msgstr "Kokoruututila"
@@ -945,6 +954,43 @@ msgstr ""
"Valitsemasi teema ei tue nykyistф valitsemaasi kieltф. Vaihda kieli ensin, "
"ja yritф sitten uudelleen."
+#: gui/recorderdialog.cpp:64
+msgid "Recorder or Playback Gameplay"
+msgstr ""
+
+#: gui/recorderdialog.cpp:69 gui/recorderdialog.cpp:156
+#: gui/saveload-dialog.cpp:220 gui/saveload-dialog.cpp:276
+msgid "Delete"
+msgstr "Poista"
+
+#: gui/recorderdialog.cpp:71
+msgid "Record"
+msgstr ""
+
+#: gui/recorderdialog.cpp:72
+#, fuzzy
+msgid "Playback"
+msgstr "Pelaa"
+
+#: gui/recorderdialog.cpp:74
+msgid "Edit"
+msgstr ""
+
+#: gui/recorderdialog.cpp:86 gui/recorderdialog.cpp:243
+#: gui/recorderdialog.cpp:253
+msgid "Author: "
+msgstr ""
+
+#: gui/recorderdialog.cpp:87 gui/recorderdialog.cpp:244
+#: gui/recorderdialog.cpp:254
+msgid "Notes: "
+msgstr ""
+
+#: gui/recorderdialog.cpp:155
+#, fuzzy
+msgid "Do you really want to delete this record?"
+msgstr "Haluatko varmasti poistaa tфmфn pelitallennuksen?"
+
#: gui/saveload-dialog.cpp:167
msgid "List view"
msgstr "Listanфkymф"
@@ -965,23 +1011,19 @@ msgstr "Aikaa ei ole tallennettu"
msgid "No playtime saved"
msgstr "Peliaikaa ei ole tallennettu"
-#: gui/saveload-dialog.cpp:220 gui/saveload-dialog.cpp:276
-msgid "Delete"
-msgstr "Poista"
-
#: gui/saveload-dialog.cpp:275
msgid "Do you really want to delete this saved game?"
msgstr "Haluatko varmasti poistaa tфmфn pelitallennuksen?"
-#: gui/saveload-dialog.cpp:385 gui/saveload-dialog.cpp:875
+#: gui/saveload-dialog.cpp:385 gui/saveload-dialog.cpp:884
msgid "Date: "
msgstr "Pфivфys: "
-#: gui/saveload-dialog.cpp:389 gui/saveload-dialog.cpp:881
+#: gui/saveload-dialog.cpp:389 gui/saveload-dialog.cpp:890
msgid "Time: "
msgstr "Aika: "
-#: gui/saveload-dialog.cpp:395 gui/saveload-dialog.cpp:889
+#: gui/saveload-dialog.cpp:395 gui/saveload-dialog.cpp:898
msgid "Playtime: "
msgstr "Peliaika: "
@@ -997,19 +1039,19 @@ msgstr "Seuraava"
msgid "Prev"
msgstr "Edellinen"
-#: gui/saveload-dialog.cpp:739
+#: gui/saveload-dialog.cpp:748
msgid "New Save"
msgstr "Uusi pelitallennus"
-#: gui/saveload-dialog.cpp:739
+#: gui/saveload-dialog.cpp:748
msgid "Create a new save game"
msgstr "Luo uusi pelitallennus"
-#: gui/saveload-dialog.cpp:868
+#: gui/saveload-dialog.cpp:877
msgid "Name: "
msgstr "Nimi: "
-#: gui/saveload-dialog.cpp:940
+#: gui/saveload-dialog.cpp:949
#, c-format
msgid "Enter a description for slot %d:"
msgstr "Anna kuvaus tallennukselle numero %d:"
@@ -1167,7 +1209,7 @@ msgstr "Ohita rivi"
msgid "Error running game:"
msgstr "Virhe ajettaessa peliф:"
-#: base/main.cpp:536
+#: base/main.cpp:554
msgid "Could not find any engine capable of running the selected game"
msgstr "Pelimoottoria joka tukisi valittua peliф ei lіytynyt"
@@ -1286,7 +1328,7 @@ 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:758
+#: engines/pegasus/pegasus.cpp:377 engines/sci/engine/kfile.cpp:759
#: engines/toltecs/menu.cpp:281 engines/tsage/scenes.cpp:598
msgid "Save game:"
msgstr "Tallenna peli:"
@@ -1299,7 +1341,7 @@ msgstr "Tallenna peli:"
#: 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:758 engines/scumm/dialogs.cpp:188
+#: engines/sci/engine/kfile.cpp:759 engines/scumm/dialogs.cpp:188
#: engines/toltecs/menu.cpp:281 engines/tsage/scenes.cpp:598
msgid "Save"
msgstr "Tallenna"
@@ -1336,23 +1378,23 @@ msgstr "~P~eruuta"
msgid "~K~eys"
msgstr "~N~фppфimet"
-#: engines/engine.cpp:245
+#: engines/engine.cpp:276
msgid "Could not initialize color format."
msgstr "Vфriformaattia ei voitu alustaa"
-#: engines/engine.cpp:253
+#: engines/engine.cpp:284
msgid "Could not switch to video mode: '"
msgstr "Videotilan vaihto ei onnistunut:'"
-#: engines/engine.cpp:262
+#: engines/engine.cpp:293
msgid "Could not apply aspect ratio setting."
msgstr "Kuvasuhdeasetusta ei voitu asettaa."
-#: engines/engine.cpp:267
+#: engines/engine.cpp:298
msgid "Could not apply fullscreen setting."
msgstr "Kokoruututila-asetusta ei voi asettaa."
-#: engines/engine.cpp:367
+#: engines/engine.cpp:398
msgid ""
"You appear to be playing this game directly\n"
"from the CD. This is known to cause problems,\n"
@@ -1365,7 +1407,7 @@ msgstr ""
"pelin tiedostot kovalevyllesi. Avaa LUEMINUT\n"
"tiedosto ohjeita varten."
-#: engines/engine.cpp:378
+#: engines/engine.cpp:409
msgid ""
"This game has audio tracks in its disk. These\n"
"tracks need to be ripped from the disk using\n"
@@ -1378,7 +1420,7 @@ msgstr ""
"ohjelmistoa kфyttфen, jotta musiikit\n"
"kuuluvat. Lue ohjeet LUEMINUT tiedostosta."
-#: engines/engine.cpp:436
+#: engines/engine.cpp:467
#, c-format
msgid ""
"Gamestate load failed (%s)! Please consult the README for basic information, "
@@ -1387,7 +1429,7 @@ msgstr ""
"Pelitilan lataus epфonnistui (%s)! Avaa LUEMINUT tiedosto saadaksesi "
"lisфtietoa."
-#: engines/engine.cpp:449
+#: engines/engine.cpp:480
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 "
@@ -1397,7 +1439,7 @@ msgstr ""
"epфvakaa, eivфtkф pelitallennukset vфlttфmфttф toimi tulevissa ScummVM:n "
"versioissa."
-#: engines/engine.cpp:452
+#: engines/engine.cpp:483
msgid "Start anyway"
msgstr "Pelaa silti"
@@ -1609,11 +1651,11 @@ msgstr "Touchad tila pффllф"
msgid "Touchpad mode disabled."
msgstr "Touchpad tila pois pффltф"
-#: backends/platform/maemo/maemo.cpp:209
+#: backends/platform/maemo/maemo.cpp:208
msgid "Click Mode"
msgstr "Klikkaus moodi"
-#: backends/platform/maemo/maemo.cpp:215
+#: backends/platform/maemo/maemo.cpp:214
#: backends/platform/symbian/src/SymbianActions.cpp:42
#: backends/platform/wince/CEActionsPocket.cpp:60
#: backends/platform/wince/CEActionsSmartphone.cpp:43
@@ -1621,11 +1663,11 @@ msgstr "Klikkaus moodi"
msgid "Left Click"
msgstr "Vasen klikkaus"
-#: backends/platform/maemo/maemo.cpp:218
+#: backends/platform/maemo/maemo.cpp:217
msgid "Middle Click"
msgstr "Keskiklikkaus"
-#: backends/platform/maemo/maemo.cpp:221
+#: 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
@@ -1662,19 +1704,19 @@ msgctxt "lowres"
msgid "Normal (no scaling)"
msgstr "Normaali (ei skaalausta)"
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2148
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2197
msgid "Enabled aspect ratio correction"
msgstr "Kuvasuhteen korjaus pффllф"
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2154
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2203
msgid "Disabled aspect ratio correction"
msgstr "Kuvasuhteen korjaus pois pффltф"
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2209
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2258
msgid "Active graphics filter:"
msgstr "Valittu grafiikkafiltteri:"
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2251
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2300
msgid "Windowed mode"
msgstr "Ikkunoitu tila"
@@ -1734,8 +1776,8 @@ msgstr "Nopea moodi"
#: 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:82
-#: engines/scumm/help.cpp:84
+#: engines/scumm/dialogs.cpp:192 engines/scumm/help.cpp:83
+#: engines/scumm/help.cpp:85
msgid "Quit"
msgstr "Lopeta"
@@ -1755,7 +1797,7 @@ msgstr "Virtuaalinen nфppфimistі"
msgid "Key mapper"
msgstr "Nфppфinmффrittelijф"
-#: backends/events/symbiansdl/symbiansdl-events.cpp:184
+#: backends/events/symbiansdl/symbiansdl-events.cpp:186
msgid "Do you want to quit ?"
msgstr "Haluatko lopettaa?"
@@ -2093,33 +2135,54 @@ msgstr "Klikkaus pффllф"
msgid "Clicking Disabled"
msgstr "Klikkaus pois pффltф"
-#: engines/agi/detection.cpp:142 engines/drascula/detection.cpp:302
+#: 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.cpp:103
+#: engines/zvision/detection.cpp:246
msgid "Use original save/load screens"
msgstr "Kфytф alkuperфisiф tallenna/lataa valikkoja"
-#: engines/agi/detection.cpp:143 engines/drascula/detection.cpp:303
+#: 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/zvision/detection.cpp:104
+#: engines/zvision/detection.cpp:247
msgid "Use the original save/load screens, instead of the ScummVM ones"
msgstr "Kфytф alkuperфisiф tallenna/lataa valikkoja, ScummVM valikoiden sijaan"
+#: engines/agi/detection.cpp:157
+#, fuzzy
+msgid "Use an alternative palette"
+msgstr "Kфytф vaihtoehtoista pelin introa (vain CD versiossa)"
+
+#: engines/agi/detection.cpp:158
+msgid ""
+"Use an alternative palette, common for all Amiga games. This was the old "
+"behavior"
+msgstr ""
+
+#: engines/agi/detection.cpp:167
+#, fuzzy
+msgid "Mouse support"
+msgstr "Ohita tuki"
+
+#: 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:857 engines/toltecs/menu.cpp:256
+#: engines/sci/engine/kfile.cpp:858 engines/toltecs/menu.cpp:256
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:857 engines/toltecs/menu.cpp:256
+#: engines/sci/engine/kfile.cpp:858 engines/toltecs/menu.cpp:256
msgid "Restore"
msgstr "Lataa tallenne"
-#: engines/agos/saveload.cpp:160 engines/scumm/scumm.cpp:2368
+#: engines/agos/saveload.cpp:160 engines/scumm/scumm.cpp:2377
#, c-format
msgid ""
"Failed to load game state from file:\n"
@@ -2130,7 +2193,7 @@ msgstr ""
"\n"
"%s"
-#: engines/agos/saveload.cpp:195 engines/scumm/scumm.cpp:2361
+#: engines/agos/saveload.cpp:195 engines/scumm/scumm.cpp:2370
#, c-format
msgid ""
"Failed to save game state to file:\n"
@@ -2141,7 +2204,7 @@ msgstr ""
"\n"
"%s"
-#: engines/agos/saveload.cpp:203 engines/scumm/scumm.cpp:2379
+#: engines/agos/saveload.cpp:203 engines/scumm/scumm.cpp:2388
#, c-format
msgid ""
"Successfully saved game state in file:\n"
@@ -2157,12 +2220,12 @@ msgstr ""
msgid "Cutscene file '%s' not found!"
msgstr "Videotiedostoa '%s' ei lіytynyt!"
-#: engines/cge/detection.cpp:105 engines/cge2/detection.cpp:81
+#: engines/cge/detection.cpp:105 engines/cge2/detection.cpp:101
#, fuzzy
msgid "Color Blind Mode"
msgstr "Klikkaus moodi"
-#: engines/cge/detection.cpp:106 engines/cge2/detection.cpp:82
+#: engines/cge/detection.cpp:106 engines/cge2/detection.cpp:102
msgid "Enable Color Blind Mode by default"
msgstr ""
@@ -2214,7 +2277,7 @@ msgstr "Nopea moodi"
msgid "Play movies at an increased speed"
msgstr ""
-#: engines/groovie/script.cpp:399
+#: engines/groovie/script.cpp:408
msgid "Failed to save game"
msgstr "Pelin tallentaminen epфonnistui."
@@ -2509,12 +2572,12 @@ msgid "Use an alternative game intro (CD version only)"
msgstr "Kфytф vaihtoehtoista pelin introa (vain CD versiossa)"
#: engines/sci/detection.cpp:374
-msgid "EGA undithering"
-msgstr "EGA unditterіinti"
+msgid "Skip EGA dithering pass (full color backgrounds)"
+msgstr ""
#: engines/sci/detection.cpp:375
-msgid "Enable undithering in EGA games"
-msgstr "Kфytф unditterіintiф EGA peleissф"
+msgid "Skip dithering pass in EGA games, graphics are shown with full colors"
+msgstr ""
#: engines/sci/detection.cpp:384
msgid "Prefer digital sound effects"
@@ -2586,12 +2649,14 @@ msgstr "Pause. Paina vфlilyіntiф jatkaaksesi."
#. "Moechten Sie wirklich neu starten? (J/N)J"
#. Will react to J as 'Yes'
#: engines/scumm/dialogs.cpp:183
-msgid "Are you sure you want to restart? (Y/N)"
+#, 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
-msgid "Are you sure you want to quit? (Y/N)"
+#, fuzzy
+msgid "Are you sure you want to quit? (Y/N)Y"
msgstr "Haluatko varmati lopettaa?"
#: engines/scumm/dialogs.cpp:190
@@ -2679,516 +2744,540 @@ msgstr "Harjoitus"
msgid "Expert"
msgstr "Ekspertti"
-#: engines/scumm/help.cpp:73
+#: engines/scumm/help.cpp:74
msgid "Common keyboard commands:"
msgstr "Yleisiф nфppфimistіkomentoja:"
-#: engines/scumm/help.cpp:74
+#: engines/scumm/help.cpp:75
msgid "Save / Load dialog"
msgstr "Tallenna / Lataa peli"
-#: engines/scumm/help.cpp:76
+#: engines/scumm/help.cpp:77
msgid "Skip line of text"
msgstr "Ohita rivi tekstiф"
-#: engines/scumm/help.cpp:77
+#: engines/scumm/help.cpp:78
msgid "Esc"
msgstr "Esc"
-#: engines/scumm/help.cpp:77
+#: engines/scumm/help.cpp:78
msgid "Skip cutscene"
msgstr "Ohita video"
-#: engines/scumm/help.cpp:78
+#: engines/scumm/help.cpp:79
msgid "Space"
msgstr "Vфlilyіnti"
-#: engines/scumm/help.cpp:78
+#: engines/scumm/help.cpp:79
msgid "Pause game"
msgstr "Pause"
-#: engines/scumm/help.cpp:79 engines/scumm/help.cpp:84
-#: engines/scumm/help.cpp:95 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: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:79
+#: engines/scumm/help.cpp:80
msgid "Load game state 1-10"
msgstr "Lataa pelitila 1-10"
-#: engines/scumm/help.cpp:80 engines/scumm/help.cpp:84
-#: engines/scumm/help.cpp:86 engines/scumm/help.cpp:100
-#: engines/scumm/help.cpp:101 engines/scumm/help.cpp:102
+#: 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:80
+#: engines/scumm/help.cpp:81
msgid "Save game state 1-10"
msgstr "Tallenna pelitila 1-10"
-#: engines/scumm/help.cpp:86 engines/scumm/help.cpp:89
+#: engines/scumm/help.cpp:87 engines/scumm/help.cpp:90
msgid "Enter"
msgstr "Enter"
-#: engines/scumm/help.cpp:87
+#: engines/scumm/help.cpp:88
msgid "Music volume up / down"
msgstr "Musiikin ффnenvoimakkuus ylіs / alas"
-#: engines/scumm/help.cpp:88
+#: engines/scumm/help.cpp:89
msgid "Text speed slower / faster"
msgstr "Hidasta/nopeuta tekstiф"
-#: engines/scumm/help.cpp:89
+#: engines/scumm/help.cpp:90
msgid "Simulate left mouse button"
msgstr "Simuloi hiiren vasenta nфppфintф"
-#: engines/scumm/help.cpp:90
+#: engines/scumm/help.cpp:91
msgid "Tab"
msgstr "Sarkain"
-#: engines/scumm/help.cpp:90
+#: engines/scumm/help.cpp:91
msgid "Simulate right mouse button"
msgstr "Simuloi oikeaa hiiren nappia"
-#: engines/scumm/help.cpp:93
+#: engines/scumm/help.cpp:94
msgid "Special keyboard commands:"
msgstr "Erityiskomennot:"
-#: engines/scumm/help.cpp:94
+#: engines/scumm/help.cpp:95
msgid "Show / Hide console"
msgstr "Nфytф / piilota konsoli"
-#: engines/scumm/help.cpp:95
+#: engines/scumm/help.cpp:96
msgid "Start the debugger"
msgstr "Kфynnistф debuggeri"
-#: engines/scumm/help.cpp:96
+#: engines/scumm/help.cpp:97
msgid "Show memory consumption"
msgstr "Nфytф muistinkulutus"
-#: engines/scumm/help.cpp:97
+#: engines/scumm/help.cpp:98
msgid "Run in fast mode (*)"
msgstr "Aja nopeassa tilassa (*)"
-#: engines/scumm/help.cpp:98
+#: engines/scumm/help.cpp:99
msgid "Run in really fast mode (*)"
msgstr "Aja erittфin nopeassa tilassa (*)"
-#: engines/scumm/help.cpp:99
+#: engines/scumm/help.cpp:100
msgid "Toggle mouse capture"
msgstr "Kytke hiiren kaappaus pффlle tai pois"
-#: engines/scumm/help.cpp:100
+#: engines/scumm/help.cpp:101
msgid "Switch between graphics filters"
msgstr "Vaihda grafiikkafiltteriф"
-#: engines/scumm/help.cpp:101
+#: engines/scumm/help.cpp:102
msgid "Increase / Decrease scale factor"
msgstr "Kasvata / vфhennф skaalakerrointa"
-#: engines/scumm/help.cpp:102
+#: engines/scumm/help.cpp:103
msgid "Toggle aspect-ratio correction"
msgstr "Kytke kuvasuhdekorjaus pффlle tai pois"
-#: engines/scumm/help.cpp:107
+#: engines/scumm/help.cpp:108
msgid "* Note that using ctrl-f and"
msgstr "* Huomaa ettф ctrl-f ja"
-#: engines/scumm/help.cpp:108
+#: engines/scumm/help.cpp:109
msgid " ctrl-g are not recommended"
msgstr " ctrl-g ovat epфvakaita eikф"
-#: engines/scumm/help.cpp:109
+#: engines/scumm/help.cpp:110
msgid " since they may cause crashes"
msgstr " niiden kфyttіф suositella"
-#: engines/scumm/help.cpp:110
+#: engines/scumm/help.cpp:111
msgid " or incorrect game behavior."
msgstr " mahdollisten virheiden vuoksi."
-#: engines/scumm/help.cpp:114
+#: engines/scumm/help.cpp:115
msgid "Spinning drafts on the keyboard:"
msgstr ""
-#: engines/scumm/help.cpp:116
+#: engines/scumm/help.cpp:117
msgid "Main game controls:"
msgstr "Pelin tфrkeimmфt kontrollit:"
-#: engines/scumm/help.cpp:121 engines/scumm/help.cpp:136
-#: engines/scumm/help.cpp:161
+#: engines/scumm/help.cpp:122 engines/scumm/help.cpp:137
+#: engines/scumm/help.cpp:162
msgid "Push"
msgstr "Paina"
-#: engines/scumm/help.cpp:122 engines/scumm/help.cpp:137
-#: engines/scumm/help.cpp:162
+#: engines/scumm/help.cpp:123 engines/scumm/help.cpp:138
+#: engines/scumm/help.cpp:163
msgid "Pull"
msgstr "Vedф"
-#: engines/scumm/help.cpp:123 engines/scumm/help.cpp:138
-#: engines/scumm/help.cpp:163 engines/scumm/help.cpp:197
-#: engines/scumm/help.cpp:207
+#: 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 "Anna"
-#: engines/scumm/help.cpp:124 engines/scumm/help.cpp:139
-#: engines/scumm/help.cpp:164 engines/scumm/help.cpp:190
-#: engines/scumm/help.cpp:208
+#: 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 "Avaa"
-#: engines/scumm/help.cpp:126
+#: engines/scumm/help.cpp:127
msgid "Go to"
msgstr "Mene"
-#: engines/scumm/help.cpp:127
+#: engines/scumm/help.cpp:128
msgid "Get"
msgstr "Ota"
-#: engines/scumm/help.cpp:128 engines/scumm/help.cpp:152
-#: engines/scumm/help.cpp:170 engines/scumm/help.cpp:198
-#: engines/scumm/help.cpp:213 engines/scumm/help.cpp:224
-#: engines/scumm/help.cpp:250
+#: 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 "Kфytф"
-#: engines/scumm/help.cpp:129 engines/scumm/help.cpp:141
+#: engines/scumm/help.cpp:130 engines/scumm/help.cpp:142
msgid "Read"
msgstr "Lue"
-#: engines/scumm/help.cpp:130 engines/scumm/help.cpp:147
+#: engines/scumm/help.cpp:131 engines/scumm/help.cpp:148
msgid "New kid"
msgstr "Uusi lapsi"
-#: engines/scumm/help.cpp:131 engines/scumm/help.cpp:153
-#: engines/scumm/help.cpp:171
+#: engines/scumm/help.cpp:132 engines/scumm/help.cpp:154
+#: engines/scumm/help.cpp:172
msgid "Turn on"
msgstr "Kфynnistф"
-#: engines/scumm/help.cpp:132 engines/scumm/help.cpp:154
-#: engines/scumm/help.cpp:172
+#: engines/scumm/help.cpp:133 engines/scumm/help.cpp:155
+#: engines/scumm/help.cpp:173
msgid "Turn off"
msgstr "Sammuta"
-#: engines/scumm/help.cpp:142 engines/scumm/help.cpp:167
-#: engines/scumm/help.cpp:194
+#: engines/scumm/help.cpp:143 engines/scumm/help.cpp:168
+#: engines/scumm/help.cpp:195
msgid "Walk to"
msgstr "Kфvele"
-#: engines/scumm/help.cpp:143 engines/scumm/help.cpp:168
-#: engines/scumm/help.cpp:195 engines/scumm/help.cpp:210
-#: engines/scumm/help.cpp:227
+#: 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 "Ota"
-#: engines/scumm/help.cpp:144 engines/scumm/help.cpp:169
+#: engines/scumm/help.cpp:145 engines/scumm/help.cpp:170
msgid "What is"
msgstr "Mitф on"
-#: engines/scumm/help.cpp:146
+#: engines/scumm/help.cpp:147
msgid "Unlock"
msgstr "Avaa lukko"
-#: engines/scumm/help.cpp:149
+#: engines/scumm/help.cpp:150
msgid "Put on"
msgstr "Pue ylle"
-#: engines/scumm/help.cpp:150
+#: engines/scumm/help.cpp:151
msgid "Take off"
msgstr "Lфhde matkaan"
-#: engines/scumm/help.cpp:156
+#: engines/scumm/help.cpp:157
msgid "Fix"
msgstr "Korjaa"
-#: engines/scumm/help.cpp:158
+#: engines/scumm/help.cpp:159
msgid "Switch"
msgstr "Vaihda"
-#: engines/scumm/help.cpp:166 engines/scumm/help.cpp:228
+#: engines/scumm/help.cpp:167 engines/scumm/help.cpp:229
msgid "Look"
msgstr "Katso"
-#: engines/scumm/help.cpp:173 engines/scumm/help.cpp:223
+#: engines/scumm/help.cpp:174 engines/scumm/help.cpp:224
msgid "Talk"
msgstr "Puhu"
-#: engines/scumm/help.cpp:174
+#: engines/scumm/help.cpp:175
msgid "Travel"
msgstr "Matkusta"
-#: engines/scumm/help.cpp:175
+#: engines/scumm/help.cpp:176
msgid "To Henry / To Indy"
msgstr "Henry / Indy"
#. I18N: These are different musical notes
-#: engines/scumm/help.cpp:179
+#: engines/scumm/help.cpp:180
msgid "play C minor on distaff"
msgstr "soita C molli"
-#: engines/scumm/help.cpp:180
+#: engines/scumm/help.cpp:181
msgid "play D on distaff"
msgstr "soita D"
-#: engines/scumm/help.cpp:181
+#: engines/scumm/help.cpp:182
msgid "play E on distaff"
msgstr "soita E"
-#: engines/scumm/help.cpp:182
+#: engines/scumm/help.cpp:183
msgid "play F on distaff"
msgstr "soita F"
-#: engines/scumm/help.cpp:183
+#: engines/scumm/help.cpp:184
msgid "play G on distaff"
msgstr "soita G"
-#: engines/scumm/help.cpp:184
+#: engines/scumm/help.cpp:185
msgid "play A on distaff"
msgstr "soita A"
-#: engines/scumm/help.cpp:185
+#: engines/scumm/help.cpp:186
msgid "play B on distaff"
msgstr "soita B"
-#: engines/scumm/help.cpp:186
+#: engines/scumm/help.cpp:187
msgid "play C major on distaff"
msgstr "soita C duuri"
-#: engines/scumm/help.cpp:192 engines/scumm/help.cpp:214
+#: engines/scumm/help.cpp:193 engines/scumm/help.cpp:215
msgid "puSh"
msgstr "Paina"
-#: engines/scumm/help.cpp:193 engines/scumm/help.cpp:215
+#: engines/scumm/help.cpp:194 engines/scumm/help.cpp:216
msgid "pull (Yank)"
msgstr "Vedф"
-#: engines/scumm/help.cpp:196 engines/scumm/help.cpp:212
-#: engines/scumm/help.cpp:248
+#: engines/scumm/help.cpp:197 engines/scumm/help.cpp:213
+#: engines/scumm/help.cpp:249
msgid "Talk to"
msgstr "Puhu"
-#: engines/scumm/help.cpp:199 engines/scumm/help.cpp:211
+#: engines/scumm/help.cpp:200 engines/scumm/help.cpp:212
msgid "Look at"
msgstr "Katso"
-#: engines/scumm/help.cpp:200
+#: engines/scumm/help.cpp:201
msgid "turn oN"
msgstr "Kytke pффlle"
-#: engines/scumm/help.cpp:201
+#: engines/scumm/help.cpp:202
msgid "turn oFf"
msgstr "Kytke pois pффltф"
-#: engines/scumm/help.cpp:217
+#: engines/scumm/help.cpp:218
msgid "KeyUp"
msgstr "KeyUp"
-#: engines/scumm/help.cpp:217
+#: engines/scumm/help.cpp:218
msgid "Highlight prev dialogue"
msgstr "Korosta edellistф dialogia"
-#: engines/scumm/help.cpp:218
+#: engines/scumm/help.cpp:219
msgid "KeyDown"
msgstr "KeyDown"
-#: engines/scumm/help.cpp:218
+#: engines/scumm/help.cpp:219
msgid "Highlight next dialogue"
msgstr "Korosta seuraavaa dialogia"
-#: engines/scumm/help.cpp:222
+#: engines/scumm/help.cpp:223
msgid "Walk"
msgstr "Kфvele"
-#: engines/scumm/help.cpp:225 engines/scumm/help.cpp:234
-#: engines/scumm/help.cpp:241 engines/scumm/help.cpp:249
+#: engines/scumm/help.cpp:226 engines/scumm/help.cpp:235
+#: engines/scumm/help.cpp:242 engines/scumm/help.cpp:250
msgid "Inventory"
msgstr "Tavarat"
-#: engines/scumm/help.cpp:226
+#: engines/scumm/help.cpp:227
msgid "Object"
msgstr "Esine"
-#: engines/scumm/help.cpp:229
+#: engines/scumm/help.cpp:230
msgid "Black and White / Color"
msgstr "Mustavalko / Vфri"
-#: engines/scumm/help.cpp:232
+#: engines/scumm/help.cpp:233
msgid "Eyes"
msgstr "Silmфt"
-#: engines/scumm/help.cpp:233
+#: engines/scumm/help.cpp:234
msgid "Tongue"
msgstr "Kieli"
-#: engines/scumm/help.cpp:235
+#: engines/scumm/help.cpp:236
msgid "Punch"
msgstr "Lyі"
-#: engines/scumm/help.cpp:236
+#: engines/scumm/help.cpp:237
msgid "Kick"
msgstr "Potkaise"
-#: engines/scumm/help.cpp:239 engines/scumm/help.cpp:247
+#: engines/scumm/help.cpp:240 engines/scumm/help.cpp:248
msgid "Examine"
msgstr "Tutki"
-#: engines/scumm/help.cpp:240
+#: engines/scumm/help.cpp:241
msgid "Regular cursor"
msgstr "Tavallinen kursori"
#. I18N: Comm is a communication device
-#: engines/scumm/help.cpp:243
+#: engines/scumm/help.cpp:244
msgid "Comm"
msgstr "Kommunikointilaite"
-#: engines/scumm/help.cpp:246
+#: engines/scumm/help.cpp:247
msgid "Save / Load / Options"
msgstr "Tallenna / Lataa / Asetukset"
-#: engines/scumm/help.cpp:255
+#: engines/scumm/help.cpp:256
msgid "Other game controls:"
msgstr "Muut pelin ohjaimet:"
-#: engines/scumm/help.cpp:257 engines/scumm/help.cpp:267
+#: engines/scumm/help.cpp:258 engines/scumm/help.cpp:268
msgid "Inventory:"
msgstr "Tavarat:"
-#: engines/scumm/help.cpp:258 engines/scumm/help.cpp:274
+#: engines/scumm/help.cpp:259 engines/scumm/help.cpp:275
msgid "Scroll list up"
msgstr "Vieritф listaa ylіs"
-#: engines/scumm/help.cpp:259 engines/scumm/help.cpp:275
+#: engines/scumm/help.cpp:260 engines/scumm/help.cpp:276
msgid "Scroll list down"
msgstr "Vieritф listaa alas"
-#: engines/scumm/help.cpp:260 engines/scumm/help.cpp:268
+#: engines/scumm/help.cpp:261 engines/scumm/help.cpp:269
msgid "Upper left item"
msgstr ""
-#: engines/scumm/help.cpp:261 engines/scumm/help.cpp:270
+#: engines/scumm/help.cpp:262 engines/scumm/help.cpp:271
msgid "Lower left item"
msgstr ""
-#: engines/scumm/help.cpp:262 engines/scumm/help.cpp:271
+#: engines/scumm/help.cpp:263 engines/scumm/help.cpp:272
msgid "Upper right item"
msgstr ""
-#: engines/scumm/help.cpp:263 engines/scumm/help.cpp:273
+#: engines/scumm/help.cpp:264 engines/scumm/help.cpp:274
msgid "Lower right item"
msgstr ""
-#: engines/scumm/help.cpp:269
+#: engines/scumm/help.cpp:270
msgid "Middle left item"
msgstr ""
-#: engines/scumm/help.cpp:272
+#: engines/scumm/help.cpp:273
msgid "Middle right item"
msgstr ""
-#: engines/scumm/help.cpp:279 engines/scumm/help.cpp:284
+#: engines/scumm/help.cpp:280 engines/scumm/help.cpp:285
msgid "Switching characters:"
msgstr "Vaihda hahmoa:"
-#: engines/scumm/help.cpp:281
+#: engines/scumm/help.cpp:282
msgid "Second kid"
msgstr "Toinen lapsi"
-#: engines/scumm/help.cpp:282
+#: engines/scumm/help.cpp:283
msgid "Third kid"
msgstr "Kolmas lapsi"
-#: engines/scumm/help.cpp:294
+#: engines/scumm/help.cpp:292
+msgid "Toggle Inventory/IQ Points display"
+msgstr ""
+
+#: engines/scumm/help.cpp:293
+msgid "Toggle Keyboard/Mouse Fighting (*)"
+msgstr ""
+
+#: engines/scumm/help.cpp:295
+msgid "* Keyboard Fighting is always on,"
+msgstr ""
+
+#: engines/scumm/help.cpp:296
+msgid " so despite the in-game message this"
+msgstr ""
+
+#: engines/scumm/help.cpp:297
+msgid " actually toggles Mouse Fighting Off/On"
+msgstr ""
+
+#: engines/scumm/help.cpp:304
msgid "Fighting controls (numpad):"
msgstr "Tappeluohjaimet (numpad)"
-#: engines/scumm/help.cpp:295 engines/scumm/help.cpp:296
-#: engines/scumm/help.cpp:297
+#: engines/scumm/help.cpp:305 engines/scumm/help.cpp:306
+#: engines/scumm/help.cpp:307
msgid "Step back"
msgstr "Astu taakse"
-#: engines/scumm/help.cpp:298
+#: engines/scumm/help.cpp:308
msgid "Block high"
msgstr "Torju korkea"
-#: engines/scumm/help.cpp:299
+#: engines/scumm/help.cpp:309
msgid "Block middle"
msgstr "Torju keskeltф"
-#: engines/scumm/help.cpp:300
+#: engines/scumm/help.cpp:310
msgid "Block low"
msgstr "Torju alhaalta"
-#: engines/scumm/help.cpp:301
+#: engines/scumm/help.cpp:311
msgid "Punch high"
msgstr "Lyі ylіs"
-#: engines/scumm/help.cpp:302
+#: engines/scumm/help.cpp:312
msgid "Punch middle"
msgstr "Lyі keskelle"
-#: engines/scumm/help.cpp:303
+#: engines/scumm/help.cpp:313
msgid "Punch low"
msgstr "Lyі alas"
-#: engines/scumm/help.cpp:306
+#: engines/scumm/help.cpp:315
+msgid "Sucker punch"
+msgstr ""
+
+#: engines/scumm/help.cpp:318
msgid "These are for Indy on left."
msgstr "Nфmф ovat Indylle vasemmalla."
-#: engines/scumm/help.cpp:307
+#: engines/scumm/help.cpp:319
msgid "When Indy is on the right,"
msgstr "Kun Indy on oikealla, "
-#: engines/scumm/help.cpp:308
+#: engines/scumm/help.cpp:320
msgid "7, 4, and 1 are switched with"
msgstr "7, 4 ja 1 vaihdetaan nфppфinten"
-#: engines/scumm/help.cpp:309
+#: engines/scumm/help.cpp:321
msgid "9, 6, and 3, respectively."
msgstr "9, 6 ja 3 kanssa."
-#: engines/scumm/help.cpp:316
+#: engines/scumm/help.cpp:328
msgid "Biplane controls (numpad):"
msgstr "Koneen ohjaimet (numpad):"
-#: engines/scumm/help.cpp:317
+#: engines/scumm/help.cpp:329
msgid "Fly to upper left"
msgstr "Lennф ylіs vasemmalle"
-#: engines/scumm/help.cpp:318
+#: engines/scumm/help.cpp:330
msgid "Fly to left"
msgstr "Lennф vasemmalle"
-#: engines/scumm/help.cpp:319
+#: engines/scumm/help.cpp:331
msgid "Fly to lower left"
msgstr "Lennф alas vasemmalle"
-#: engines/scumm/help.cpp:320
+#: engines/scumm/help.cpp:332
msgid "Fly upwards"
msgstr "Lennф ylіspфin"
-#: engines/scumm/help.cpp:321
+#: engines/scumm/help.cpp:333
msgid "Fly straight"
msgstr "Lennф suoraan"
-#: engines/scumm/help.cpp:322
+#: engines/scumm/help.cpp:334
msgid "Fly down"
msgstr "Lennф alas"
-#: engines/scumm/help.cpp:323
+#: engines/scumm/help.cpp:335
msgid "Fly to upper right"
msgstr "Lennф ylіs oikealle"
-#: engines/scumm/help.cpp:324
+#: engines/scumm/help.cpp:336
msgid "Fly to right"
msgstr "Lennф oikealle"
-#: engines/scumm/help.cpp:325
+#: engines/scumm/help.cpp:337
msgid "Fly to lower right"
msgstr "Lennф alas oikealle"
-#: engines/scumm/scumm.cpp:1823
+#: engines/scumm/scumm.cpp:1832
#, c-format
msgid ""
"Native MIDI support requires the Roland Upgrade from LucasArts,\n"
@@ -3197,11 +3286,12 @@ msgstr ""
"Suora MIDI tuki vaatii Roland pфivityksen LucasArtsilta, mutta\n"
"%s puuttuu. Kфytetффn AdLibia sen sijaan."
-#: engines/scumm/scumm.cpp:2594
+#: engines/scumm/scumm.cpp:2644
+#, fuzzy
msgid ""
-"Usually, Maniac Mansion would start now. But ScummVM doesn't do that yet. To "
-"play it, go to 'Add Game' in the ScummVM start menu and select the 'Maniac' "
-"directory inside the Tentacle game directory."
+"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 Mansionin pitфisi nyt kфynnistyф, mutta ScummVM ei tue sitф vielф. "
"Pelataksesi Maniac Mansionia, mene ScummVM:n pффvalikkoon ja paina 'Lisфф "
@@ -3338,6 +3428,47 @@ msgstr ""
msgid "Show the current number of frames per second in the upper left corner"
msgstr ""
+#: engines/zvision/detection.cpp:256
+msgid "Double FPS"
+msgstr ""
+
+#: engines/zvision/detection.cpp:257
+msgid "Increase game FPS from 30 to 60"
+msgstr ""
+
+#: engines/zvision/detection.cpp:266
+#, fuzzy
+msgid "Enable Venus"
+msgstr "Kфytф helium moodia"
+
+#: engines/zvision/detection.cpp:267
+msgid "Enable the Venus help system"
+msgstr ""
+
+#: engines/zvision/detection.cpp:276
+msgid "Disable animation while turning"
+msgstr ""
+
+#: engines/zvision/detection.cpp:277
+msgid "Disable animation while turning in panoramic mode"
+msgstr ""
+
+#: engines/zvision/detection.cpp:286
+msgid "Use the hires MPEG movies"
+msgstr ""
+
+#: engines/zvision/detection.cpp:287
+#, fuzzy
+msgid ""
+"Use the hires MPEG movies of the DVD version, instead of the lowres AVI ones"
+msgstr "Kфytф vaihtoehtoisia hopeisia kursoreita normaalien kultaisten sijaan"
+
+#~ msgid "EGA undithering"
+#~ msgstr "EGA unditterіinti"
+
+#~ msgid "Enable undithering in EGA games"
+#~ msgstr "Kфytф unditterіintiф EGA peleissф"
+
#, fuzzy
#~ msgid "MPEG-2 cutscenes found but ScummVM has been built without MPEG-2"
#~ msgstr "PSX videoita lіydetty, mutta ScummVM on kффnnetty ilman RGB tukea"
@@ -3346,9 +3477,6 @@ msgstr ""
#~ msgid "Mass Add..."
#~ msgstr "Lisфф monta..."
-#~ msgid "Mass Add..."
-#~ msgstr "Lisфф monta..."
-
#~ msgid ""
#~ "Turns off General MIDI mapping for games with Roland MT-32 soundtrack"
#~ msgstr "Poistaa General MIDIn peleistф joissa on Roland MT-32 ффniraita"
diff --git a/po/fr_FR.po b/po/fr_FR.po
index 4e2654e706..2627e1e54f 100644
--- a/po/fr_FR.po
+++ b/po/fr_FR.po
@@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: ScummVM 1.3.0svn\n"
"Report-Msgid-Bugs-To: scummvm-devel@lists.sf.net\n"
-"POT-Creation-Date: 2014-10-04 00:58+0100\n"
+"POT-Creation-Date: 2015-06-30 20:57+0100\n"
"PO-Revision-Date: 2014-07-05 13:49-0000\n"
"Last-Translator: Thierry Crozat <criezy@scummvm.org>\n"
"Language-Team: French <scummvm-devel@lists.sf.net>\n"
@@ -54,10 +54,11 @@ msgstr "Remonter"
#: gui/browser.cpp:75 gui/chooser.cpp:46 gui/KeysDialog.cpp:43
#: gui/launcher.cpp:351 gui/massadd.cpp:95 gui/options.cpp:1239
+#: gui/recorderdialog.cpp:70 gui/recorderdialog.cpp:156
#: gui/saveload-dialog.cpp:216 gui/saveload-dialog.cpp:276
-#: gui/saveload-dialog.cpp:547 gui/saveload-dialog.cpp:922
+#: gui/saveload-dialog.cpp:547 gui/saveload-dialog.cpp:931
#: gui/themebrowser.cpp:55 gui/fluidsynth-dialog.cpp:152
-#: engines/engine.cpp:452 backends/platform/wii/options.cpp:48
+#: engines/engine.cpp:483 backends/platform/wii/options.cpp:48
#: backends/events/default/default-events.cpp:196
#: backends/events/default/default-events.cpp:218
#: engines/drascula/saveload.cpp:49 engines/parallaction/saveload.cpp:274
@@ -70,9 +71,9 @@ msgid "Choose"
msgstr "Choisir"
#: gui/gui-manager.cpp:117 backends/keymapper/remap-dialog.cpp:53
-#: 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
+#: 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"
@@ -88,7 +89,7 @@ msgstr "Afficher le clavier"
msgid "Remap keys"
msgstr "Changer l'affectation des touches"
-#: gui/gui-manager.cpp:131 base/main.cpp:326 engines/scumm/help.cpp:86
+#: gui/gui-manager.cpp:131 base/main.cpp:326 engines/scumm/help.cpp:87
msgid "Toggle fullscreen"
msgstr "Basculer en plein щcran"
@@ -102,13 +103,13 @@ 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:1240
-#: gui/saveload-dialog.cpp:923 gui/fluidsynth-dialog.cpp:153
-#: engines/engine.cpp:371 engines/engine.cpp:382
+#: 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:399 engines/parallaction/saveload.cpp:274
-#: engines/scumm/dialogs.cpp:193 engines/scumm/scumm.cpp:1825
+#: 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
@@ -479,7 +480,7 @@ msgstr ""
#: gui/launcher.cpp:793 gui/launcher.cpp:941 gui/launcher.cpp:1000
#: gui/fluidsynth-dialog.cpp:217
-#: backends/events/symbiansdl/symbiansdl-events.cpp:184
+#: 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
@@ -489,7 +490,7 @@ 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:184
+#: 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
@@ -526,6 +527,14 @@ msgstr ""
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
+msgid "Mass Add..."
+msgstr "Ajout Massif..."
+
+#: gui/launcher.cpp:1161
+msgid "Record..."
+msgstr ""
+
#: gui/massadd.cpp:79 gui/massadd.cpp:82
msgid "... progress ..."
msgstr "... en cours ..."
@@ -625,7 +634,7 @@ msgid "Special dithering modes supported by some games"
msgstr "Mode spщcial de tramage supportщ par certains jeux"
#: gui/options.cpp:760
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2249
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2298
msgid "Fullscreen mode"
msgstr "Plein щcran"
@@ -950,6 +959,43 @@ msgstr ""
"Le thшme que vous avez sщlectionщ ne support pas la langue franчaise. Si "
"vous voulez l'utiliser vous devez d'abord changer de langue."
+#: gui/recorderdialog.cpp:64
+msgid "Recorder or Playback Gameplay"
+msgstr ""
+
+#: gui/recorderdialog.cpp:69 gui/recorderdialog.cpp:156
+#: gui/saveload-dialog.cpp:220 gui/saveload-dialog.cpp:276
+msgid "Delete"
+msgstr "Supprimer"
+
+#: gui/recorderdialog.cpp:71
+msgid "Record"
+msgstr ""
+
+#: gui/recorderdialog.cpp:72
+#, fuzzy
+msgid "Playback"
+msgstr "Jouer"
+
+#: gui/recorderdialog.cpp:74
+msgid "Edit"
+msgstr ""
+
+#: gui/recorderdialog.cpp:86 gui/recorderdialog.cpp:243
+#: gui/recorderdialog.cpp:253
+msgid "Author: "
+msgstr ""
+
+#: gui/recorderdialog.cpp:87 gui/recorderdialog.cpp:244
+#: gui/recorderdialog.cpp:254
+msgid "Notes: "
+msgstr ""
+
+#: gui/recorderdialog.cpp:155
+#, fuzzy
+msgid "Do you really want to delete this record?"
+msgstr "Voulez-vous vraiment supprimer cette sauvegarde ?"
+
#: gui/saveload-dialog.cpp:167
msgid "List view"
msgstr "Vue en liste"
@@ -970,23 +1016,19 @@ msgstr "Heure inconnue"
msgid "No playtime saved"
msgstr "Durщe de jeu inconnue"
-#: gui/saveload-dialog.cpp:220 gui/saveload-dialog.cpp:276
-msgid "Delete"
-msgstr "Supprimer"
-
#: gui/saveload-dialog.cpp:275
msgid "Do you really want to delete this saved game?"
msgstr "Voulez-vous vraiment supprimer cette sauvegarde ?"
-#: gui/saveload-dialog.cpp:385 gui/saveload-dialog.cpp:875
+#: gui/saveload-dialog.cpp:385 gui/saveload-dialog.cpp:884
msgid "Date: "
msgstr "Date: "
-#: gui/saveload-dialog.cpp:389 gui/saveload-dialog.cpp:881
+#: gui/saveload-dialog.cpp:389 gui/saveload-dialog.cpp:890
msgid "Time: "
msgstr "Heure: "
-#: gui/saveload-dialog.cpp:395 gui/saveload-dialog.cpp:889
+#: gui/saveload-dialog.cpp:395 gui/saveload-dialog.cpp:898
msgid "Playtime: "
msgstr "Durщe de jeu: "
@@ -1002,19 +1044,19 @@ msgstr "Suivant"
msgid "Prev"
msgstr "Prщcщdent"
-#: gui/saveload-dialog.cpp:739
+#: gui/saveload-dialog.cpp:748
msgid "New Save"
msgstr "Nouvelle Sauvegarde"
-#: gui/saveload-dialog.cpp:739
+#: gui/saveload-dialog.cpp:748
msgid "Create a new save game"
msgstr "Crщe une nouvelle sauvegarde."
-#: gui/saveload-dialog.cpp:868
+#: gui/saveload-dialog.cpp:877
msgid "Name: "
msgstr "Nom: "
-#: gui/saveload-dialog.cpp:940
+#: gui/saveload-dialog.cpp:949
#, c-format
msgid "Enter a description for slot %d:"
msgstr "Entrez une description pour l'emplacement %d:"
@@ -1166,7 +1208,7 @@ msgstr "Passer la phrase"
msgid "Error running game:"
msgstr "Erreur lors de l'щxщcution du jeu:"
-#: base/main.cpp:536
+#: base/main.cpp:554
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щ"
@@ -1285,7 +1327,7 @@ 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:758
+#: engines/pegasus/pegasus.cpp:377 engines/sci/engine/kfile.cpp:759
#: engines/toltecs/menu.cpp:281 engines/tsage/scenes.cpp:598
msgid "Save game:"
msgstr "Sauvegarde:"
@@ -1298,7 +1340,7 @@ msgstr "Sauvegarde:"
#: 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:758 engines/scumm/dialogs.cpp:188
+#: engines/sci/engine/kfile.cpp:759 engines/scumm/dialogs.cpp:188
#: engines/toltecs/menu.cpp:281 engines/tsage/scenes.cpp:598
msgid "Save"
msgstr "Sauver"
@@ -1336,23 +1378,23 @@ msgstr "~A~nnuler"
msgid "~K~eys"
msgstr "~T~ouches"
-#: engines/engine.cpp:245
+#: engines/engine.cpp:276
msgid "Could not initialize color format."
msgstr "Impossible d'initialiser le format des couleurs."
-#: engines/engine.cpp:253
+#: engines/engine.cpp:284
msgid "Could not switch to video mode: '"
msgstr "Impossible de changer le mode vidщo р: '"
-#: engines/engine.cpp:262
+#: engines/engine.cpp:293
msgid "Could not apply aspect ratio setting."
msgstr "Impossible d'appliquer la correction du rapport d'aspect."
-#: engines/engine.cpp:267
+#: engines/engine.cpp:298
msgid "Could not apply fullscreen setting."
msgstr "Impossible d'appliquer l'option plein щcran."
-#: engines/engine.cpp:367
+#: engines/engine.cpp:398
msgid ""
"You appear to be playing this game directly\n"
"from the CD. This is known to cause problems,\n"
@@ -1366,7 +1408,7 @@ msgstr ""
"donnщes du jeu sur votre disque dur.\n"
"Lisez le fichier README pour plus de dщtails."
-#: engines/engine.cpp:378
+#: engines/engine.cpp:409
msgid ""
"This game has audio tracks in its disk. These\n"
"tracks need to be ripped from the disk using\n"
@@ -1380,7 +1422,7 @@ msgstr ""
"logiciel appropriщ.\n"
"Lisez le fichier README pour plus de dщtails."
-#: engines/engine.cpp:436
+#: engines/engine.cpp:467
#, c-format
msgid ""
"Gamestate load failed (%s)! Please consult the README for basic information, "
@@ -1389,7 +1431,7 @@ msgstr ""
"Echec du chargement (%s)! . Lisez le fichier README pour les informations de "
"base et les instructions pour obtenir de l'aide supplщmentaire."
-#: engines/engine.cpp:449
+#: engines/engine.cpp:480
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 "
@@ -1399,7 +1441,7 @@ msgstr ""
"complшtement supportщ par ScummVM. Il est donc instable et les sauvegardes "
"peuvent ne pas marcher avec une future version de ScummVM."
-#: engines/engine.cpp:452
+#: engines/engine.cpp:483
msgid "Start anyway"
msgstr "Jouer quand mъme"
@@ -1609,11 +1651,11 @@ msgstr "Mode touchpad activщ"
msgid "Touchpad mode disabled."
msgstr "Mode touchpad dщsactivщ"
-#: backends/platform/maemo/maemo.cpp:209
+#: backends/platform/maemo/maemo.cpp:208
msgid "Click Mode"
msgstr "Mode Clic"
-#: backends/platform/maemo/maemo.cpp:215
+#: backends/platform/maemo/maemo.cpp:214
#: backends/platform/symbian/src/SymbianActions.cpp:42
#: backends/platform/wince/CEActionsPocket.cpp:60
#: backends/platform/wince/CEActionsSmartphone.cpp:43
@@ -1621,11 +1663,11 @@ msgstr "Mode Clic"
msgid "Left Click"
msgstr "Clic Gauche"
-#: backends/platform/maemo/maemo.cpp:218
+#: backends/platform/maemo/maemo.cpp:217
msgid "Middle Click"
msgstr "Clic Milieu"
-#: backends/platform/maemo/maemo.cpp:221
+#: 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
@@ -1662,19 +1704,19 @@ msgctxt "lowres"
msgid "Normal (no scaling)"
msgstr "Normal"
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2148
+#: 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:2154
+#: 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:2209
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2258
msgid "Active graphics filter:"
msgstr "Mode graphique actif:"
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2251
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2300
msgid "Windowed mode"
msgstr "Mode Fenъtre"
@@ -1733,8 +1775,8 @@ msgstr "Mode rapide"
#: 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:82
-#: engines/scumm/help.cpp:84
+#: engines/scumm/dialogs.cpp:192 engines/scumm/help.cpp:83
+#: engines/scumm/help.cpp:85
msgid "Quit"
msgstr "Quitter"
@@ -1754,7 +1796,7 @@ msgstr "Clavier virtuel"
msgid "Key mapper"
msgstr "Affectation des touches"
-#: backends/events/symbiansdl/symbiansdl-events.cpp:184
+#: backends/events/symbiansdl/symbiansdl-events.cpp:186
msgid "Do you want to quit ?"
msgstr "Voulez-vous quitter ?"
@@ -2091,35 +2133,56 @@ msgstr "Clic Activщ"
msgid "Clicking Disabled"
msgstr "Clic Dщsactivщ"
-#: engines/agi/detection.cpp:142 engines/drascula/detection.cpp:302
+#: 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.cpp:103
+#: engines/zvision/detection.cpp:246
msgid "Use original save/load screens"
msgstr "Dialogues sauvegarde/chargement d'origine"
-#: engines/agi/detection.cpp:143 engines/drascula/detection.cpp:303
+#: 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/zvision/detection.cpp:104
+#: engines/zvision/detection.cpp:247
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)"
+
+#: engines/agi/detection.cpp:158
+msgid ""
+"Use an alternative palette, common for all Amiga games. This was the old "
+"behavior"
+msgstr ""
+
+#: engines/agi/detection.cpp:167
+#, fuzzy
+msgid "Mouse support"
+msgstr "Support des interruptions"
+
+#: 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:857 engines/toltecs/menu.cpp:256
+#: engines/sci/engine/kfile.cpp:858 engines/toltecs/menu.cpp:256
msgid "Restore game:"
msgstr "Charger le jeu:"
#: 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:857 engines/toltecs/menu.cpp:256
+#: engines/sci/engine/kfile.cpp:858 engines/toltecs/menu.cpp:256
msgid "Restore"
msgstr "Charger"
-#: engines/agos/saveload.cpp:160 engines/scumm/scumm.cpp:2368
+#: engines/agos/saveload.cpp:160 engines/scumm/scumm.cpp:2377
#, c-format
msgid ""
"Failed to load game state from file:\n"
@@ -2130,7 +2193,7 @@ msgstr ""
"\n"
"%s"
-#: engines/agos/saveload.cpp:195 engines/scumm/scumm.cpp:2361
+#: engines/agos/saveload.cpp:195 engines/scumm/scumm.cpp:2370
#, c-format
msgid ""
"Failed to save game state to file:\n"
@@ -2141,7 +2204,7 @@ msgstr ""
"\n"
"%s"
-#: engines/agos/saveload.cpp:203 engines/scumm/scumm.cpp:2379
+#: engines/agos/saveload.cpp:203 engines/scumm/scumm.cpp:2388
#, c-format
msgid ""
"Successfully saved game state in file:\n"
@@ -2157,12 +2220,12 @@ msgstr ""
msgid "Cutscene file '%s' not found!"
msgstr "Fichier de sщquence '%s' non trouvщ!"
-#: engines/cge/detection.cpp:105 engines/cge2/detection.cpp:81
+#: engines/cge/detection.cpp:105 engines/cge2/detection.cpp:101
#, fuzzy
msgid "Color Blind Mode"
msgstr "Mode Clic"
-#: engines/cge/detection.cpp:106 engines/cge2/detection.cpp:82
+#: engines/cge/detection.cpp:106 engines/cge2/detection.cpp:102
msgid "Enable Color Blind Mode by default"
msgstr ""
@@ -2214,7 +2277,7 @@ msgstr "Vidщo rapide"
msgid "Play movies at an increased speed"
msgstr "Joue les vidщos plus rapidement"
-#: engines/groovie/script.cpp:399
+#: engines/groovie/script.cpp:408
msgid "Failed to save game"
msgstr "Щchec de la sauvegarde."
@@ -2513,12 +2576,12 @@ msgid "Use an alternative game intro (CD version only)"
msgstr "Utiliser une intro alternative (version CD uniquement)"
#: engines/sci/detection.cpp:374
-msgid "EGA undithering"
-msgstr "Dщtramage EGA"
+msgid "Skip EGA dithering pass (full color backgrounds)"
+msgstr ""
#: engines/sci/detection.cpp:375
-msgid "Enable undithering in EGA games"
-msgstr "Activer le dщtramage dans les jeux EGA"
+msgid "Skip dithering pass in EGA games, graphics are shown with full colors"
+msgstr ""
#: engines/sci/detection.cpp:384
msgid "Prefer digital sound effects"
@@ -2593,12 +2656,14 @@ msgstr "Jeu en pause. Appuyer sur Espace pour Reprendre."
#. "Moechten Sie wirklich neu starten? (J/N)J"
#. Will react to J as 'Yes'
#: engines/scumm/dialogs.cpp:183
-msgid "Are you sure you want to restart? (Y/N)"
+#, fuzzy
+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
-msgid "Are you sure you want to quit? (Y/N)"
+#, fuzzy
+msgid "Are you sure you want to quit? (Y/N)Y"
msgstr "Voulez-vous vraiment quitter ? (O/N)O"
#: engines/scumm/dialogs.cpp:190
@@ -2686,516 +2751,541 @@ msgstr "Essai"
msgid "Expert"
msgstr "Expert"
-#: engines/scumm/help.cpp:73
+#: engines/scumm/help.cpp:74
msgid "Common keyboard commands:"
msgstr "Commandes clavier communes:"
-#: engines/scumm/help.cpp:74
+#: engines/scumm/help.cpp:75
msgid "Save / Load dialog"
msgstr "Dialogue de Sauvegarde/Chargement"
-#: engines/scumm/help.cpp:76
+#: engines/scumm/help.cpp:77
msgid "Skip line of text"
msgstr "Passer la phrase"
-#: engines/scumm/help.cpp:77
+#: engines/scumm/help.cpp:78
msgid "Esc"
msgstr "Esc"
-#: engines/scumm/help.cpp:77
+#: engines/scumm/help.cpp:78
msgid "Skip cutscene"
msgstr "Passer la sщquence"
-#: engines/scumm/help.cpp:78
+#: engines/scumm/help.cpp:79
msgid "Space"
msgstr "Espace"
-#: engines/scumm/help.cpp:78
+#: engines/scumm/help.cpp:79
msgid "Pause game"
msgstr "Mettre en pause:"
-#: engines/scumm/help.cpp:79 engines/scumm/help.cpp:84
-#: engines/scumm/help.cpp:95 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: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:79
+#: engines/scumm/help.cpp:80
msgid "Load game state 1-10"
msgstr "Charger sauvegarde 1-10:"
-#: engines/scumm/help.cpp:80 engines/scumm/help.cpp:84
-#: engines/scumm/help.cpp:86 engines/scumm/help.cpp:100
-#: engines/scumm/help.cpp:101 engines/scumm/help.cpp:102
+#: 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:80
+#: engines/scumm/help.cpp:81
msgid "Save game state 1-10"
msgstr "Щcrire sauvegarde 1-10:"
-#: engines/scumm/help.cpp:86 engines/scumm/help.cpp:89
+#: engines/scumm/help.cpp:87 engines/scumm/help.cpp:90
msgid "Enter"
msgstr "Entrer"
-#: engines/scumm/help.cpp:87
+#: engines/scumm/help.cpp:88
msgid "Music volume up / down"
msgstr "Augmenter / Diminuer volume musique"
-#: engines/scumm/help.cpp:88
+#: engines/scumm/help.cpp:89
msgid "Text speed slower / faster"
msgstr "Diminuer/Augmenter vitesse du texte"
-#: engines/scumm/help.cpp:89
+#: engines/scumm/help.cpp:90
msgid "Simulate left mouse button"
msgstr "Simuler bouton gauche de la souris"
-#: engines/scumm/help.cpp:90
+#: engines/scumm/help.cpp:91
msgid "Tab"
msgstr "Tab"
-#: engines/scumm/help.cpp:90
+#: engines/scumm/help.cpp:91
msgid "Simulate right mouse button"
msgstr "Simuler bouton droit de la souris"
-#: engines/scumm/help.cpp:93
+#: engines/scumm/help.cpp:94
msgid "Special keyboard commands:"
msgstr "Commandes clavier spщciales:"
-#: engines/scumm/help.cpp:94
+#: engines/scumm/help.cpp:95
msgid "Show / Hide console"
msgstr "Afficher/Cacher la console"
-#: engines/scumm/help.cpp:95
+#: engines/scumm/help.cpp:96
msgid "Start the debugger"
msgstr "Ouvrir le dщbugger"
-#: engines/scumm/help.cpp:96
+#: engines/scumm/help.cpp:97
msgid "Show memory consumption"
msgstr "Afficher la consomation de mщmoire"
-#: engines/scumm/help.cpp:97
+#: engines/scumm/help.cpp:98
msgid "Run in fast mode (*)"
msgstr "Jouer en mode rapide (*)"
-#: engines/scumm/help.cpp:98
+#: engines/scumm/help.cpp:99
msgid "Run in really fast mode (*)"
msgstr "Jouer en mode trшs rapide (*)"
-#: engines/scumm/help.cpp:99
+#: engines/scumm/help.cpp:100
msgid "Toggle mouse capture"
msgstr "Capturer/Libщrer la souris"
-#: engines/scumm/help.cpp:100
+#: engines/scumm/help.cpp:101
msgid "Switch between graphics filters"
msgstr "Changer de filtre graphique"
-#: engines/scumm/help.cpp:101
+#: engines/scumm/help.cpp:102
msgid "Increase / Decrease scale factor"
msgstr "Augmenter/Diminuer le facteur d'щchelle"
-#: engines/scumm/help.cpp:102
+#: engines/scumm/help.cpp:103
msgid "Toggle aspect-ratio correction"
msgstr "Changer correction du rapport d'aspect"
-#: engines/scumm/help.cpp:107
+#: engines/scumm/help.cpp:108
msgid "* Note that using ctrl-f and"
msgstr "* Note que l'utilisation de crtl-f et"
-#: engines/scumm/help.cpp:108
+#: engines/scumm/help.cpp:109
msgid " ctrl-g are not recommended"
msgstr " crtl-g n'est pas recommandщ car"
-#: engines/scumm/help.cpp:109
+#: engines/scumm/help.cpp:110
msgid " since they may cause crashes"
msgstr " elle peut causer des plantages ou"
-#: engines/scumm/help.cpp:110
+#: engines/scumm/help.cpp:111
msgid " or incorrect game behavior."
msgstr " ou comportement incorrect du jeu."
-#: engines/scumm/help.cpp:114
+#: engines/scumm/help.cpp:115
msgid "Spinning drafts on the keyboard:"
msgstr "Filage au clavier:"
-#: engines/scumm/help.cpp:116
+#: engines/scumm/help.cpp:117
msgid "Main game controls:"
msgstr "Controles principaux du jeu:"
-#: engines/scumm/help.cpp:121 engines/scumm/help.cpp:136
-#: engines/scumm/help.cpp:161
+#: engines/scumm/help.cpp:122 engines/scumm/help.cpp:137
+#: engines/scumm/help.cpp:162
msgid "Push"
msgstr "Pousser"
-#: engines/scumm/help.cpp:122 engines/scumm/help.cpp:137
-#: engines/scumm/help.cpp:162
+#: engines/scumm/help.cpp:123 engines/scumm/help.cpp:138
+#: engines/scumm/help.cpp:163
msgid "Pull"
msgstr "Tirer"
-#: engines/scumm/help.cpp:123 engines/scumm/help.cpp:138
-#: engines/scumm/help.cpp:163 engines/scumm/help.cpp:197
-#: engines/scumm/help.cpp:207
+#: 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 "Donner"
-#: engines/scumm/help.cpp:124 engines/scumm/help.cpp:139
-#: engines/scumm/help.cpp:164 engines/scumm/help.cpp:190
-#: engines/scumm/help.cpp:208
+#: 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 "Ouvrir"
-#: engines/scumm/help.cpp:126
+#: engines/scumm/help.cpp:127
msgid "Go to"
msgstr "Aller"
-#: engines/scumm/help.cpp:127
+#: engines/scumm/help.cpp:128
msgid "Get"
msgstr "Prendre"
-#: engines/scumm/help.cpp:128 engines/scumm/help.cpp:152
-#: engines/scumm/help.cpp:170 engines/scumm/help.cpp:198
-#: engines/scumm/help.cpp:213 engines/scumm/help.cpp:224
-#: engines/scumm/help.cpp:250
+#: 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 "Utiliser"
-#: engines/scumm/help.cpp:129 engines/scumm/help.cpp:141
+#: engines/scumm/help.cpp:130 engines/scumm/help.cpp:142
msgid "Read"
msgstr "Lire"
-#: engines/scumm/help.cpp:130 engines/scumm/help.cpp:147
+#: engines/scumm/help.cpp:131 engines/scumm/help.cpp:148
msgid "New kid"
msgstr "Changer"
-#: engines/scumm/help.cpp:131 engines/scumm/help.cpp:153
-#: engines/scumm/help.cpp:171
+#: engines/scumm/help.cpp:132 engines/scumm/help.cpp:154
+#: engines/scumm/help.cpp:172
msgid "Turn on"
msgstr "Allumer"
-#: engines/scumm/help.cpp:132 engines/scumm/help.cpp:154
-#: engines/scumm/help.cpp:172
+#: engines/scumm/help.cpp:133 engines/scumm/help.cpp:155
+#: engines/scumm/help.cpp:173
msgid "Turn off"
msgstr "Щteindre"
-#: engines/scumm/help.cpp:142 engines/scumm/help.cpp:167
-#: engines/scumm/help.cpp:194
+#: engines/scumm/help.cpp:143 engines/scumm/help.cpp:168
+#: engines/scumm/help.cpp:195
msgid "Walk to"
msgstr "Aller"
-#: engines/scumm/help.cpp:143 engines/scumm/help.cpp:168
-#: engines/scumm/help.cpp:195 engines/scumm/help.cpp:210
-#: engines/scumm/help.cpp:227
+#: 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 "Prendre"
-#: engines/scumm/help.cpp:144 engines/scumm/help.cpp:169
+#: engines/scumm/help.cpp:145 engines/scumm/help.cpp:170
msgid "What is"
msgstr "Qu'est-ce"
-#: engines/scumm/help.cpp:146
+#: engines/scumm/help.cpp:147
msgid "Unlock"
msgstr "Dщverrouiller"
-#: engines/scumm/help.cpp:149
+#: engines/scumm/help.cpp:150
msgid "Put on"
msgstr "Mettre"
-#: engines/scumm/help.cpp:150
+#: engines/scumm/help.cpp:151
msgid "Take off"
msgstr "Enlever"
-#: engines/scumm/help.cpp:156
+#: engines/scumm/help.cpp:157
msgid "Fix"
msgstr "Rщparer"
-#: engines/scumm/help.cpp:158
+#: engines/scumm/help.cpp:159
msgid "Switch"
msgstr "Commuter"
-#: engines/scumm/help.cpp:166 engines/scumm/help.cpp:228
+#: engines/scumm/help.cpp:167 engines/scumm/help.cpp:229
msgid "Look"
msgstr "Regarder"
-#: engines/scumm/help.cpp:173 engines/scumm/help.cpp:223
+#: engines/scumm/help.cpp:174 engines/scumm/help.cpp:224
msgid "Talk"
msgstr "Parler"
-#: engines/scumm/help.cpp:174
+#: engines/scumm/help.cpp:175
msgid "Travel"
msgstr "Voyager"
-#: engines/scumm/help.cpp:175
+#: engines/scumm/help.cpp:176
msgid "To Henry / To Indy"
msgstr "Henry / Indy"
#. I18N: These are different musical notes
-#: engines/scumm/help.cpp:179
+#: engines/scumm/help.cpp:180
msgid "play C minor on distaff"
msgstr "jouer Do mineur sur la quenouille"
-#: engines/scumm/help.cpp:180
+#: engines/scumm/help.cpp:181
msgid "play D on distaff"
msgstr "jouer Rщ sur la quenouille"
-#: engines/scumm/help.cpp:181
+#: engines/scumm/help.cpp:182
msgid "play E on distaff"
msgstr "jouer Mi sur la quenouille"
-#: engines/scumm/help.cpp:182
+#: engines/scumm/help.cpp:183
msgid "play F on distaff"
msgstr "jouer Fa sur la quenouille"
-#: engines/scumm/help.cpp:183
+#: engines/scumm/help.cpp:184
msgid "play G on distaff"
msgstr "jouer Sol sur la quenouille"
-#: engines/scumm/help.cpp:184
+#: engines/scumm/help.cpp:185
msgid "play A on distaff"
msgstr "jouer La sur la quenouille"
-#: engines/scumm/help.cpp:185
+#: engines/scumm/help.cpp:186
msgid "play B on distaff"
msgstr "jouer Si sur la quenouille"
-#: engines/scumm/help.cpp:186
+#: engines/scumm/help.cpp:187
msgid "play C major on distaff"
msgstr "jouer Do Majeur sur la quenouille"
-#: engines/scumm/help.cpp:192 engines/scumm/help.cpp:214
+#: engines/scumm/help.cpp:193 engines/scumm/help.cpp:215
msgid "puSh"
msgstr "Pousser"
-#: engines/scumm/help.cpp:193 engines/scumm/help.cpp:215
+#: engines/scumm/help.cpp:194 engines/scumm/help.cpp:216
msgid "pull (Yank)"
msgstr "Tirer"
-#: engines/scumm/help.cpp:196 engines/scumm/help.cpp:212
-#: engines/scumm/help.cpp:248
+#: engines/scumm/help.cpp:197 engines/scumm/help.cpp:213
+#: engines/scumm/help.cpp:249
msgid "Talk to"
msgstr "Parler р"
-#: engines/scumm/help.cpp:199 engines/scumm/help.cpp:211
+#: engines/scumm/help.cpp:200 engines/scumm/help.cpp:212
msgid "Look at"
msgstr "Regarder"
-#: engines/scumm/help.cpp:200
+#: engines/scumm/help.cpp:201
msgid "turn oN"
msgstr "Allumer"
-#: engines/scumm/help.cpp:201
+#: engines/scumm/help.cpp:202
msgid "turn oFf"
msgstr "Щteindre"
-#: engines/scumm/help.cpp:217
+#: engines/scumm/help.cpp:218
msgid "KeyUp"
msgstr "Touche Haut"
-#: engines/scumm/help.cpp:217
+#: engines/scumm/help.cpp:218
msgid "Highlight prev dialogue"
msgstr "Sщlectionner le dialogue prщcщdent"
-#: engines/scumm/help.cpp:218
+#: engines/scumm/help.cpp:219
msgid "KeyDown"
msgstr "Touche Bas"
-#: engines/scumm/help.cpp:218
+#: engines/scumm/help.cpp:219
msgid "Highlight next dialogue"
msgstr "Sщlectionner le dialogue suivant"
-#: engines/scumm/help.cpp:222
+#: engines/scumm/help.cpp:223
msgid "Walk"
msgstr "Marcher"
-#: engines/scumm/help.cpp:225 engines/scumm/help.cpp:234
-#: engines/scumm/help.cpp:241 engines/scumm/help.cpp:249
+#: engines/scumm/help.cpp:226 engines/scumm/help.cpp:235
+#: engines/scumm/help.cpp:242 engines/scumm/help.cpp:250
msgid "Inventory"
msgstr "Inventaire"
-#: engines/scumm/help.cpp:226
+#: engines/scumm/help.cpp:227
msgid "Object"
msgstr "Objet"
-#: engines/scumm/help.cpp:229
+#: engines/scumm/help.cpp:230
msgid "Black and White / Color"
msgstr "Noir et Blanc / Couleur"
-#: engines/scumm/help.cpp:232
+#: engines/scumm/help.cpp:233
msgid "Eyes"
msgstr "Yeux"
-#: engines/scumm/help.cpp:233
+#: engines/scumm/help.cpp:234
msgid "Tongue"
msgstr "Langue"
-#: engines/scumm/help.cpp:235
+#: engines/scumm/help.cpp:236
msgid "Punch"
msgstr "Frapper"
-#: engines/scumm/help.cpp:236
+#: engines/scumm/help.cpp:237
msgid "Kick"
msgstr "Coup de pied"
-#: engines/scumm/help.cpp:239 engines/scumm/help.cpp:247
+#: engines/scumm/help.cpp:240 engines/scumm/help.cpp:248
msgid "Examine"
msgstr "Examiner"
-#: engines/scumm/help.cpp:240
+#: engines/scumm/help.cpp:241
msgid "Regular cursor"
msgstr "Curseur normal"
#. I18N: Comm is a communication device
-#: engines/scumm/help.cpp:243
+#: engines/scumm/help.cpp:244
msgid "Comm"
msgstr "Comm"
-#: engines/scumm/help.cpp:246
+#: engines/scumm/help.cpp:247
msgid "Save / Load / Options"
msgstr "Sauvegarder / Charger / Options"
-#: engines/scumm/help.cpp:255
+#: engines/scumm/help.cpp:256
msgid "Other game controls:"
msgstr "Autres controles du jeu:"
-#: engines/scumm/help.cpp:257 engines/scumm/help.cpp:267
+#: engines/scumm/help.cpp:258 engines/scumm/help.cpp:268
msgid "Inventory:"
msgstr "Inventaires:"
-#: engines/scumm/help.cpp:258 engines/scumm/help.cpp:274
+#: engines/scumm/help.cpp:259 engines/scumm/help.cpp:275
msgid "Scroll list up"
msgstr "Faire dщfiler vers le haut"
-#: engines/scumm/help.cpp:259 engines/scumm/help.cpp:275
+#: engines/scumm/help.cpp:260 engines/scumm/help.cpp:276
msgid "Scroll list down"
msgstr "Faire dщfiler vers le bas"
-#: engines/scumm/help.cpp:260 engines/scumm/help.cpp:268
+#: engines/scumm/help.cpp:261 engines/scumm/help.cpp:269
msgid "Upper left item"
msgstr "Щlщment en haut р gauche"
-#: engines/scumm/help.cpp:261 engines/scumm/help.cpp:270
+#: engines/scumm/help.cpp:262 engines/scumm/help.cpp:271
msgid "Lower left item"
msgstr "Щlщment en bas р gauche"
-#: engines/scumm/help.cpp:262 engines/scumm/help.cpp:271
+#: engines/scumm/help.cpp:263 engines/scumm/help.cpp:272
msgid "Upper right item"
msgstr "Щlщment en haut р droite"
-#: engines/scumm/help.cpp:263 engines/scumm/help.cpp:273
+#: engines/scumm/help.cpp:264 engines/scumm/help.cpp:274
msgid "Lower right item"
msgstr "Щlщment en bas р droite"
-#: engines/scumm/help.cpp:269
+#: engines/scumm/help.cpp:270
msgid "Middle left item"
msgstr "Щlщment au milieu р gauche"
-#: engines/scumm/help.cpp:272
+#: engines/scumm/help.cpp:273
msgid "Middle right item"
msgstr "Щlщment au milieu р droite"
-#: engines/scumm/help.cpp:279 engines/scumm/help.cpp:284
+#: engines/scumm/help.cpp:280 engines/scumm/help.cpp:285
msgid "Switching characters:"
msgstr "Changer de personnage"
-#: engines/scumm/help.cpp:281
+#: engines/scumm/help.cpp:282
msgid "Second kid"
msgstr "Second enfant"
-#: engines/scumm/help.cpp:282
+#: engines/scumm/help.cpp:283
msgid "Third kid"
msgstr "Troisiшme enfant"
-#: engines/scumm/help.cpp:294
+#: engines/scumm/help.cpp:292
+#, fuzzy
+msgid "Toggle Inventory/IQ Points display"
+msgstr "Basculer l'Affichage Central"
+
+#: engines/scumm/help.cpp:293
+msgid "Toggle Keyboard/Mouse Fighting (*)"
+msgstr ""
+
+#: engines/scumm/help.cpp:295
+msgid "* Keyboard Fighting is always on,"
+msgstr ""
+
+#: engines/scumm/help.cpp:296
+msgid " so despite the in-game message this"
+msgstr ""
+
+#: engines/scumm/help.cpp:297
+msgid " actually toggles Mouse Fighting Off/On"
+msgstr ""
+
+#: engines/scumm/help.cpp:304
msgid "Fighting controls (numpad):"
msgstr "Controles de combat (pavet numщrique):"
-#: engines/scumm/help.cpp:295 engines/scumm/help.cpp:296
-#: engines/scumm/help.cpp:297
+#: engines/scumm/help.cpp:305 engines/scumm/help.cpp:306
+#: engines/scumm/help.cpp:307
msgid "Step back"
msgstr "Pas en arriшre"
-#: engines/scumm/help.cpp:298
+#: engines/scumm/help.cpp:308
msgid "Block high"
msgstr "Bloquer haut"
-#: engines/scumm/help.cpp:299
+#: engines/scumm/help.cpp:309
msgid "Block middle"
msgstr "Bloquer milieu"
-#: engines/scumm/help.cpp:300
+#: engines/scumm/help.cpp:310
msgid "Block low"
msgstr "Bloquer bas"
-#: engines/scumm/help.cpp:301
+#: engines/scumm/help.cpp:311
msgid "Punch high"
msgstr "Fraper haut"
-#: engines/scumm/help.cpp:302
+#: engines/scumm/help.cpp:312
msgid "Punch middle"
msgstr "Frapper milieu"
-#: engines/scumm/help.cpp:303
+#: engines/scumm/help.cpp:313
msgid "Punch low"
msgstr "Frapper bas"
-#: engines/scumm/help.cpp:306
+#: engines/scumm/help.cpp:315
+msgid "Sucker punch"
+msgstr ""
+
+#: engines/scumm/help.cpp:318
msgid "These are for Indy on left."
msgstr "Correct quand Indy est р gauche."
-#: engines/scumm/help.cpp:307
+#: engines/scumm/help.cpp:319
msgid "When Indy is on the right,"
msgstr "Quand Indy est р droite, 7, 4 et 1"
-#: engines/scumm/help.cpp:308
+#: engines/scumm/help.cpp:320
msgid "7, 4, and 1 are switched with"
msgstr "sont interverties avec 9, 6 et 3"
-#: engines/scumm/help.cpp:309
+#: engines/scumm/help.cpp:321
msgid "9, 6, and 3, respectively."
msgstr "respectivement."
-#: engines/scumm/help.cpp:316
+#: engines/scumm/help.cpp:328
msgid "Biplane controls (numpad):"
msgstr "Controles du biplane (paver numщrique):"
-#: engines/scumm/help.cpp:317
+#: engines/scumm/help.cpp:329
msgid "Fly to upper left"
msgstr "Voler vers le haut р gauche"
-#: engines/scumm/help.cpp:318
+#: engines/scumm/help.cpp:330
msgid "Fly to left"
msgstr "Voler vers la gauche"
-#: engines/scumm/help.cpp:319
+#: engines/scumm/help.cpp:331
msgid "Fly to lower left"
msgstr "Voler vers le bas р gauche"
-#: engines/scumm/help.cpp:320
+#: engines/scumm/help.cpp:332
msgid "Fly upwards"
msgstr "Voler vers le haut"
-#: engines/scumm/help.cpp:321
+#: engines/scumm/help.cpp:333
msgid "Fly straight"
msgstr "Voler tout droit"
-#: engines/scumm/help.cpp:322
+#: engines/scumm/help.cpp:334
msgid "Fly down"
msgstr "Voler vers le bas"
-#: engines/scumm/help.cpp:323
+#: engines/scumm/help.cpp:335
msgid "Fly to upper right"
msgstr "Voler vers le haut р droite"
-#: engines/scumm/help.cpp:324
+#: engines/scumm/help.cpp:336
msgid "Fly to right"
msgstr "Voler vers la droite"
-#: engines/scumm/help.cpp:325
+#: engines/scumm/help.cpp:337
msgid "Fly to lower right"
msgstr "Voler vers la bas р droite"
-#: engines/scumm/scumm.cpp:1823
+#: engines/scumm/scumm.cpp:1832
#, c-format
msgid ""
"Native MIDI support requires the Roland Upgrade from LucasArts,\n"
@@ -3204,11 +3294,12 @@ msgstr ""
"Support MIDI natif requiшre la mise р jour Roland de LucasArt,\n"
"mais %s manque. Utilise AdLib р la place."
-#: engines/scumm/scumm.cpp:2594
+#: engines/scumm/scumm.cpp:2644
+#, fuzzy
msgid ""
-"Usually, Maniac Mansion would start now. But ScummVM doesn't do that yet. To "
-"play it, go to 'Add Game' in the ScummVM start menu and select the 'Maniac' "
-"directory inside the Tentacle game directory."
+"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, "
@@ -3352,6 +3443,47 @@ msgstr ""
msgid "Show the current number of frames per second in the upper left corner"
msgstr ""
+#: engines/zvision/detection.cpp:256
+msgid "Double FPS"
+msgstr ""
+
+#: engines/zvision/detection.cpp:257
+msgid "Increase game FPS from 30 to 60"
+msgstr ""
+
+#: engines/zvision/detection.cpp:266
+#, fuzzy
+msgid "Enable Venus"
+msgstr "Activer le mode helium"
+
+#: engines/zvision/detection.cpp:267
+msgid "Enable the Venus help system"
+msgstr ""
+
+#: engines/zvision/detection.cpp:276
+msgid "Disable animation while turning"
+msgstr ""
+
+#: engines/zvision/detection.cpp:277
+msgid "Disable animation while turning in panoramic mode"
+msgstr ""
+
+#: engines/zvision/detection.cpp:286
+msgid "Use the hires MPEG movies"
+msgstr ""
+
+#: engines/zvision/detection.cpp:287
+#, fuzzy
+msgid ""
+"Use the hires MPEG movies of the DVD version, instead of the lowres AVI ones"
+msgstr "Utiliser les curseurs argentщs au lieu des curseurs normaux dorщs"
+
+#~ msgid "EGA undithering"
+#~ msgstr "Dщtramage EGA"
+
+#~ msgid "Enable undithering in EGA games"
+#~ msgstr "Activer le dщtramage dans les jeux EGA"
+
#~ msgid "MPEG-2 cutscenes found but ScummVM has been built without MPEG-2"
#~ msgstr ""
#~ "Scшnes cinщmatiques MPEG-2 dщtectщes mais ScummVM a щtщ compilщ sans le "
@@ -3361,9 +3493,6 @@ msgstr ""
#~ msgid "Mass Add..."
#~ msgstr "Ajout Massif..."
-#~ msgid "Mass Add..."
-#~ msgstr "Ajout Massif..."
-
#~ msgid ""
#~ "Turns off General MIDI mapping for games with Roland MT-32 soundtrack"
#~ msgstr "Dщsactiver la conversion des pistes MT-32 en General MIDI"
diff --git a/po/gl_ES.po b/po/gl_ES.po
index 971e6be4b8..a6a5365e42 100644
--- a/po/gl_ES.po
+++ b/po/gl_ES.po
@@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: ScummVM 1.6.0git\n"
"Report-Msgid-Bugs-To: scummvm-devel@lists.sf.net\n"
-"POT-Creation-Date: 2014-10-04 00:58+0100\n"
+"POT-Creation-Date: 2015-06-30 20:57+0100\n"
"PO-Revision-Date: 2014-07-02 09:51+0100\n"
"Last-Translator: Santiago G. Sanz <s.sanz@uvigo.es>\n"
"Language-Team: Santiago G. Sanz <s.sanz@uvigo.es>\n"
@@ -53,10 +53,11 @@ msgstr "Arriba"
#: gui/browser.cpp:75 gui/chooser.cpp:46 gui/KeysDialog.cpp:43
#: gui/launcher.cpp:351 gui/massadd.cpp:95 gui/options.cpp:1239
+#: gui/recorderdialog.cpp:70 gui/recorderdialog.cpp:156
#: gui/saveload-dialog.cpp:216 gui/saveload-dialog.cpp:276
-#: gui/saveload-dialog.cpp:547 gui/saveload-dialog.cpp:922
+#: gui/saveload-dialog.cpp:547 gui/saveload-dialog.cpp:931
#: gui/themebrowser.cpp:55 gui/fluidsynth-dialog.cpp:152
-#: engines/engine.cpp:452 backends/platform/wii/options.cpp:48
+#: engines/engine.cpp:483 backends/platform/wii/options.cpp:48
#: backends/events/default/default-events.cpp:196
#: backends/events/default/default-events.cpp:218
#: engines/drascula/saveload.cpp:49 engines/parallaction/saveload.cpp:274
@@ -69,9 +70,9 @@ msgid "Choose"
msgstr "Elixir"
#: gui/gui-manager.cpp:117 backends/keymapper/remap-dialog.cpp:53
-#: 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
+#: 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"
@@ -87,7 +88,7 @@ msgstr "Mostrar teclado"
msgid "Remap keys"
msgstr "Asignar teclas"
-#: gui/gui-manager.cpp:131 base/main.cpp:326 engines/scumm/help.cpp:86
+#: gui/gui-manager.cpp:131 base/main.cpp:326 engines/scumm/help.cpp:87
msgid "Toggle fullscreen"
msgstr "Activar/desactivar pantalla completa"
@@ -101,13 +102,13 @@ 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:1240
-#: gui/saveload-dialog.cpp:923 gui/fluidsynth-dialog.cpp:153
-#: engines/engine.cpp:371 engines/engine.cpp:382
+#: 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:399 engines/parallaction/saveload.cpp:274
-#: engines/scumm/dialogs.cpp:193 engines/scumm/scumm.cpp:1825
+#: 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
@@ -475,7 +476,7 @@ msgstr ""
#: gui/launcher.cpp:793 gui/launcher.cpp:941 gui/launcher.cpp:1000
#: gui/fluidsynth-dialog.cpp:217
-#: backends/events/symbiansdl/symbiansdl-events.cpp:184
+#: 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
@@ -485,7 +486,7 @@ 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:184
+#: 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
@@ -521,6 +522,14 @@ msgstr "O xogo non permite cargar partidas dende o iniciador."
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
+msgid "Mass Add..."
+msgstr "Engadir en masa..."
+
+#: gui/launcher.cpp:1161
+msgid "Record..."
+msgstr ""
+
#: gui/massadd.cpp:79 gui/massadd.cpp:82
msgid "... progress ..."
msgstr "...progreso..."
@@ -619,7 +628,7 @@ msgid "Special dithering modes supported by some games"
msgstr "Modos de interpolaciѓn de cores compatibles con algњns xogos"
#: gui/options.cpp:760
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2249
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2298
msgid "Fullscreen mode"
msgstr "Pantalla completa"
@@ -937,6 +946,43 @@ msgstr ""
"O tema seleccionado non щ compatible co idioma actual. Para empregar o tema, "
"deberсs cambiar antes o idioma da interfaz."
+#: gui/recorderdialog.cpp:64
+msgid "Recorder or Playback Gameplay"
+msgstr ""
+
+#: gui/recorderdialog.cpp:69 gui/recorderdialog.cpp:156
+#: gui/saveload-dialog.cpp:220 gui/saveload-dialog.cpp:276
+msgid "Delete"
+msgstr "Eliminar"
+
+#: gui/recorderdialog.cpp:71
+msgid "Record"
+msgstr ""
+
+#: gui/recorderdialog.cpp:72
+#, fuzzy
+msgid "Playback"
+msgstr "Xogar"
+
+#: gui/recorderdialog.cpp:74
+msgid "Edit"
+msgstr ""
+
+#: gui/recorderdialog.cpp:86 gui/recorderdialog.cpp:243
+#: gui/recorderdialog.cpp:253
+msgid "Author: "
+msgstr ""
+
+#: gui/recorderdialog.cpp:87 gui/recorderdialog.cpp:244
+#: gui/recorderdialog.cpp:254
+msgid "Notes: "
+msgstr ""
+
+#: gui/recorderdialog.cpp:155
+#, fuzzy
+msgid "Do you really want to delete this record?"
+msgstr "Seguro que queres eliminar esta partida?"
+
#: gui/saveload-dialog.cpp:167
msgid "List view"
msgstr "Lista"
@@ -957,23 +1003,19 @@ msgstr "Non hai hora gardada"
msgid "No playtime saved"
msgstr "Non hai tempo de xogo gardado"
-#: gui/saveload-dialog.cpp:220 gui/saveload-dialog.cpp:276
-msgid "Delete"
-msgstr "Eliminar"
-
#: gui/saveload-dialog.cpp:275
msgid "Do you really want to delete this saved game?"
msgstr "Seguro que queres eliminar esta partida?"
-#: gui/saveload-dialog.cpp:385 gui/saveload-dialog.cpp:875
+#: gui/saveload-dialog.cpp:385 gui/saveload-dialog.cpp:884
msgid "Date: "
msgstr "Data:"
-#: gui/saveload-dialog.cpp:389 gui/saveload-dialog.cpp:881
+#: gui/saveload-dialog.cpp:389 gui/saveload-dialog.cpp:890
msgid "Time: "
msgstr "Hora:"
-#: gui/saveload-dialog.cpp:395 gui/saveload-dialog.cpp:889
+#: gui/saveload-dialog.cpp:395 gui/saveload-dialog.cpp:898
msgid "Playtime: "
msgstr "Tempo de xogo:"
@@ -989,19 +1031,19 @@ msgstr "Seg."
msgid "Prev"
msgstr "Ant."
-#: gui/saveload-dialog.cpp:739
+#: gui/saveload-dialog.cpp:748
msgid "New Save"
msgstr "Novo ficheiro"
-#: gui/saveload-dialog.cpp:739
+#: gui/saveload-dialog.cpp:748
msgid "Create a new save game"
msgstr "Crea un novo ficheiro de gardado"
-#: gui/saveload-dialog.cpp:868
+#: gui/saveload-dialog.cpp:877
msgid "Name: "
msgstr "Nome:"
-#: gui/saveload-dialog.cpp:940
+#: gui/saveload-dialog.cpp:949
#, c-format
msgid "Enter a description for slot %d:"
msgstr "Introduce unha descriciѓn para o espazo %d:"
@@ -1155,7 +1197,7 @@ msgstr "Omitir liёa"
msgid "Error running game:"
msgstr "Erro de execuciѓn do xogo:"
-#: base/main.cpp:536
+#: base/main.cpp:554
msgid "Could not find any engine capable of running the selected game"
msgstr "Non se puido atopar un motor para executar o xogo seleccionado"
@@ -1272,7 +1314,7 @@ 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:758
+#: engines/pegasus/pegasus.cpp:377 engines/sci/engine/kfile.cpp:759
#: engines/toltecs/menu.cpp:281 engines/tsage/scenes.cpp:598
msgid "Save game:"
msgstr "Gardar partida:"
@@ -1285,7 +1327,7 @@ msgstr "Gardar partida:"
#: 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:758 engines/scumm/dialogs.cpp:188
+#: engines/sci/engine/kfile.cpp:759 engines/scumm/dialogs.cpp:188
#: engines/toltecs/menu.cpp:281 engines/tsage/scenes.cpp:598
msgid "Save"
msgstr "Gardar"
@@ -1323,23 +1365,23 @@ msgstr "~C~ancelar"
msgid "~K~eys"
msgstr "~T~eclas"
-#: engines/engine.cpp:245
+#: engines/engine.cpp:276
msgid "Could not initialize color format."
msgstr "Non se puido iniciar o formato de cor."
-#: engines/engine.cpp:253
+#: engines/engine.cpp:284
msgid "Could not switch to video mode: '"
msgstr "Non se puido cambiar ao modo de vэdeo: '"
-#: engines/engine.cpp:262
+#: engines/engine.cpp:293
msgid "Could not apply aspect ratio setting."
msgstr "Non se puido aplicar a configuraciѓn de proporciѓn."
-#: engines/engine.cpp:267
+#: engines/engine.cpp:298
msgid "Could not apply fullscreen setting."
msgstr "Non se puido aplicar a configuraciѓn de pantalla completa."
-#: engines/engine.cpp:367
+#: engines/engine.cpp:398
msgid ""
"You appear to be playing this game directly\n"
"from the CD. This is known to cause problems,\n"
@@ -1353,7 +1395,7 @@ msgstr ""
"os ficheiros de datos ao disco duro. Consulta\n"
"o ficheiro README para obter mсis informaciѓn."
-#: engines/engine.cpp:378
+#: engines/engine.cpp:409
msgid ""
"This game has audio tracks in its disk. These\n"
"tracks need to be ripped from the disk using\n"
@@ -1367,7 +1409,7 @@ msgstr ""
"do xogo. Consulta o ficheiro README\n"
"para obter mсis informaciѓn."
-#: engines/engine.cpp:436
+#: engines/engine.cpp:467
#, c-format
msgid ""
"Gamestate load failed (%s)! Please consult the README for basic information, "
@@ -1376,7 +1418,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:449
+#: engines/engine.cpp:480
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 "
@@ -1386,7 +1428,7 @@ msgstr ""
"Por iso, talvez sexa inestable e os ficheiros de gardado talvez non "
"funcionen en futuras versiѓns de ScummVM."
-#: engines/engine.cpp:452
+#: engines/engine.cpp:483
msgid "Start anyway"
msgstr "Iniciar de todos os xeitos"
@@ -1596,11 +1638,11 @@ msgstr "Modo panel tсctil activado."
msgid "Touchpad mode disabled."
msgstr "Modo panel tсctil desactivado."
-#: backends/platform/maemo/maemo.cpp:209
+#: backends/platform/maemo/maemo.cpp:208
msgid "Click Mode"
msgstr "Modo rato"
-#: backends/platform/maemo/maemo.cpp:215
+#: backends/platform/maemo/maemo.cpp:214
#: backends/platform/symbian/src/SymbianActions.cpp:42
#: backends/platform/wince/CEActionsPocket.cpp:60
#: backends/platform/wince/CEActionsSmartphone.cpp:43
@@ -1608,11 +1650,11 @@ msgstr "Modo rato"
msgid "Left Click"
msgstr "Botѓn primario"
-#: backends/platform/maemo/maemo.cpp:218
+#: backends/platform/maemo/maemo.cpp:217
msgid "Middle Click"
msgstr "Botѓn central"
-#: backends/platform/maemo/maemo.cpp:221
+#: 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
@@ -1649,19 +1691,19 @@ msgctxt "lowres"
msgid "Normal (no scaling)"
msgstr "Normal (sen escala)"
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2148
+#: 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:2154
+#: 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:2209
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2258
msgid "Active graphics filter:"
msgstr "Filtro de grсficos activo:"
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2251
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2300
msgid "Windowed mode"
msgstr "Modo en ventс"
@@ -1720,8 +1762,8 @@ msgstr "Modo rсpido"
#: 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:82
-#: engines/scumm/help.cpp:84
+#: engines/scumm/dialogs.cpp:192 engines/scumm/help.cpp:83
+#: engines/scumm/help.cpp:85
msgid "Quit"
msgstr "Saэr"
@@ -1741,7 +1783,7 @@ msgstr "Teclado virtual"
msgid "Key mapper"
msgstr "Asignador de teclas"
-#: backends/events/symbiansdl/symbiansdl-events.cpp:184
+#: backends/events/symbiansdl/symbiansdl-events.cpp:186
msgid "Do you want to quit ?"
msgstr "Queres saэr?"
@@ -2076,34 +2118,55 @@ msgstr "Premer activado"
msgid "Clicking Disabled"
msgstr "Premer desactivado"
-#: engines/agi/detection.cpp:142 engines/drascula/detection.cpp:302
+#: 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.cpp:103
+#: engines/zvision/detection.cpp:246
msgid "Use original save/load screens"
msgstr "Empregar pantallas orixinais de gardado e carga"
-#: engines/agi/detection.cpp:143 engines/drascula/detection.cpp:303
+#: 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/zvision/detection.cpp:104
+#: engines/zvision/detection.cpp:247
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)"
+
+#: engines/agi/detection.cpp:158
+msgid ""
+"Use an alternative palette, common for all Amiga games. This was the old "
+"behavior"
+msgstr ""
+
+#: engines/agi/detection.cpp:167
+#, fuzzy
+msgid "Mouse support"
+msgstr "Omisiѓns"
+
+#: 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:857 engines/toltecs/menu.cpp:256
+#: engines/sci/engine/kfile.cpp:858 engines/toltecs/menu.cpp:256
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:857 engines/toltecs/menu.cpp:256
+#: engines/sci/engine/kfile.cpp:858 engines/toltecs/menu.cpp:256
msgid "Restore"
msgstr "Restaurar"
-#: engines/agos/saveload.cpp:160 engines/scumm/scumm.cpp:2368
+#: engines/agos/saveload.cpp:160 engines/scumm/scumm.cpp:2377
#, c-format
msgid ""
"Failed to load game state from file:\n"
@@ -2114,7 +2177,7 @@ msgstr ""
"\n"
"%s"
-#: engines/agos/saveload.cpp:195 engines/scumm/scumm.cpp:2361
+#: engines/agos/saveload.cpp:195 engines/scumm/scumm.cpp:2370
#, c-format
msgid ""
"Failed to save game state to file:\n"
@@ -2125,7 +2188,7 @@ msgstr ""
"\n"
"%s"
-#: engines/agos/saveload.cpp:203 engines/scumm/scumm.cpp:2379
+#: engines/agos/saveload.cpp:203 engines/scumm/scumm.cpp:2388
#, c-format
msgid ""
"Successfully saved game state in file:\n"
@@ -2141,12 +2204,12 @@ msgstr ""
msgid "Cutscene file '%s' not found!"
msgstr "Non se atopou o ficheiro de secuencia %s!"
-#: engines/cge/detection.cpp:105 engines/cge2/detection.cpp:81
+#: engines/cge/detection.cpp:105 engines/cge2/detection.cpp:101
#, fuzzy
msgid "Color Blind Mode"
msgstr "Modo rato"
-#: engines/cge/detection.cpp:106 engines/cge2/detection.cpp:82
+#: engines/cge/detection.cpp:106 engines/cge2/detection.cpp:102
msgid "Enable Color Blind Mode by default"
msgstr ""
@@ -2198,7 +2261,7 @@ msgstr "Velocidade de vэdeo rсpida"
msgid "Play movies at an increased speed"
msgstr "Reproducir vэdeos a mсis velocidade"
-#: engines/groovie/script.cpp:399
+#: engines/groovie/script.cpp:408
msgid "Failed to save game"
msgstr "Erro ao gardar a partida"
@@ -2496,12 +2559,12 @@ msgid "Use an alternative game intro (CD version only)"
msgstr "Empregar unha introduciѓn alternativa para o xogo (sѓ versiѓn en CD)"
#: engines/sci/detection.cpp:374
-msgid "EGA undithering"
-msgstr "Non interpolaciѓn EGA"
+msgid "Skip EGA dithering pass (full color backgrounds)"
+msgstr ""
#: engines/sci/detection.cpp:375
-msgid "Enable undithering in EGA games"
-msgstr "Activar a non interpolaciѓn nos xogos en EGA"
+msgid "Skip dithering pass in EGA games, graphics are shown with full colors"
+msgstr ""
#: engines/sci/detection.cpp:384
msgid "Prefer digital sound effects"
@@ -2576,12 +2639,14 @@ msgstr "Xogo en pausa. Pulsa a barra espazadora para continuar."
#. "Moechten Sie wirklich neu starten? (J/N)J"
#. Will react to J as 'Yes'
#: engines/scumm/dialogs.cpp:183
-msgid "Are you sure you want to restart? (Y/N)"
+#, fuzzy
+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
-msgid "Are you sure you want to quit? (Y/N)"
+#, fuzzy
+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
@@ -2669,516 +2734,541 @@ msgstr "Prсctica"
msgid "Expert"
msgstr "Experto"
-#: engines/scumm/help.cpp:73
+#: engines/scumm/help.cpp:74
msgid "Common keyboard commands:"
msgstr "Comandos de teclado comњns:"
-#: engines/scumm/help.cpp:74
+#: engines/scumm/help.cpp:75
msgid "Save / Load dialog"
msgstr "Gardar/cargar diсlogo"
-#: engines/scumm/help.cpp:76
+#: engines/scumm/help.cpp:77
msgid "Skip line of text"
msgstr "Omitir liёa de texto"
-#: engines/scumm/help.cpp:77
+#: engines/scumm/help.cpp:78
msgid "Esc"
msgstr "ESC"
-#: engines/scumm/help.cpp:77
+#: engines/scumm/help.cpp:78
msgid "Skip cutscene"
msgstr "Omitir secuencia"
-#: engines/scumm/help.cpp:78
+#: engines/scumm/help.cpp:79
msgid "Space"
msgstr "Barra espazadora"
-#: engines/scumm/help.cpp:78
+#: engines/scumm/help.cpp:79
msgid "Pause game"
msgstr "Pausar xogo"
-#: engines/scumm/help.cpp:79 engines/scumm/help.cpp:84
-#: engines/scumm/help.cpp:95 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: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:79
+#: engines/scumm/help.cpp:80
msgid "Load game state 1-10"
msgstr "Cargar partida 1-10"
-#: engines/scumm/help.cpp:80 engines/scumm/help.cpp:84
-#: engines/scumm/help.cpp:86 engines/scumm/help.cpp:100
-#: engines/scumm/help.cpp:101 engines/scumm/help.cpp:102
+#: 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:80
+#: engines/scumm/help.cpp:81
msgid "Save game state 1-10"
msgstr "Gardar partida 1-10"
-#: engines/scumm/help.cpp:86 engines/scumm/help.cpp:89
+#: engines/scumm/help.cpp:87 engines/scumm/help.cpp:90
msgid "Enter"
msgstr "INTRO"
-#: engines/scumm/help.cpp:87
+#: engines/scumm/help.cpp:88
msgid "Music volume up / down"
msgstr "Subir/baixar volume de mњsica"
-#: engines/scumm/help.cpp:88
+#: engines/scumm/help.cpp:89
msgid "Text speed slower / faster"
msgstr "Acelerar/frear texto"
-#: engines/scumm/help.cpp:89
+#: engines/scumm/help.cpp:90
msgid "Simulate left mouse button"
msgstr "Simular botѓn primario do rato"
-#: engines/scumm/help.cpp:90
+#: engines/scumm/help.cpp:91
msgid "Tab"
msgstr "TAB"
-#: engines/scumm/help.cpp:90
+#: engines/scumm/help.cpp:91
msgid "Simulate right mouse button"
msgstr "Simular botѓn secundario do rato"
-#: engines/scumm/help.cpp:93
+#: engines/scumm/help.cpp:94
msgid "Special keyboard commands:"
msgstr "Comandos de teclado especiais:"
-#: engines/scumm/help.cpp:94
+#: engines/scumm/help.cpp:95
msgid "Show / Hide console"
msgstr "Mostrar/ocultar consola"
-#: engines/scumm/help.cpp:95
+#: engines/scumm/help.cpp:96
msgid "Start the debugger"
msgstr "Iniciar o depurador"
-#: engines/scumm/help.cpp:96
+#: engines/scumm/help.cpp:97
msgid "Show memory consumption"
msgstr "Mostrar consumo de memoria"
-#: engines/scumm/help.cpp:97
+#: engines/scumm/help.cpp:98
msgid "Run in fast mode (*)"
msgstr "Executar en modo rсpido (*)"
-#: engines/scumm/help.cpp:98
+#: engines/scumm/help.cpp:99
msgid "Run in really fast mode (*)"
msgstr "Executar en modo moi rсpido (*)"
-#: engines/scumm/help.cpp:99
+#: engines/scumm/help.cpp:100
msgid "Toggle mouse capture"
msgstr "Activar/desactivar captura de rato"
-#: engines/scumm/help.cpp:100
+#: engines/scumm/help.cpp:101
msgid "Switch between graphics filters"
msgstr "Cambiar filtro de grсficos"
-#: engines/scumm/help.cpp:101
+#: engines/scumm/help.cpp:102
msgid "Increase / Decrease scale factor"
msgstr "Aumentar/reducir factor de escala"
-#: engines/scumm/help.cpp:102
+#: engines/scumm/help.cpp:103
msgid "Toggle aspect-ratio correction"
msgstr "Activar/desactivar correcciѓn de proporciѓn"
-#: engines/scumm/help.cpp:107
+#: engines/scumm/help.cpp:108
msgid "* Note that using ctrl-f and"
msgstr "* Nota: non recomendamos"
-#: engines/scumm/help.cpp:108
+#: engines/scumm/help.cpp:109
msgid " ctrl-g are not recommended"
msgstr " empregar CTRL-F nin CTRL-G,"
-#: engines/scumm/help.cpp:109
+#: engines/scumm/help.cpp:110
msgid " since they may cause crashes"
msgstr " xa que poden provocar bloqueos"
-#: engines/scumm/help.cpp:110
+#: engines/scumm/help.cpp:111
msgid " or incorrect game behavior."
msgstr " ou outros erros no xogo."
-#: engines/scumm/help.cpp:114
+#: engines/scumm/help.cpp:115
msgid "Spinning drafts on the keyboard:"
msgstr "Tecer feitizos co teclado:"
-#: engines/scumm/help.cpp:116
+#: engines/scumm/help.cpp:117
msgid "Main game controls:"
msgstr "Controis principais de xogo:"
-#: engines/scumm/help.cpp:121 engines/scumm/help.cpp:136
-#: engines/scumm/help.cpp:161
+#: engines/scumm/help.cpp:122 engines/scumm/help.cpp:137
+#: engines/scumm/help.cpp:162
msgid "Push"
msgstr "Empuxar"
-#: engines/scumm/help.cpp:122 engines/scumm/help.cpp:137
-#: engines/scumm/help.cpp:162
+#: engines/scumm/help.cpp:123 engines/scumm/help.cpp:138
+#: engines/scumm/help.cpp:163
msgid "Pull"
msgstr "Tirar de"
-#: engines/scumm/help.cpp:123 engines/scumm/help.cpp:138
-#: engines/scumm/help.cpp:163 engines/scumm/help.cpp:197
-#: engines/scumm/help.cpp:207
+#: 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 "Dar"
-#: engines/scumm/help.cpp:124 engines/scumm/help.cpp:139
-#: engines/scumm/help.cpp:164 engines/scumm/help.cpp:190
-#: engines/scumm/help.cpp:208
+#: 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 "Abrir"
-#: engines/scumm/help.cpp:126
+#: engines/scumm/help.cpp:127
msgid "Go to"
msgstr "Ir a"
-#: engines/scumm/help.cpp:127
+#: engines/scumm/help.cpp:128
msgid "Get"
msgstr "Coller"
-#: engines/scumm/help.cpp:128 engines/scumm/help.cpp:152
-#: engines/scumm/help.cpp:170 engines/scumm/help.cpp:198
-#: engines/scumm/help.cpp:213 engines/scumm/help.cpp:224
-#: engines/scumm/help.cpp:250
+#: 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 "Usar"
-#: engines/scumm/help.cpp:129 engines/scumm/help.cpp:141
+#: engines/scumm/help.cpp:130 engines/scumm/help.cpp:142
msgid "Read"
msgstr "Ler"
-#: engines/scumm/help.cpp:130 engines/scumm/help.cpp:147
+#: engines/scumm/help.cpp:131 engines/scumm/help.cpp:148
msgid "New kid"
msgstr "Rapaz"
-#: engines/scumm/help.cpp:131 engines/scumm/help.cpp:153
-#: engines/scumm/help.cpp:171
+#: engines/scumm/help.cpp:132 engines/scumm/help.cpp:154
+#: engines/scumm/help.cpp:172
msgid "Turn on"
msgstr "Acender"
-#: engines/scumm/help.cpp:132 engines/scumm/help.cpp:154
-#: engines/scumm/help.cpp:172
+#: engines/scumm/help.cpp:133 engines/scumm/help.cpp:155
+#: engines/scumm/help.cpp:173
msgid "Turn off"
msgstr "Apagar"
-#: engines/scumm/help.cpp:142 engines/scumm/help.cpp:167
-#: engines/scumm/help.cpp:194
+#: engines/scumm/help.cpp:143 engines/scumm/help.cpp:168
+#: engines/scumm/help.cpp:195
msgid "Walk to"
msgstr "Ir a"
-#: engines/scumm/help.cpp:143 engines/scumm/help.cpp:168
-#: engines/scumm/help.cpp:195 engines/scumm/help.cpp:210
-#: engines/scumm/help.cpp:227
+#: 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 "Coller"
-#: engines/scumm/help.cpp:144 engines/scumm/help.cpp:169
+#: engines/scumm/help.cpp:145 engines/scumm/help.cpp:170
msgid "What is"
msgstr "Que щ"
-#: engines/scumm/help.cpp:146
+#: engines/scumm/help.cpp:147
msgid "Unlock"
msgstr "Despechar"
-#: engines/scumm/help.cpp:149
+#: engines/scumm/help.cpp:150
msgid "Put on"
msgstr "Poёer"
-#: engines/scumm/help.cpp:150
+#: engines/scumm/help.cpp:151
msgid "Take off"
msgstr "Quitar"
-#: engines/scumm/help.cpp:156
+#: engines/scumm/help.cpp:157
msgid "Fix"
msgstr "Reparar"
-#: engines/scumm/help.cpp:158
+#: engines/scumm/help.cpp:159
msgid "Switch"
msgstr "Cambiar"
-#: engines/scumm/help.cpp:166 engines/scumm/help.cpp:228
+#: engines/scumm/help.cpp:167 engines/scumm/help.cpp:229
msgid "Look"
msgstr "Mirar"
-#: engines/scumm/help.cpp:173 engines/scumm/help.cpp:223
+#: engines/scumm/help.cpp:174 engines/scumm/help.cpp:224
msgid "Talk"
msgstr "Falar"
-#: engines/scumm/help.cpp:174
+#: engines/scumm/help.cpp:175
msgid "Travel"
msgstr "Viaxar"
-#: engines/scumm/help.cpp:175
+#: engines/scumm/help.cpp:176
msgid "To Henry / To Indy"
msgstr "A Henry / A Indy"
#. I18N: These are different musical notes
-#: engines/scumm/help.cpp:179
+#: engines/scumm/help.cpp:180
msgid "play C minor on distaff"
msgstr "tocar do menor no bastѓn"
-#: engines/scumm/help.cpp:180
+#: engines/scumm/help.cpp:181
msgid "play D on distaff"
msgstr "tocar re no bastѓn"
-#: engines/scumm/help.cpp:181
+#: engines/scumm/help.cpp:182
msgid "play E on distaff"
msgstr "tocar mi no bastѓn"
-#: engines/scumm/help.cpp:182
+#: engines/scumm/help.cpp:183
msgid "play F on distaff"
msgstr "tocar fa no bastѓn"
-#: engines/scumm/help.cpp:183
+#: engines/scumm/help.cpp:184
msgid "play G on distaff"
msgstr "tocar sol no bastѓn"
-#: engines/scumm/help.cpp:184
+#: engines/scumm/help.cpp:185
msgid "play A on distaff"
msgstr "tocar la no bastѓn"
-#: engines/scumm/help.cpp:185
+#: engines/scumm/help.cpp:186
msgid "play B on distaff"
msgstr "tocar si no bastѓn"
-#: engines/scumm/help.cpp:186
+#: engines/scumm/help.cpp:187
msgid "play C major on distaff"
msgstr "tocar do maior no bastѓn"
-#: engines/scumm/help.cpp:192 engines/scumm/help.cpp:214
+#: engines/scumm/help.cpp:193 engines/scumm/help.cpp:215
msgid "puSh"
msgstr "Empurrar"
-#: engines/scumm/help.cpp:193 engines/scumm/help.cpp:215
+#: engines/scumm/help.cpp:194 engines/scumm/help.cpp:216
msgid "pull (Yank)"
msgstr "Tirar de"
-#: engines/scumm/help.cpp:196 engines/scumm/help.cpp:212
-#: engines/scumm/help.cpp:248
+#: engines/scumm/help.cpp:197 engines/scumm/help.cpp:213
+#: engines/scumm/help.cpp:249
msgid "Talk to"
msgstr "Falar con"
-#: engines/scumm/help.cpp:199 engines/scumm/help.cpp:211
+#: engines/scumm/help.cpp:200 engines/scumm/help.cpp:212
msgid "Look at"
msgstr "Mirar"
-#: engines/scumm/help.cpp:200
+#: engines/scumm/help.cpp:201
msgid "turn oN"
msgstr "Acender"
-#: engines/scumm/help.cpp:201
+#: engines/scumm/help.cpp:202
msgid "turn oFf"
msgstr "Apagar"
-#: engines/scumm/help.cpp:217
+#: engines/scumm/help.cpp:218
msgid "KeyUp"
msgstr "Arriba"
-#: engines/scumm/help.cpp:217
+#: engines/scumm/help.cpp:218
msgid "Highlight prev dialogue"
msgstr "Destacar diсlogo anterior"
-#: engines/scumm/help.cpp:218
+#: engines/scumm/help.cpp:219
msgid "KeyDown"
msgstr "Abaixo"
-#: engines/scumm/help.cpp:218
+#: engines/scumm/help.cpp:219
msgid "Highlight next dialogue"
msgstr "Destacar diсlogo seguinte"
-#: engines/scumm/help.cpp:222
+#: engines/scumm/help.cpp:223
msgid "Walk"
msgstr "Ir a"
-#: engines/scumm/help.cpp:225 engines/scumm/help.cpp:234
-#: engines/scumm/help.cpp:241 engines/scumm/help.cpp:249
+#: engines/scumm/help.cpp:226 engines/scumm/help.cpp:235
+#: engines/scumm/help.cpp:242 engines/scumm/help.cpp:250
msgid "Inventory"
msgstr "Inventario"
-#: engines/scumm/help.cpp:226
+#: engines/scumm/help.cpp:227
msgid "Object"
msgstr "Obxecto"
-#: engines/scumm/help.cpp:229
+#: engines/scumm/help.cpp:230
msgid "Black and White / Color"
msgstr "Branco e negro/cor"
-#: engines/scumm/help.cpp:232
+#: engines/scumm/help.cpp:233
msgid "Eyes"
msgstr "Ollos"
-#: engines/scumm/help.cpp:233
+#: engines/scumm/help.cpp:234
msgid "Tongue"
msgstr "Lingua"
-#: engines/scumm/help.cpp:235
+#: engines/scumm/help.cpp:236
msgid "Punch"
msgstr "Bater a"
-#: engines/scumm/help.cpp:236
+#: engines/scumm/help.cpp:237
msgid "Kick"
msgstr "Patear a"
-#: engines/scumm/help.cpp:239 engines/scumm/help.cpp:247
+#: engines/scumm/help.cpp:240 engines/scumm/help.cpp:248
msgid "Examine"
msgstr "Examinar"
-#: engines/scumm/help.cpp:240
+#: engines/scumm/help.cpp:241
msgid "Regular cursor"
msgstr "Cursor normal"
#. I18N: Comm is a communication device
-#: engines/scumm/help.cpp:243
+#: engines/scumm/help.cpp:244
msgid "Comm"
msgstr "Comunicador"
-#: engines/scumm/help.cpp:246
+#: engines/scumm/help.cpp:247
msgid "Save / Load / Options"
msgstr "Gardar/cargar/opciѓns"
-#: engines/scumm/help.cpp:255
+#: engines/scumm/help.cpp:256
msgid "Other game controls:"
msgstr "Outros controis de xogo:"
-#: engines/scumm/help.cpp:257 engines/scumm/help.cpp:267
+#: engines/scumm/help.cpp:258 engines/scumm/help.cpp:268
msgid "Inventory:"
msgstr "Inventario:"
-#: engines/scumm/help.cpp:258 engines/scumm/help.cpp:274
+#: engines/scumm/help.cpp:259 engines/scumm/help.cpp:275
msgid "Scroll list up"
msgstr "Subir lista"
-#: engines/scumm/help.cpp:259 engines/scumm/help.cpp:275
+#: engines/scumm/help.cpp:260 engines/scumm/help.cpp:276
msgid "Scroll list down"
msgstr "Baixar lista"
-#: engines/scumm/help.cpp:260 engines/scumm/help.cpp:268
+#: engines/scumm/help.cpp:261 engines/scumm/help.cpp:269
msgid "Upper left item"
msgstr "Obxecto esquerdo arriba"
-#: engines/scumm/help.cpp:261 engines/scumm/help.cpp:270
+#: engines/scumm/help.cpp:262 engines/scumm/help.cpp:271
msgid "Lower left item"
msgstr "Obxecto esquerdo abaixo"
-#: engines/scumm/help.cpp:262 engines/scumm/help.cpp:271
+#: engines/scumm/help.cpp:263 engines/scumm/help.cpp:272
msgid "Upper right item"
msgstr "Obxecto dereito arriba"
-#: engines/scumm/help.cpp:263 engines/scumm/help.cpp:273
+#: engines/scumm/help.cpp:264 engines/scumm/help.cpp:274
msgid "Lower right item"
msgstr "Obxecto dereito abaixo"
-#: engines/scumm/help.cpp:269
+#: engines/scumm/help.cpp:270
msgid "Middle left item"
msgstr "Obxecto esquerdo medio"
-#: engines/scumm/help.cpp:272
+#: engines/scumm/help.cpp:273
msgid "Middle right item"
msgstr "Obxecto dereito medio"
-#: engines/scumm/help.cpp:279 engines/scumm/help.cpp:284
+#: engines/scumm/help.cpp:280 engines/scumm/help.cpp:285
msgid "Switching characters:"
msgstr "Cambiar caracteres:"
-#: engines/scumm/help.cpp:281
+#: engines/scumm/help.cpp:282
msgid "Second kid"
msgstr "Rapaz 2"
-#: engines/scumm/help.cpp:282
+#: engines/scumm/help.cpp:283
msgid "Third kid"
msgstr "Rapaz 3"
-#: engines/scumm/help.cpp:294
+#: engines/scumm/help.cpp:292
+#, fuzzy
+msgid "Toggle Inventory/IQ Points display"
+msgstr "Activar/Desactivar pantalla de datos"
+
+#: engines/scumm/help.cpp:293
+msgid "Toggle Keyboard/Mouse Fighting (*)"
+msgstr ""
+
+#: engines/scumm/help.cpp:295
+msgid "* Keyboard Fighting is always on,"
+msgstr ""
+
+#: engines/scumm/help.cpp:296
+msgid " so despite the in-game message this"
+msgstr ""
+
+#: engines/scumm/help.cpp:297
+msgid " actually toggles Mouse Fighting Off/On"
+msgstr ""
+
+#: engines/scumm/help.cpp:304
msgid "Fighting controls (numpad):"
msgstr "Controis de combate (teclado numщrico):"
-#: engines/scumm/help.cpp:295 engines/scumm/help.cpp:296
-#: engines/scumm/help.cpp:297
+#: engines/scumm/help.cpp:305 engines/scumm/help.cpp:306
+#: engines/scumm/help.cpp:307
msgid "Step back"
msgstr "Paso atrсs"
-#: engines/scumm/help.cpp:298
+#: engines/scumm/help.cpp:308
msgid "Block high"
msgstr "Bloqueo alto"
-#: engines/scumm/help.cpp:299
+#: engines/scumm/help.cpp:309
msgid "Block middle"
msgstr "Bloqueo medio"
-#: engines/scumm/help.cpp:300
+#: engines/scumm/help.cpp:310
msgid "Block low"
msgstr "Bloqueo baixo"
-#: engines/scumm/help.cpp:301
+#: engines/scumm/help.cpp:311
msgid "Punch high"
msgstr "Puёazo alto"
-#: engines/scumm/help.cpp:302
+#: engines/scumm/help.cpp:312
msgid "Punch middle"
msgstr "Puёazo medio"
-#: engines/scumm/help.cpp:303
+#: engines/scumm/help.cpp:313
msgid "Punch low"
msgstr "Puёazo baixo"
-#: engines/scumm/help.cpp:306
+#: engines/scumm/help.cpp:315
+msgid "Sucker punch"
+msgstr ""
+
+#: engines/scumm/help.cpp:318
msgid "These are for Indy on left."
msgstr "Son para Indy na esquerda."
-#: engines/scumm/help.cpp:307
+#: engines/scumm/help.cpp:319
msgid "When Indy is on the right,"
msgstr "Se estс na dereita,"
-#: engines/scumm/help.cpp:308
+#: engines/scumm/help.cpp:320
msgid "7, 4, and 1 are switched with"
msgstr "7, 4 e 1 cсmbianse por"
-#: engines/scumm/help.cpp:309
+#: engines/scumm/help.cpp:321
msgid "9, 6, and 3, respectively."
msgstr "9, 6 e 3 respectivamente."
-#: engines/scumm/help.cpp:316
+#: engines/scumm/help.cpp:328
msgid "Biplane controls (numpad):"
msgstr "Controis de biplano (teclado numщrico):"
-#: engines/scumm/help.cpp:317
+#: engines/scumm/help.cpp:329
msgid "Fly to upper left"
msgstr "Voar с esquerda arriba"
-#: engines/scumm/help.cpp:318
+#: engines/scumm/help.cpp:330
msgid "Fly to left"
msgstr "Voar с esquerda"
-#: engines/scumm/help.cpp:319
+#: engines/scumm/help.cpp:331
msgid "Fly to lower left"
msgstr "Voar с esquerda abaixo"
-#: engines/scumm/help.cpp:320
+#: engines/scumm/help.cpp:332
msgid "Fly upwards"
msgstr "Voar arriba"
-#: engines/scumm/help.cpp:321
+#: engines/scumm/help.cpp:333
msgid "Fly straight"
msgstr "Voar recto"
-#: engines/scumm/help.cpp:322
+#: engines/scumm/help.cpp:334
msgid "Fly down"
msgstr "Voar abaixo"
-#: engines/scumm/help.cpp:323
+#: engines/scumm/help.cpp:335
msgid "Fly to upper right"
msgstr "Voar с dereita arriba"
-#: engines/scumm/help.cpp:324
+#: engines/scumm/help.cpp:336
msgid "Fly to right"
msgstr "Voar с dereita"
-#: engines/scumm/help.cpp:325
+#: engines/scumm/help.cpp:337
msgid "Fly to lower right"
msgstr "Voar с dereita abaixo"
-#: engines/scumm/scumm.cpp:1823
+#: engines/scumm/scumm.cpp:1832
#, c-format
msgid ""
"Native MIDI support requires the Roland Upgrade from LucasArts,\n"
@@ -3187,11 +3277,12 @@ msgstr ""
"A compatibilidade nativa con MIDI precisa a actualizaciѓn de Roland\n"
"de LucasArts, mais falla %s. Empregarase AdLib."
-#: engines/scumm/scumm.cpp:2594
+#: engines/scumm/scumm.cpp:2644
+#, fuzzy
msgid ""
-"Usually, Maniac Mansion would start now. But ScummVM doesn't do that yet. To "
-"play it, go to 'Add Game' in the ScummVM start menu and select the 'Maniac' "
-"directory inside the Tentacle game directory."
+"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 "
@@ -3332,6 +3423,49 @@ msgstr ""
msgid "Show the current number of frames per second in the upper left corner"
msgstr ""
+#: engines/zvision/detection.cpp:256
+msgid "Double FPS"
+msgstr ""
+
+#: engines/zvision/detection.cpp:257
+msgid "Increase game FPS from 30 to 60"
+msgstr ""
+
+#: engines/zvision/detection.cpp:266
+#, fuzzy
+msgid "Enable Venus"
+msgstr "Activar o modo helio"
+
+#: engines/zvision/detection.cpp:267
+msgid "Enable the Venus help system"
+msgstr ""
+
+#: engines/zvision/detection.cpp:276
+msgid "Disable animation while turning"
+msgstr ""
+
+#: engines/zvision/detection.cpp:277
+msgid "Disable animation while turning in panoramic mode"
+msgstr ""
+
+#: engines/zvision/detection.cpp:286
+msgid "Use the hires MPEG movies"
+msgstr ""
+
+#: engines/zvision/detection.cpp:287
+#, fuzzy
+msgid ""
+"Use the hires MPEG movies of the DVD version, instead of the lowres AVI ones"
+msgstr ""
+"Empregar o xogo de cursores prateados alternativo, no canto dos dourados "
+"normais"
+
+#~ msgid "EGA undithering"
+#~ msgstr "Non interpolaciѓn EGA"
+
+#~ msgid "Enable undithering in EGA games"
+#~ msgstr "Activar a non interpolaciѓn nos xogos en EGA"
+
#~ msgid "MPEG-2 cutscenes found but ScummVM has been built without MPEG-2"
#~ msgstr "Atopсronse secuencias MPEG-2, mais ScummVM foi compilado sen MPEG-2"
@@ -3339,9 +3473,6 @@ msgstr ""
#~ msgid "Mass Add..."
#~ msgstr "Engadir en masa..."
-#~ msgid "Mass Add..."
-#~ msgstr "Engadir en masa..."
-
#~ msgid ""
#~ "Turns off General MIDI mapping for games with Roland MT-32 soundtrack"
#~ msgstr "Desactiva o General MIDI para os xogos con mњsica en Roland MT-32"
diff --git a/po/hu_HU.po b/po/hu_HU.po
index 614fe401fc..2121b0a100 100644
--- a/po/hu_HU.po
+++ b/po/hu_HU.po
@@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: ScummVM 1.3.0svn\n"
"Report-Msgid-Bugs-To: scummvm-devel@lists.sf.net\n"
-"POT-Creation-Date: 2014-10-04 00:58+0100\n"
+"POT-Creation-Date: 2015-06-30 20:57+0100\n"
"PO-Revision-Date: 2014-02-18 06:30+0100\n"
"Last-Translator: George Kormendi <grubycza@hotmail.com>\n"
"Language-Team: Hungarian\n"
@@ -55,10 +55,11 @@ msgstr "Feljebb"
#: gui/browser.cpp:75 gui/chooser.cpp:46 gui/KeysDialog.cpp:43
#: gui/launcher.cpp:351 gui/massadd.cpp:95 gui/options.cpp:1239
+#: gui/recorderdialog.cpp:70 gui/recorderdialog.cpp:156
#: gui/saveload-dialog.cpp:216 gui/saveload-dialog.cpp:276
-#: gui/saveload-dialog.cpp:547 gui/saveload-dialog.cpp:922
+#: gui/saveload-dialog.cpp:547 gui/saveload-dialog.cpp:931
#: gui/themebrowser.cpp:55 gui/fluidsynth-dialog.cpp:152
-#: engines/engine.cpp:452 backends/platform/wii/options.cpp:48
+#: engines/engine.cpp:483 backends/platform/wii/options.cpp:48
#: backends/events/default/default-events.cpp:196
#: backends/events/default/default-events.cpp:218
#: engines/drascula/saveload.cpp:49 engines/parallaction/saveload.cpp:274
@@ -71,9 +72,9 @@ msgid "Choose"
msgstr "Vсlaszt"
#: gui/gui-manager.cpp:117 backends/keymapper/remap-dialog.cpp:53
-#: 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
+#: 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"
@@ -89,7 +90,7 @@ msgstr "Billentyћzet beсllэtсsok"
msgid "Remap keys"
msgstr "Billentyћk сtсllэtсsa"
-#: gui/gui-manager.cpp:131 base/main.cpp:326 engines/scumm/help.cpp:86
+#: gui/gui-manager.cpp:131 base/main.cpp:326 engines/scumm/help.cpp:87
msgid "Toggle fullscreen"
msgstr "Teljeskщpernyѕ kapcsolѓ"
@@ -103,13 +104,13 @@ 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:1240
-#: gui/saveload-dialog.cpp:923 gui/fluidsynth-dialog.cpp:153
-#: engines/engine.cpp:371 engines/engine.cpp:382
+#: 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:399 engines/parallaction/saveload.cpp:274
-#: engines/scumm/dialogs.cpp:193 engines/scumm/scumm.cpp:1825
+#: 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
@@ -477,7 +478,7 @@ msgstr ""
#: gui/launcher.cpp:793 gui/launcher.cpp:941 gui/launcher.cpp:1000
#: gui/fluidsynth-dialog.cpp:217
-#: backends/events/symbiansdl/symbiansdl-events.cpp:184
+#: 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
@@ -487,7 +488,7 @@ 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:184
+#: 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
@@ -524,6 +525,14 @@ 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
+msgid "Mass Add..."
+msgstr "Masszэv mѓd..."
+
+#: gui/launcher.cpp:1161
+msgid "Record..."
+msgstr ""
+
#: gui/massadd.cpp:79 gui/massadd.cpp:82
msgid "... progress ..."
msgstr "... folyamatban ..."
@@ -622,7 +631,7 @@ 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:760
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2249
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2298
msgid "Fullscreen mode"
msgstr "Teljeskщpernyѕs mѓd:"
@@ -936,6 +945,43 @@ msgstr ""
"A kivсlasztott tщma nem tсmogatja a nyelvedet. Ha hasznсlni akarod ezt a "
"tщmсt, elѕszѕr vсlts сt egy mсsik nyelvre."
+#: gui/recorderdialog.cpp:64
+msgid "Recorder or Playback Gameplay"
+msgstr ""
+
+#: gui/recorderdialog.cpp:69 gui/recorderdialog.cpp:156
+#: gui/saveload-dialog.cpp:220 gui/saveload-dialog.cpp:276
+msgid "Delete"
+msgstr "Tіrіl"
+
+#: gui/recorderdialog.cpp:71
+msgid "Record"
+msgstr ""
+
+#: gui/recorderdialog.cpp:72
+#, fuzzy
+msgid "Playback"
+msgstr "Jсtщk"
+
+#: gui/recorderdialog.cpp:74
+msgid "Edit"
+msgstr ""
+
+#: gui/recorderdialog.cpp:86 gui/recorderdialog.cpp:243
+#: gui/recorderdialog.cpp:253
+msgid "Author: "
+msgstr ""
+
+#: gui/recorderdialog.cpp:87 gui/recorderdialog.cpp:244
+#: gui/recorderdialog.cpp:254
+msgid "Notes: "
+msgstr ""
+
+#: gui/recorderdialog.cpp:155
+#, fuzzy
+msgid "Do you really want to delete this record?"
+msgstr "Biztos hogy tіrіlni akarod ezt a jсtщkсllсst?"
+
#: gui/saveload-dialog.cpp:167
msgid "List view"
msgstr "Lista nщzet"
@@ -956,23 +1002,19 @@ msgstr "Idѕ nincs mentve"
msgid "No playtime saved"
msgstr "Jсtщkidѕ nincs mentve"
-#: gui/saveload-dialog.cpp:220 gui/saveload-dialog.cpp:276
-msgid "Delete"
-msgstr "Tіrіl"
-
#: gui/saveload-dialog.cpp:275
msgid "Do you really want to delete this saved game?"
msgstr "Biztos hogy tіrіlni akarod ezt a jсtщkсllсst?"
-#: gui/saveload-dialog.cpp:385 gui/saveload-dialog.cpp:875
+#: gui/saveload-dialog.cpp:385 gui/saveload-dialog.cpp:884
msgid "Date: "
msgstr "Dсtum:"
-#: gui/saveload-dialog.cpp:389 gui/saveload-dialog.cpp:881
+#: gui/saveload-dialog.cpp:389 gui/saveload-dialog.cpp:890
msgid "Time: "
msgstr "Idѕ:"
-#: gui/saveload-dialog.cpp:395 gui/saveload-dialog.cpp:889
+#: gui/saveload-dialog.cpp:395 gui/saveload-dialog.cpp:898
msgid "Playtime: "
msgstr "Jсtщkidѕ:"
@@ -988,19 +1030,19 @@ msgstr "Kіvetkezѕ"
msgid "Prev"
msgstr "Elѕzѕ"
-#: gui/saveload-dialog.cpp:739
+#: gui/saveload-dialog.cpp:748
msgid "New Save"
msgstr "кj Mentщs"
-#: gui/saveload-dialog.cpp:739
+#: gui/saveload-dialog.cpp:748
msgid "Create a new save game"
msgstr "кj jсtщkmentщs kщszэtщse"
-#: gui/saveload-dialog.cpp:868
+#: gui/saveload-dialog.cpp:877
msgid "Name: "
msgstr "Nщv:"
-#: gui/saveload-dialog.cpp:940
+#: gui/saveload-dialog.cpp:949
#, c-format
msgid "Enter a description for slot %d:"
msgstr "Adj meg egy leэrсst a %d slothoz:"
@@ -1152,7 +1194,7 @@ msgstr "Sor сtlщpщse"
msgid "Error running game:"
msgstr "Hiba a jсtщk futtatсsakor:"
-#: base/main.cpp:536
+#: base/main.cpp:554
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"
@@ -1269,7 +1311,7 @@ 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:758
+#: engines/pegasus/pegasus.cpp:377 engines/sci/engine/kfile.cpp:759
#: engines/toltecs/menu.cpp:281 engines/tsage/scenes.cpp:598
msgid "Save game:"
msgstr "Jсtщk mentщse:"
@@ -1282,7 +1324,7 @@ msgstr "Jсtщk mentщse:"
#: 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:758 engines/scumm/dialogs.cpp:188
+#: engines/sci/engine/kfile.cpp:759 engines/scumm/dialogs.cpp:188
#: engines/toltecs/menu.cpp:281 engines/tsage/scenes.cpp:598
msgid "Save"
msgstr "Mentщs"
@@ -1319,23 +1361,23 @@ msgstr "Mщgse"
msgid "~K~eys"
msgstr "Billentyќk"
-#: engines/engine.cpp:245
+#: engines/engine.cpp:276
msgid "Could not initialize color format."
msgstr "Szэn formсtum nincs alkalmazva"
-#: engines/engine.cpp:253
+#: engines/engine.cpp:284
msgid "Could not switch to video mode: '"
msgstr "Videѓmѓd nincs сtсllэtva: ' "
-#: engines/engine.cpp:262
+#: engines/engine.cpp:293
msgid "Could not apply aspect ratio setting."
msgstr "Mщretarсny korrekciѓ nem vсltozott."
-#: engines/engine.cpp:267
+#: engines/engine.cpp:298
msgid "Could not apply fullscreen setting."
msgstr "Teljeskщpernyѕs beсllэtсs nincs alkalmazva"
-#: engines/engine.cpp:367
+#: engines/engine.cpp:398
msgid ""
"You appear to be playing this game directly\n"
"from the CD. This is known to cause problems,\n"
@@ -1349,7 +1391,7 @@ msgstr ""
"adatfсjljait a merevlemezedre.\n"
"Nщzd meg a README fсjlt a rщszletekщrt."
-#: engines/engine.cpp:378
+#: engines/engine.cpp:409
msgid ""
"This game has audio tracks in its disk. These\n"
"tracks need to be ripped from the disk using\n"
@@ -1363,7 +1405,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:436
+#: engines/engine.cpp:467
#, c-format
msgid ""
"Gamestate load failed (%s)! Please consult the README for basic information, "
@@ -1372,7 +1414,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:449
+#: engines/engine.cpp:480
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 "
@@ -1382,7 +1424,7 @@ 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:452
+#: engines/engine.cpp:483
msgid "Start anyway"
msgstr "Indэtсs эgy is"
@@ -1590,11 +1632,11 @@ msgstr "Touchpad mѓd engedщlyezve."
msgid "Touchpad mode disabled."
msgstr "Touchpad mѓd letiltva."
-#: backends/platform/maemo/maemo.cpp:209
+#: backends/platform/maemo/maemo.cpp:208
msgid "Click Mode"
msgstr "Kattintсs Mѓd"
-#: backends/platform/maemo/maemo.cpp:215
+#: backends/platform/maemo/maemo.cpp:214
#: backends/platform/symbian/src/SymbianActions.cpp:42
#: backends/platform/wince/CEActionsPocket.cpp:60
#: backends/platform/wince/CEActionsSmartphone.cpp:43
@@ -1602,11 +1644,11 @@ msgstr "Kattintсs Mѓd"
msgid "Left Click"
msgstr "Bal katt"
-#: backends/platform/maemo/maemo.cpp:218
+#: backends/platform/maemo/maemo.cpp:217
msgid "Middle Click"
msgstr "Kіzщpsѕ katt"
-#: backends/platform/maemo/maemo.cpp:221
+#: 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
@@ -1643,19 +1685,19 @@ msgctxt "lowres"
msgid "Normal (no scaling)"
msgstr "Normсl (nincs сtmщretezщs)"
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2148
+#: 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:2154
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2203
msgid "Disabled aspect ratio correction"
msgstr "Mщretarсny korrekciѓ letiltva"
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2209
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2258
msgid "Active graphics filter:"
msgstr "Aktэv grafikus szћrѕk:"
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2251
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2300
msgid "Windowed mode"
msgstr "Ablakos mѓd"
@@ -1714,8 +1756,8 @@ msgstr "Gyors mѓd"
#: 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:82
-#: engines/scumm/help.cpp:84
+#: engines/scumm/dialogs.cpp:192 engines/scumm/help.cpp:83
+#: engines/scumm/help.cpp:85
msgid "Quit"
msgstr "Kilщpщs"
@@ -1735,7 +1777,7 @@ msgstr "Virtuсlis billentyћzet"
msgid "Key mapper"
msgstr "Billentyћ kiosztсs"
-#: backends/events/symbiansdl/symbiansdl-events.cpp:184
+#: backends/events/symbiansdl/symbiansdl-events.cpp:186
msgid "Do you want to quit ?"
msgstr "Ki akarsz lщpni ?"
@@ -2068,33 +2110,54 @@ msgstr "Kattintсs engedve"
msgid "Clicking Disabled"
msgstr "Kattintсs tiltva"
-#: engines/agi/detection.cpp:142 engines/drascula/detection.cpp:302
+#: 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.cpp:103
+#: engines/zvision/detection.cpp:246
msgid "Use original save/load screens"
msgstr "Eredeti ment/tіlt kщpernyѕk hasznсlata"
-#: engines/agi/detection.cpp:143 engines/drascula/detection.cpp:303
+#: 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/zvision/detection.cpp:104
+#: engines/zvision/detection.cpp:247
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)"
+
+#: engines/agi/detection.cpp:158
+msgid ""
+"Use an alternative palette, common for all Amiga games. This was the old "
+"behavior"
+msgstr ""
+
+#: engines/agi/detection.cpp:167
+#, fuzzy
+msgid "Mouse support"
+msgstr "Сtugrсs tсmogatсs"
+
+#: 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:857 engines/toltecs/menu.cpp:256
+#: engines/sci/engine/kfile.cpp:858 engines/toltecs/menu.cpp:256
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:857 engines/toltecs/menu.cpp:256
+#: engines/sci/engine/kfile.cpp:858 engines/toltecs/menu.cpp:256
msgid "Restore"
msgstr "Visszaсllэtсs"
-#: engines/agos/saveload.cpp:160 engines/scumm/scumm.cpp:2368
+#: engines/agos/saveload.cpp:160 engines/scumm/scumm.cpp:2377
#, c-format
msgid ""
"Failed to load game state from file:\n"
@@ -2105,7 +2168,7 @@ msgstr ""
"\n"
"%s fсjlbѓl nem sikerќlt"
-#: engines/agos/saveload.cpp:195 engines/scumm/scumm.cpp:2361
+#: engines/agos/saveload.cpp:195 engines/scumm/scumm.cpp:2370
#, c-format
msgid ""
"Failed to save game state to file:\n"
@@ -2116,7 +2179,7 @@ msgstr ""
"\n"
"%s fсjlba nem sikerќlt"
-#: engines/agos/saveload.cpp:203 engines/scumm/scumm.cpp:2379
+#: engines/agos/saveload.cpp:203 engines/scumm/scumm.cpp:2388
#, c-format
msgid ""
"Successfully saved game state in file:\n"
@@ -2132,12 +2195,12 @@ msgstr ""
msgid "Cutscene file '%s' not found!"
msgstr "'%s' сtvezetѕ fсjl nem talсlhatѓ"
-#: engines/cge/detection.cpp:105 engines/cge2/detection.cpp:81
+#: engines/cge/detection.cpp:105 engines/cge2/detection.cpp:101
#, fuzzy
msgid "Color Blind Mode"
msgstr "Kattintсs Mѓd"
-#: engines/cge/detection.cpp:106 engines/cge2/detection.cpp:82
+#: engines/cge/detection.cpp:106 engines/cge2/detection.cpp:102
msgid "Enable Color Blind Mode by default"
msgstr ""
@@ -2188,7 +2251,7 @@ msgstr "Gyors filmsebessщg"
msgid "Play movies at an increased speed"
msgstr "Filmek lejсtszсsa nagyobb sebessщggel"
-#: engines/groovie/script.cpp:399
+#: engines/groovie/script.cpp:408
msgid "Failed to save game"
msgstr "Jсtщk mentщs nem sikerќlt"
@@ -2486,12 +2549,12 @@ 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
-msgid "EGA undithering"
-msgstr "EGA szinjavэtсs"
+msgid "Skip EGA dithering pass (full color backgrounds)"
+msgstr ""
#: engines/sci/detection.cpp:375
-msgid "Enable undithering in EGA games"
-msgstr "Undithering engedщlyezщse EGA jсtщkokban"
+msgid "Skip dithering pass in EGA games, graphics are shown with full colors"
+msgstr ""
#: engines/sci/detection.cpp:384
msgid "Prefer digital sound effects"
@@ -2562,12 +2625,14 @@ msgstr "Jсtщk szќnetel. SPACE a folytatсshoz."
#. "Moechten Sie wirklich neu starten? (J/N)J"
#. Will react to J as 'Yes'
#: engines/scumm/dialogs.cpp:183
-msgid "Are you sure you want to restart? (Y/N)"
+#, fuzzy
+msgid "Are you sure you want to restart? (Y/N)Y"
msgstr "Biztos hogy њjra akarod indэtani? (Y/N)"
#. I18N: you may specify 'Yes' symbol at the end of the line. See previous comment
#: engines/scumm/dialogs.cpp:185
-msgid "Are you sure you want to quit? (Y/N)"
+#, fuzzy
+msgid "Are you sure you want to quit? (Y/N)Y"
msgstr "Biztos hogy ki akarsz lщpni? (Y/N)"
#: engines/scumm/dialogs.cpp:190
@@ -2655,516 +2720,541 @@ msgstr "Gyakorlсs"
msgid "Expert"
msgstr "Szakщrtѕ"
-#: engines/scumm/help.cpp:73
+#: engines/scumm/help.cpp:74
msgid "Common keyboard commands:"
msgstr "Сltalсnos billentyћparancsok:"
-#: engines/scumm/help.cpp:74
+#: engines/scumm/help.cpp:75
msgid "Save / Load dialog"
msgstr "Ment / Tіlt dialѓgus"
-#: engines/scumm/help.cpp:76
+#: engines/scumm/help.cpp:77
msgid "Skip line of text"
msgstr "Szіvegsor сtugrсsa"
-#: engines/scumm/help.cpp:77
+#: engines/scumm/help.cpp:78
msgid "Esc"
msgstr "Esc"
-#: engines/scumm/help.cpp:77
+#: engines/scumm/help.cpp:78
msgid "Skip cutscene"
msgstr "Bevezetѕ сtugrсsa"
-#: engines/scumm/help.cpp:78
+#: engines/scumm/help.cpp:79
msgid "Space"
msgstr "Szѓkіz"
-#: engines/scumm/help.cpp:78
+#: engines/scumm/help.cpp:79
msgid "Pause game"
msgstr "Szќnet a jсtщkban"
-#: engines/scumm/help.cpp:79 engines/scumm/help.cpp:84
-#: engines/scumm/help.cpp:95 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: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:79
+#: engines/scumm/help.cpp:80
msgid "Load game state 1-10"
msgstr "1-10 Jсtщkсllсs betіltщse"
-#: engines/scumm/help.cpp:80 engines/scumm/help.cpp:84
-#: engines/scumm/help.cpp:86 engines/scumm/help.cpp:100
-#: engines/scumm/help.cpp:101 engines/scumm/help.cpp:102
+#: 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:80
+#: engines/scumm/help.cpp:81
msgid "Save game state 1-10"
msgstr "1-10 Jсtщkсllсs mentщse"
-#: engines/scumm/help.cpp:86 engines/scumm/help.cpp:89
+#: engines/scumm/help.cpp:87 engines/scumm/help.cpp:90
msgid "Enter"
msgstr "Enter"
-#: engines/scumm/help.cpp:87
+#: engines/scumm/help.cpp:88
msgid "Music volume up / down"
msgstr "Zene hangerѕ fel / le"
-#: engines/scumm/help.cpp:88
+#: engines/scumm/help.cpp:89
msgid "Text speed slower / faster"
msgstr "Szіvegsebessщg gyors / lassњ"
-#: engines/scumm/help.cpp:89
+#: engines/scumm/help.cpp:90
msgid "Simulate left mouse button"
msgstr "Bal egщrgomb szimulсciѓ"
-#: engines/scumm/help.cpp:90
+#: engines/scumm/help.cpp:91
msgid "Tab"
msgstr "Tab"
-#: engines/scumm/help.cpp:90
+#: engines/scumm/help.cpp:91
msgid "Simulate right mouse button"
msgstr "Jobb egщrgomb szimulсciѓ"
-#: engines/scumm/help.cpp:93
+#: engines/scumm/help.cpp:94
msgid "Special keyboard commands:"
msgstr "Speciсlis billentyћparancsok:"
-#: engines/scumm/help.cpp:94
+#: engines/scumm/help.cpp:95
msgid "Show / Hide console"
msgstr "Konzol be / ki kapcsolсs"
-#: engines/scumm/help.cpp:95
+#: engines/scumm/help.cpp:96
msgid "Start the debugger"
msgstr "Hibakeresѕ indэtсsa"
-#: engines/scumm/help.cpp:96
+#: engines/scumm/help.cpp:97
msgid "Show memory consumption"
msgstr "Memѓriakihasznсltsсg lсtszik"
-#: engines/scumm/help.cpp:97
+#: engines/scumm/help.cpp:98
msgid "Run in fast mode (*)"
msgstr "Futtatсs gyors mѓdban (*)"
-#: engines/scumm/help.cpp:98
+#: engines/scumm/help.cpp:99
msgid "Run in really fast mode (*)"
msgstr "Futtatсs tњlgyors mѓdban (*)"
-#: engines/scumm/help.cpp:99
+#: engines/scumm/help.cpp:100
msgid "Toggle mouse capture"
msgstr "Egщr rіgzэtщs kapcsolѓ"
-#: engines/scumm/help.cpp:100
+#: engines/scumm/help.cpp:101
msgid "Switch between graphics filters"
msgstr "Kapcsolсs grafikus szћrѕk kіzіtt"
-#: engines/scumm/help.cpp:101
+#: engines/scumm/help.cpp:102
msgid "Increase / Decrease scale factor"
msgstr "Lщptщk nіvelщs / csіkkentщs"
-#: engines/scumm/help.cpp:102
+#: engines/scumm/help.cpp:103
msgid "Toggle aspect-ratio correction"
msgstr "Mщretarсny korrekciѓ kapcsolѓ"
-#: engines/scumm/help.cpp:107
+#: engines/scumm/help.cpp:108
msgid "* Note that using ctrl-f and"
msgstr "* Megjegyzщs, ctrl-f щs"
-#: engines/scumm/help.cpp:108
+#: engines/scumm/help.cpp:109
msgid " ctrl-g are not recommended"
msgstr " ctrl-g hasznсlata nem javasolt"
-#: engines/scumm/help.cpp:109
+#: engines/scumm/help.cpp:110
msgid " since they may cause crashes"
msgstr " mert rendszerіsszeomlсst vagy"
-#: engines/scumm/help.cpp:110
+#: engines/scumm/help.cpp:111
msgid " or incorrect game behavior."
msgstr " vagy hibсs jсtщkmћkіdщst okoz."
-#: engines/scumm/help.cpp:114
+#: engines/scumm/help.cpp:115
msgid "Spinning drafts on the keyboard:"
msgstr "Forgѓ draftok a billentyћzeten:"
-#: engines/scumm/help.cpp:116
+#: engines/scumm/help.cpp:117
msgid "Main game controls:"
msgstr "Fѕ jсtщkvezщrlѕk:"
-#: engines/scumm/help.cpp:121 engines/scumm/help.cpp:136
-#: engines/scumm/help.cpp:161
+#: engines/scumm/help.cpp:122 engines/scumm/help.cpp:137
+#: engines/scumm/help.cpp:162
msgid "Push"
msgstr "Tol"
-#: engines/scumm/help.cpp:122 engines/scumm/help.cpp:137
-#: engines/scumm/help.cpp:162
+#: engines/scumm/help.cpp:123 engines/scumm/help.cpp:138
+#: engines/scumm/help.cpp:163
msgid "Pull"
msgstr "Hњz"
-#: engines/scumm/help.cpp:123 engines/scumm/help.cpp:138
-#: engines/scumm/help.cpp:163 engines/scumm/help.cpp:197
-#: engines/scumm/help.cpp:207
+#: 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 "Ad"
-#: engines/scumm/help.cpp:124 engines/scumm/help.cpp:139
-#: engines/scumm/help.cpp:164 engines/scumm/help.cpp:190
-#: engines/scumm/help.cpp:208
+#: 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 "Nyit"
-#: engines/scumm/help.cpp:126
+#: engines/scumm/help.cpp:127
msgid "Go to"
msgstr "Menj"
-#: engines/scumm/help.cpp:127
+#: engines/scumm/help.cpp:128
msgid "Get"
msgstr "Vesz"
-#: engines/scumm/help.cpp:128 engines/scumm/help.cpp:152
-#: engines/scumm/help.cpp:170 engines/scumm/help.cpp:198
-#: engines/scumm/help.cpp:213 engines/scumm/help.cpp:224
-#: engines/scumm/help.cpp:250
+#: 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 "Hasznсl"
-#: engines/scumm/help.cpp:129 engines/scumm/help.cpp:141
+#: engines/scumm/help.cpp:130 engines/scumm/help.cpp:142
msgid "Read"
msgstr "Olvas"
-#: engines/scumm/help.cpp:130 engines/scumm/help.cpp:147
+#: engines/scumm/help.cpp:131 engines/scumm/help.cpp:148
msgid "New kid"
msgstr "кj gyerek"
-#: engines/scumm/help.cpp:131 engines/scumm/help.cpp:153
-#: engines/scumm/help.cpp:171
+#: engines/scumm/help.cpp:132 engines/scumm/help.cpp:154
+#: engines/scumm/help.cpp:172
msgid "Turn on"
msgstr "Bekapcsol"
-#: engines/scumm/help.cpp:132 engines/scumm/help.cpp:154
-#: engines/scumm/help.cpp:172
+#: engines/scumm/help.cpp:133 engines/scumm/help.cpp:155
+#: engines/scumm/help.cpp:173
msgid "Turn off"
msgstr "Kikapcsol"
-#: engines/scumm/help.cpp:142 engines/scumm/help.cpp:167
-#: engines/scumm/help.cpp:194
+#: engines/scumm/help.cpp:143 engines/scumm/help.cpp:168
+#: engines/scumm/help.cpp:195
msgid "Walk to"
msgstr "Odamegy"
-#: engines/scumm/help.cpp:143 engines/scumm/help.cpp:168
-#: engines/scumm/help.cpp:195 engines/scumm/help.cpp:210
-#: engines/scumm/help.cpp:227
+#: 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 "Felvesz"
-#: engines/scumm/help.cpp:144 engines/scumm/help.cpp:169
+#: engines/scumm/help.cpp:145 engines/scumm/help.cpp:170
msgid "What is"
msgstr "Mi ez"
-#: engines/scumm/help.cpp:146
+#: engines/scumm/help.cpp:147
msgid "Unlock"
msgstr "Felold"
-#: engines/scumm/help.cpp:149
+#: engines/scumm/help.cpp:150
msgid "Put on"
msgstr "Felvesz"
-#: engines/scumm/help.cpp:150
+#: engines/scumm/help.cpp:151
msgid "Take off"
msgstr "Letesz"
-#: engines/scumm/help.cpp:156
+#: engines/scumm/help.cpp:157
msgid "Fix"
msgstr "Javэt"
-#: engines/scumm/help.cpp:158
+#: engines/scumm/help.cpp:159
msgid "Switch"
msgstr "Kapcsol"
-#: engines/scumm/help.cpp:166 engines/scumm/help.cpp:228
+#: engines/scumm/help.cpp:167 engines/scumm/help.cpp:229
msgid "Look"
msgstr "Megnщz"
-#: engines/scumm/help.cpp:173 engines/scumm/help.cpp:223
+#: engines/scumm/help.cpp:174 engines/scumm/help.cpp:224
msgid "Talk"
msgstr "Beszщl"
-#: engines/scumm/help.cpp:174
+#: engines/scumm/help.cpp:175
msgid "Travel"
msgstr "Utazсs"
-#: engines/scumm/help.cpp:175
+#: engines/scumm/help.cpp:176
msgid "To Henry / To Indy"
msgstr "Henrytѕl / Indytѕl"
#. I18N: These are different musical notes
-#: engines/scumm/help.cpp:179
+#: engines/scumm/help.cpp:180
msgid "play C minor on distaff"
msgstr "C moll jсtщk a bottal"
-#: engines/scumm/help.cpp:180
+#: engines/scumm/help.cpp:181
msgid "play D on distaff"
msgstr "Jсtщk D-ben a bottal"
-#: engines/scumm/help.cpp:181
+#: engines/scumm/help.cpp:182
msgid "play E on distaff"
msgstr "Jсtщk E-ben a bottal"
-#: engines/scumm/help.cpp:182
+#: engines/scumm/help.cpp:183
msgid "play F on distaff"
msgstr "Jсtщk F-ben a bottal"
-#: engines/scumm/help.cpp:183
+#: engines/scumm/help.cpp:184
msgid "play G on distaff"
msgstr "Jсtщk G-ben a bottal"
-#: engines/scumm/help.cpp:184
+#: engines/scumm/help.cpp:185
msgid "play A on distaff"
msgstr "Jсtщk A-ban a bottal"
-#: engines/scumm/help.cpp:185
+#: engines/scumm/help.cpp:186
msgid "play B on distaff"
msgstr "Jсtщk B-ben a bottal"
-#: engines/scumm/help.cpp:186
+#: engines/scumm/help.cpp:187
msgid "play C major on distaff"
msgstr "C dњr jсtщk a bottal"
-#: engines/scumm/help.cpp:192 engines/scumm/help.cpp:214
+#: engines/scumm/help.cpp:193 engines/scumm/help.cpp:215
msgid "puSh"
msgstr "Megtol"
-#: engines/scumm/help.cpp:193 engines/scumm/help.cpp:215
+#: engines/scumm/help.cpp:194 engines/scumm/help.cpp:216
msgid "pull (Yank)"
msgstr "hњz (Rсnt)"
-#: engines/scumm/help.cpp:196 engines/scumm/help.cpp:212
-#: engines/scumm/help.cpp:248
+#: engines/scumm/help.cpp:197 engines/scumm/help.cpp:213
+#: engines/scumm/help.cpp:249
msgid "Talk to"
msgstr "Beszщl"
-#: engines/scumm/help.cpp:199 engines/scumm/help.cpp:211
+#: engines/scumm/help.cpp:200 engines/scumm/help.cpp:212
msgid "Look at"
msgstr "Megnщzi"
-#: engines/scumm/help.cpp:200
+#: engines/scumm/help.cpp:201
msgid "turn oN"
msgstr "Bekapcsol"
-#: engines/scumm/help.cpp:201
+#: engines/scumm/help.cpp:202
msgid "turn oFf"
msgstr "Kikapcsol"
-#: engines/scumm/help.cpp:217
+#: engines/scumm/help.cpp:218
msgid "KeyUp"
msgstr "FelGomb"
-#: engines/scumm/help.cpp:217
+#: engines/scumm/help.cpp:218
msgid "Highlight prev dialogue"
msgstr "Elѕzѕ dialѓgus kiemelщse"
-#: engines/scumm/help.cpp:218
+#: engines/scumm/help.cpp:219
msgid "KeyDown"
msgstr "LeGomb"
-#: engines/scumm/help.cpp:218
+#: engines/scumm/help.cpp:219
msgid "Highlight next dialogue"
msgstr "Kіvetkezѕ dialѓgus kiemelщse"
-#: engines/scumm/help.cpp:222
+#: engines/scumm/help.cpp:223
msgid "Walk"
msgstr "Megy"
-#: engines/scumm/help.cpp:225 engines/scumm/help.cpp:234
-#: engines/scumm/help.cpp:241 engines/scumm/help.cpp:249
+#: engines/scumm/help.cpp:226 engines/scumm/help.cpp:235
+#: engines/scumm/help.cpp:242 engines/scumm/help.cpp:250
msgid "Inventory"
msgstr "Tсrgylista"
-#: engines/scumm/help.cpp:226
+#: engines/scumm/help.cpp:227
msgid "Object"
msgstr "Tсrgy"
-#: engines/scumm/help.cpp:229
+#: engines/scumm/help.cpp:230
msgid "Black and White / Color"
msgstr "Fekete fehщr / Szэnes"
-#: engines/scumm/help.cpp:232
+#: engines/scumm/help.cpp:233
msgid "Eyes"
msgstr "Szemek"
-#: engines/scumm/help.cpp:233
+#: engines/scumm/help.cpp:234
msgid "Tongue"
msgstr "Nyelv"
-#: engines/scumm/help.cpp:235
+#: engines/scumm/help.cpp:236
msgid "Punch"
msgstr "Megќt"
-#: engines/scumm/help.cpp:236
+#: engines/scumm/help.cpp:237
msgid "Kick"
msgstr "Megќt"
-#: engines/scumm/help.cpp:239 engines/scumm/help.cpp:247
+#: engines/scumm/help.cpp:240 engines/scumm/help.cpp:248
msgid "Examine"
msgstr "Vizsgсl"
-#: engines/scumm/help.cpp:240
+#: engines/scumm/help.cpp:241
msgid "Regular cursor"
msgstr "Szabvсny kurzor"
#. I18N: Comm is a communication device
-#: engines/scumm/help.cpp:243
+#: engines/scumm/help.cpp:244
msgid "Comm"
msgstr "Comm"
-#: engines/scumm/help.cpp:246
+#: engines/scumm/help.cpp:247
msgid "Save / Load / Options"
msgstr "Ment / Tіlt / Opciѓk"
-#: engines/scumm/help.cpp:255
+#: engines/scumm/help.cpp:256
msgid "Other game controls:"
msgstr "Egyщbb jсtщkvezщrlѕk:"
-#: engines/scumm/help.cpp:257 engines/scumm/help.cpp:267
+#: engines/scumm/help.cpp:258 engines/scumm/help.cpp:268
msgid "Inventory:"
msgstr "Tсrgylista:"
-#: engines/scumm/help.cpp:258 engines/scumm/help.cpp:274
+#: engines/scumm/help.cpp:259 engines/scumm/help.cpp:275
msgid "Scroll list up"
msgstr "Listagіrgetщs fel"
-#: engines/scumm/help.cpp:259 engines/scumm/help.cpp:275
+#: engines/scumm/help.cpp:260 engines/scumm/help.cpp:276
msgid "Scroll list down"
msgstr "Listagіrgetщs le"
-#: engines/scumm/help.cpp:260 engines/scumm/help.cpp:268
+#: engines/scumm/help.cpp:261 engines/scumm/help.cpp:269
msgid "Upper left item"
msgstr "Bal felsѕ tсrgy"
-#: engines/scumm/help.cpp:261 engines/scumm/help.cpp:270
+#: engines/scumm/help.cpp:262 engines/scumm/help.cpp:271
msgid "Lower left item"
msgstr "Bal alsѓ tсrgy"
-#: engines/scumm/help.cpp:262 engines/scumm/help.cpp:271
+#: engines/scumm/help.cpp:263 engines/scumm/help.cpp:272
msgid "Upper right item"
msgstr "Jobb felsѕ tсrgy"
-#: engines/scumm/help.cpp:263 engines/scumm/help.cpp:273
+#: engines/scumm/help.cpp:264 engines/scumm/help.cpp:274
msgid "Lower right item"
msgstr "Jobb alsѓ tсrgy"
-#: engines/scumm/help.cpp:269
+#: engines/scumm/help.cpp:270
msgid "Middle left item"
msgstr "Bal kіzщpsѕ tсrgy"
-#: engines/scumm/help.cpp:272
+#: engines/scumm/help.cpp:273
msgid "Middle right item"
msgstr "Jobb kіzщpsѕ tсrgy"
-#: engines/scumm/help.cpp:279 engines/scumm/help.cpp:284
+#: engines/scumm/help.cpp:280 engines/scumm/help.cpp:285
msgid "Switching characters:"
msgstr "Karakterek cserщje:"
-#: engines/scumm/help.cpp:281
+#: engines/scumm/help.cpp:282
msgid "Second kid"
msgstr "Mсsodik gyerek"
-#: engines/scumm/help.cpp:282
+#: engines/scumm/help.cpp:283
msgid "Third kid"
msgstr "Harmadik gyerek"
-#: engines/scumm/help.cpp:294
+#: engines/scumm/help.cpp:292
+#, fuzzy
+msgid "Toggle Inventory/IQ Points display"
+msgstr "Adatkщpernyѕ kapcsolѓ"
+
+#: engines/scumm/help.cpp:293
+msgid "Toggle Keyboard/Mouse Fighting (*)"
+msgstr ""
+
+#: engines/scumm/help.cpp:295
+msgid "* Keyboard Fighting is always on,"
+msgstr ""
+
+#: engines/scumm/help.cpp:296
+msgid " so despite the in-game message this"
+msgstr ""
+
+#: engines/scumm/help.cpp:297
+msgid " actually toggles Mouse Fighting Off/On"
+msgstr ""
+
+#: engines/scumm/help.cpp:304
msgid "Fighting controls (numpad):"
msgstr "Verekedщs irсnyэtѓk (numpad):"
-#: engines/scumm/help.cpp:295 engines/scumm/help.cpp:296
-#: engines/scumm/help.cpp:297
+#: engines/scumm/help.cpp:305 engines/scumm/help.cpp:306
+#: engines/scumm/help.cpp:307
msgid "Step back"
msgstr "Hсtralщp"
-#: engines/scumm/help.cpp:298
+#: engines/scumm/help.cpp:308
msgid "Block high"
msgstr "Felsѕ vщdщs"
-#: engines/scumm/help.cpp:299
+#: engines/scumm/help.cpp:309
msgid "Block middle"
msgstr "Vщdщs kіzщpen"
-#: engines/scumm/help.cpp:300
+#: engines/scumm/help.cpp:310
msgid "Block low"
msgstr "Alsѓ vщdщs"
-#: engines/scumm/help.cpp:301
+#: engines/scumm/help.cpp:311
msgid "Punch high"
msgstr "Felsѕ ќtщs"
-#: engines/scumm/help.cpp:302
+#: engines/scumm/help.cpp:312
msgid "Punch middle"
msgstr "мtщs kіzщpen"
-#: engines/scumm/help.cpp:303
+#: engines/scumm/help.cpp:313
msgid "Punch low"
msgstr "Alsѓ ќtщs"
-#: engines/scumm/help.cpp:306
+#: engines/scumm/help.cpp:315
+msgid "Sucker punch"
+msgstr ""
+
+#: engines/scumm/help.cpp:318
msgid "These are for Indy on left."
msgstr "Indytѕl balra levѕ."
-#: engines/scumm/help.cpp:307
+#: engines/scumm/help.cpp:319
msgid "When Indy is on the right,"
msgstr "Indytѕl jobbra levѕ,"
-#: engines/scumm/help.cpp:308
+#: engines/scumm/help.cpp:320
msgid "7, 4, and 1 are switched with"
msgstr "7, 4, щs 1 сtkapcsolva"
-#: engines/scumm/help.cpp:309
+#: engines/scumm/help.cpp:321
msgid "9, 6, and 3, respectively."
msgstr "9, 6, щs 3-ra, egyenkщnt."
-#: engines/scumm/help.cpp:316
+#: engines/scumm/help.cpp:328
msgid "Biplane controls (numpad):"
msgstr "Repќlѕ vezщrlѕk (numpad):"
-#: engines/scumm/help.cpp:317
+#: engines/scumm/help.cpp:329
msgid "Fly to upper left"
msgstr "Balra fel repќlщs"
-#: engines/scumm/help.cpp:318
+#: engines/scumm/help.cpp:330
msgid "Fly to left"
msgstr "Balra repќlщs"
-#: engines/scumm/help.cpp:319
+#: engines/scumm/help.cpp:331
msgid "Fly to lower left"
msgstr "Balra le repќlщs"
-#: engines/scumm/help.cpp:320
+#: engines/scumm/help.cpp:332
msgid "Fly upwards"
msgstr "Repќlщs fel"
-#: engines/scumm/help.cpp:321
+#: engines/scumm/help.cpp:333
msgid "Fly straight"
msgstr "Repќlщs elѕre"
-#: engines/scumm/help.cpp:322
+#: engines/scumm/help.cpp:334
msgid "Fly down"
msgstr "Repќlщs le"
-#: engines/scumm/help.cpp:323
+#: engines/scumm/help.cpp:335
msgid "Fly to upper right"
msgstr "Jobbra fel repќlщs"
-#: engines/scumm/help.cpp:324
+#: engines/scumm/help.cpp:336
msgid "Fly to right"
msgstr "Jobbra repќlщs"
-#: engines/scumm/help.cpp:325
+#: engines/scumm/help.cpp:337
msgid "Fly to lower right"
msgstr "Jobbra le repќlщs"
-#: engines/scumm/scumm.cpp:1823
+#: engines/scumm/scumm.cpp:1832
#, c-format
msgid ""
"Native MIDI support requires the Roland Upgrade from LucasArts,\n"
@@ -3173,11 +3263,12 @@ 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:2594
+#: engines/scumm/scumm.cpp:2644
+#, fuzzy
msgid ""
-"Usually, Maniac Mansion would start now. But ScummVM doesn't do that yet. To "
-"play it, go to 'Add Game' in the ScummVM start menu and select the 'Maniac' "
-"directory inside the Tentacle game directory."
+"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 "
@@ -3315,6 +3406,47 @@ msgstr ""
msgid "Show the current number of frames per second in the upper left corner"
msgstr ""
+#: engines/zvision/detection.cpp:256
+msgid "Double FPS"
+msgstr ""
+
+#: engines/zvision/detection.cpp:257
+msgid "Increase game FPS from 30 to 60"
+msgstr ""
+
+#: engines/zvision/detection.cpp:266
+#, fuzzy
+msgid "Enable Venus"
+msgstr "Helium mѓd engedщlyezve"
+
+#: engines/zvision/detection.cpp:267
+msgid "Enable the Venus help system"
+msgstr ""
+
+#: engines/zvision/detection.cpp:276
+msgid "Disable animation while turning"
+msgstr ""
+
+#: engines/zvision/detection.cpp:277
+msgid "Disable animation while turning in panoramic mode"
+msgstr ""
+
+#: engines/zvision/detection.cpp:286
+msgid "Use the hires MPEG movies"
+msgstr ""
+
+#: engines/zvision/detection.cpp:287
+#, fuzzy
+msgid ""
+"Use the hires MPEG movies of the DVD version, instead of the lowres AVI ones"
+msgstr "Alternatэv ezќst kurzorszett hasznсlata, a normсl arany helyett"
+
+#~ msgid "EGA undithering"
+#~ msgstr "EGA szinjavэtсs"
+
+#~ msgid "Enable undithering in EGA games"
+#~ msgstr "Undithering engedщlyezщse EGA jсtщkokban"
+
#~ msgid "MPEG-2 cutscenes found but ScummVM has been built without MPEG-2"
#~ msgstr ""
#~ "MPEG-2 сtvezetѕfilmet talсltam, de a ScummVM MPEG-2 nщlkќl van lefordэtva"
@@ -3323,9 +3455,6 @@ msgstr ""
#~ msgid "Mass Add..."
#~ msgstr "Masszэv mѓd..."
-#~ msgid "Mass Add..."
-#~ msgstr "Masszэv mѓd..."
-
#~ msgid ""
#~ "Turns off General MIDI mapping for games with Roland MT-32 soundtrack"
#~ msgstr "General MIDI lekщpezщs Roland MT-32 zenщs jсtщkokhoz kikapcsolva"
diff --git a/po/it_IT.po b/po/it_IT.po
index 3db0122682..5dfa8039b4 100644
--- a/po/it_IT.po
+++ b/po/it_IT.po
@@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: ScummVM 1.3.0svn\n"
"Report-Msgid-Bugs-To: scummvm-devel@lists.sf.net\n"
-"POT-Creation-Date: 2014-10-04 00:58+0100\n"
+"POT-Creation-Date: 2015-06-30 20:57+0100\n"
"PO-Revision-Date: 2014-07-03 17:59-0600\n"
"Last-Translator: Matteo 'Maff' Angelino <matteo.maff at gmail dot com>\n"
"Language-Team: Italian\n"
@@ -52,10 +52,11 @@ msgstr "Su"
#: gui/browser.cpp:75 gui/chooser.cpp:46 gui/KeysDialog.cpp:43
#: gui/launcher.cpp:351 gui/massadd.cpp:95 gui/options.cpp:1239
+#: gui/recorderdialog.cpp:70 gui/recorderdialog.cpp:156
#: gui/saveload-dialog.cpp:216 gui/saveload-dialog.cpp:276
-#: gui/saveload-dialog.cpp:547 gui/saveload-dialog.cpp:922
+#: gui/saveload-dialog.cpp:547 gui/saveload-dialog.cpp:931
#: gui/themebrowser.cpp:55 gui/fluidsynth-dialog.cpp:152
-#: engines/engine.cpp:452 backends/platform/wii/options.cpp:48
+#: engines/engine.cpp:483 backends/platform/wii/options.cpp:48
#: backends/events/default/default-events.cpp:196
#: backends/events/default/default-events.cpp:218
#: engines/drascula/saveload.cpp:49 engines/parallaction/saveload.cpp:274
@@ -68,9 +69,9 @@ msgid "Choose"
msgstr "Scegli"
#: gui/gui-manager.cpp:117 backends/keymapper/remap-dialog.cpp:53
-#: 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
+#: 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"
@@ -86,7 +87,7 @@ msgstr "Mostra tastiera"
msgid "Remap keys"
msgstr "Riprogramma tasti"
-#: gui/gui-manager.cpp:131 base/main.cpp:326 engines/scumm/help.cpp:86
+#: gui/gui-manager.cpp:131 base/main.cpp:326 engines/scumm/help.cpp:87
msgid "Toggle fullscreen"
msgstr "Attiva / disattiva schermo intero"
@@ -100,13 +101,13 @@ 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:1240
-#: gui/saveload-dialog.cpp:923 gui/fluidsynth-dialog.cpp:153
-#: engines/engine.cpp:371 engines/engine.cpp:382
+#: 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:399 engines/parallaction/saveload.cpp:274
-#: engines/scumm/dialogs.cpp:193 engines/scumm/scumm.cpp:1825
+#: 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
@@ -475,7 +476,7 @@ msgstr ""
#: gui/launcher.cpp:793 gui/launcher.cpp:941 gui/launcher.cpp:1000
#: gui/fluidsynth-dialog.cpp:217
-#: backends/events/symbiansdl/symbiansdl-events.cpp:184
+#: 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
@@ -485,7 +486,7 @@ 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:184
+#: 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
@@ -525,6 +526,14 @@ msgstr ""
"ScummVM non ha potuto trovare un motore in grado di eseguire il gioco "
"selezionato!"
+#: gui/launcher.cpp:1159
+msgid "Mass Add..."
+msgstr "Agg. in massa..."
+
+#: gui/launcher.cpp:1161
+msgid "Record..."
+msgstr ""
+
#: gui/massadd.cpp:79 gui/massadd.cpp:82
msgid "... progress ..."
msgstr "... progresso ..."
@@ -623,7 +632,7 @@ msgid "Special dithering modes supported by some games"
msgstr "Modalitр di resa grafica speciali supportate da alcuni giochi"
#: gui/options.cpp:760
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2249
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2298
msgid "Fullscreen mode"
msgstr "Modalitр a schermo intero"
@@ -941,6 +950,43 @@ msgstr ""
"Il tema che hai selezionato non supporta la lingua attuale. Se vuoi "
"utilizzare questo tema devi prima cambiare la lingua."
+#: gui/recorderdialog.cpp:64
+msgid "Recorder or Playback Gameplay"
+msgstr ""
+
+#: gui/recorderdialog.cpp:69 gui/recorderdialog.cpp:156
+#: gui/saveload-dialog.cpp:220 gui/saveload-dialog.cpp:276
+msgid "Delete"
+msgstr "Elimina"
+
+#: gui/recorderdialog.cpp:71
+msgid "Record"
+msgstr ""
+
+#: gui/recorderdialog.cpp:72
+#, fuzzy
+msgid "Playback"
+msgstr "Gioca"
+
+#: gui/recorderdialog.cpp:74
+msgid "Edit"
+msgstr ""
+
+#: gui/recorderdialog.cpp:86 gui/recorderdialog.cpp:243
+#: gui/recorderdialog.cpp:253
+msgid "Author: "
+msgstr ""
+
+#: gui/recorderdialog.cpp:87 gui/recorderdialog.cpp:244
+#: gui/recorderdialog.cpp:254
+msgid "Notes: "
+msgstr ""
+
+#: gui/recorderdialog.cpp:155
+#, fuzzy
+msgid "Do you really want to delete this record?"
+msgstr "Sei sicuro di voler eliminare questo salvataggio?"
+
#: gui/saveload-dialog.cpp:167
msgid "List view"
msgstr "Elenco"
@@ -961,23 +1007,19 @@ msgstr "Nessun orario salvato"
msgid "No playtime saved"
msgstr "Nessun tempo salvato"
-#: gui/saveload-dialog.cpp:220 gui/saveload-dialog.cpp:276
-msgid "Delete"
-msgstr "Elimina"
-
#: gui/saveload-dialog.cpp:275
msgid "Do you really want to delete this saved game?"
msgstr "Sei sicuro di voler eliminare questo salvataggio?"
-#: gui/saveload-dialog.cpp:385 gui/saveload-dialog.cpp:875
+#: gui/saveload-dialog.cpp:385 gui/saveload-dialog.cpp:884
msgid "Date: "
msgstr "Data: "
-#: gui/saveload-dialog.cpp:389 gui/saveload-dialog.cpp:881
+#: gui/saveload-dialog.cpp:389 gui/saveload-dialog.cpp:890
msgid "Time: "
msgstr "Ora: "
-#: gui/saveload-dialog.cpp:395 gui/saveload-dialog.cpp:889
+#: gui/saveload-dialog.cpp:395 gui/saveload-dialog.cpp:898
msgid "Playtime: "
msgstr "Tempo di gioco: "
@@ -993,19 +1035,19 @@ msgstr "Succ."
msgid "Prev"
msgstr "Prec."
-#: gui/saveload-dialog.cpp:739
+#: gui/saveload-dialog.cpp:748
msgid "New Save"
msgstr "Nuovo salvataggio"
-#: gui/saveload-dialog.cpp:739
+#: gui/saveload-dialog.cpp:748
msgid "Create a new save game"
msgstr "Crea un nuovo salvataggio"
-#: gui/saveload-dialog.cpp:868
+#: gui/saveload-dialog.cpp:877
msgid "Name: "
msgstr "Nome: "
-#: gui/saveload-dialog.cpp:940
+#: gui/saveload-dialog.cpp:949
#, c-format
msgid "Enter a description for slot %d:"
msgstr "Inserisci una descrizione per la posizione %d:"
@@ -1159,7 +1201,7 @@ msgstr "Salta battuta"
msgid "Error running game:"
msgstr "Errore nell'esecuzione del gioco:"
-#: base/main.cpp:536
+#: base/main.cpp:554
msgid "Could not find any engine capable of running the selected game"
msgstr ""
"Impossibile trovare un motore in grado di eseguire il gioco selezionato"
@@ -1277,7 +1319,7 @@ 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:758
+#: engines/pegasus/pegasus.cpp:377 engines/sci/engine/kfile.cpp:759
#: engines/toltecs/menu.cpp:281 engines/tsage/scenes.cpp:598
msgid "Save game:"
msgstr "Salva gioco:"
@@ -1290,7 +1332,7 @@ msgstr "Salva gioco:"
#: 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:758 engines/scumm/dialogs.cpp:188
+#: engines/sci/engine/kfile.cpp:759 engines/scumm/dialogs.cpp:188
#: engines/toltecs/menu.cpp:281 engines/tsage/scenes.cpp:598
msgid "Save"
msgstr "Salva"
@@ -1329,23 +1371,23 @@ msgstr "~A~nnulla"
msgid "~K~eys"
msgstr "~T~asti"
-#: engines/engine.cpp:245
+#: engines/engine.cpp:276
msgid "Could not initialize color format."
msgstr "Impossibile inizializzare il formato colore."
-#: engines/engine.cpp:253
+#: engines/engine.cpp:284
msgid "Could not switch to video mode: '"
msgstr "Impossibile cambiare la modalitр video: '"
-#: engines/engine.cpp:262
+#: engines/engine.cpp:293
msgid "Could not apply aspect ratio setting."
msgstr "Impossibile applicare l'impostazione proporzioni"
-#: engines/engine.cpp:267
+#: engines/engine.cpp:298
msgid "Could not apply fullscreen setting."
msgstr "Impossibile applicare l'impostazione schermo intero."
-#: engines/engine.cpp:367
+#: engines/engine.cpp:398
msgid ""
"You appear to be playing this game directly\n"
"from the CD. This is known to cause problems,\n"
@@ -1359,7 +1401,7 @@ msgstr ""
"sull'hard disk.\n"
"Vedi il file README per i dettagli."
-#: engines/engine.cpp:378
+#: engines/engine.cpp:409
msgid ""
"This game has audio tracks in its disk. These\n"
"tracks need to be ripped from the disk using\n"
@@ -1373,7 +1415,7 @@ msgstr ""
"la musica del gioco.\n"
"Vedi il file README per i dettagli."
-#: engines/engine.cpp:436
+#: engines/engine.cpp:467
#, c-format
msgid ""
"Gamestate load failed (%s)! Please consult the README for basic information, "
@@ -1383,7 +1425,7 @@ msgstr ""
"per le informazioni di base e per le istruzioni su come ottenere ulteriore "
"assistenza."
-#: engines/engine.cpp:449
+#: engines/engine.cpp:480
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 "
@@ -1393,7 +1435,7 @@ msgstr ""
"ScummVM. Ш quindi possibile che sia instabile, e i salvataggi potrebbero non "
"funzionare con future versioni di ScummVM."
-#: engines/engine.cpp:452
+#: engines/engine.cpp:483
msgid "Start anyway"
msgstr "Avvia comunque"
@@ -1603,11 +1645,11 @@ msgstr "Modalitр touchpad attivata."
msgid "Touchpad mode disabled."
msgstr "Modalitр touchpad disattivata."
-#: backends/platform/maemo/maemo.cpp:209
+#: backends/platform/maemo/maemo.cpp:208
msgid "Click Mode"
msgstr "Modalitр clic"
-#: backends/platform/maemo/maemo.cpp:215
+#: backends/platform/maemo/maemo.cpp:214
#: backends/platform/symbian/src/SymbianActions.cpp:42
#: backends/platform/wince/CEActionsPocket.cpp:60
#: backends/platform/wince/CEActionsSmartphone.cpp:43
@@ -1615,11 +1657,11 @@ msgstr "Modalitр clic"
msgid "Left Click"
msgstr "Clic sinistro"
-#: backends/platform/maemo/maemo.cpp:218
+#: backends/platform/maemo/maemo.cpp:217
msgid "Middle Click"
msgstr "Clic centrale"
-#: backends/platform/maemo/maemo.cpp:221
+#: 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
@@ -1656,19 +1698,19 @@ msgctxt "lowres"
msgid "Normal (no scaling)"
msgstr "Normale (no ridim.)"
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2148
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2197
msgid "Enabled aspect ratio correction"
msgstr "Correzione proporzioni attivata"
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2154
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2203
msgid "Disabled aspect ratio correction"
msgstr "Correzione proporzioni disattivata"
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2209
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2258
msgid "Active graphics filter:"
msgstr "Filtro grafico attivo:"
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2251
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2300
msgid "Windowed mode"
msgstr "Modalitр finestra"
@@ -1727,8 +1769,8 @@ msgstr "Modalitр veloce"
#: 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:82
-#: engines/scumm/help.cpp:84
+#: engines/scumm/dialogs.cpp:192 engines/scumm/help.cpp:83
+#: engines/scumm/help.cpp:85
msgid "Quit"
msgstr "Esci"
@@ -1748,7 +1790,7 @@ msgstr "Tastiera virtuale"
msgid "Key mapper"
msgstr "Programmatore tasti"
-#: backends/events/symbiansdl/symbiansdl-events.cpp:184
+#: backends/events/symbiansdl/symbiansdl-events.cpp:186
msgid "Do you want to quit ?"
msgstr "Sei sicuro di voler uscire?"
@@ -2083,35 +2125,56 @@ msgstr "Clic attivato"
msgid "Clicking Disabled"
msgstr "Clic disattivato"
-#: engines/agi/detection.cpp:142 engines/drascula/detection.cpp:302
+#: 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.cpp:103
+#: engines/zvision/detection.cpp:246
msgid "Use original save/load screens"
msgstr "Usa schermate di salvataggio originali"
-#: engines/agi/detection.cpp:143 engines/drascula/detection.cpp:303
+#: 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/zvision/detection.cpp:104
+#: engines/zvision/detection.cpp:247
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 "
"di ScummVM"
+#: engines/agi/detection.cpp:157
+#, fuzzy
+msgid "Use an alternative palette"
+msgstr "Usa un'intro del gioco alternativa (solo versione CD)"
+
+#: engines/agi/detection.cpp:158
+msgid ""
+"Use an alternative palette, common for all Amiga games. This was the old "
+"behavior"
+msgstr ""
+
+#: engines/agi/detection.cpp:167
+#, fuzzy
+msgid "Mouse support"
+msgstr "Interruzione del parlato"
+
+#: 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:857 engines/toltecs/menu.cpp:256
+#: engines/sci/engine/kfile.cpp:858 engines/toltecs/menu.cpp:256
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:857 engines/toltecs/menu.cpp:256
+#: engines/sci/engine/kfile.cpp:858 engines/toltecs/menu.cpp:256
msgid "Restore"
msgstr "Ripristina"
-#: engines/agos/saveload.cpp:160 engines/scumm/scumm.cpp:2368
+#: engines/agos/saveload.cpp:160 engines/scumm/scumm.cpp:2377
#, c-format
msgid ""
"Failed to load game state from file:\n"
@@ -2122,7 +2185,7 @@ msgstr ""
"\n"
"%s"
-#: engines/agos/saveload.cpp:195 engines/scumm/scumm.cpp:2361
+#: engines/agos/saveload.cpp:195 engines/scumm/scumm.cpp:2370
#, c-format
msgid ""
"Failed to save game state to file:\n"
@@ -2133,7 +2196,7 @@ msgstr ""
"\n"
"%s"
-#: engines/agos/saveload.cpp:203 engines/scumm/scumm.cpp:2379
+#: engines/agos/saveload.cpp:203 engines/scumm/scumm.cpp:2388
#, c-format
msgid ""
"Successfully saved game state in file:\n"
@@ -2149,12 +2212,12 @@ msgstr ""
msgid "Cutscene file '%s' not found!"
msgstr "File della scena di intermezzo '%s' non trovato!"
-#: engines/cge/detection.cpp:105 engines/cge2/detection.cpp:81
+#: engines/cge/detection.cpp:105 engines/cge2/detection.cpp:101
#, fuzzy
msgid "Color Blind Mode"
msgstr "Modalitр clic"
-#: engines/cge/detection.cpp:106 engines/cge2/detection.cpp:82
+#: engines/cge/detection.cpp:106 engines/cge2/detection.cpp:102
msgid "Enable Color Blind Mode by default"
msgstr ""
@@ -2206,7 +2269,7 @@ msgstr "Alta velocitр filmati"
msgid "Play movies at an increased speed"
msgstr "Aumenta la velocitр di riproduzione dei filmati"
-#: engines/groovie/script.cpp:399
+#: engines/groovie/script.cpp:408
msgid "Failed to save game"
msgstr "Impossibile salvare il gioco"
@@ -2504,12 +2567,12 @@ msgid "Use an alternative game intro (CD version only)"
msgstr "Usa un'intro del gioco alternativa (solo versione CD)"
#: engines/sci/detection.cpp:374
-msgid "EGA undithering"
-msgstr "Undithering EGA"
+msgid "Skip EGA dithering pass (full color backgrounds)"
+msgstr ""
#: engines/sci/detection.cpp:375
-msgid "Enable undithering in EGA games"
-msgstr "Attiva undithering nei giochi EGA"
+msgid "Skip dithering pass in EGA games, graphics are shown with full colors"
+msgstr ""
#: engines/sci/detection.cpp:384
msgid "Prefer digital sound effects"
@@ -2583,12 +2646,14 @@ msgstr "Gioco in pausa. Premere SPAZIO per continuare."
#. "Moechten Sie wirklich neu starten? (J/N)J"
#. Will react to J as 'Yes'
#: engines/scumm/dialogs.cpp:183
-msgid "Are you sure you want to restart? (Y/N)"
+#, 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
-msgid "Are you sure you want to quit? (Y/N)"
+#, 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
@@ -2676,516 +2741,541 @@ msgstr "Base"
msgid "Expert"
msgstr "Expert"
-#: engines/scumm/help.cpp:73
+#: engines/scumm/help.cpp:74
msgid "Common keyboard commands:"
msgstr "Comandi da tastiera comuni:"
-#: engines/scumm/help.cpp:74
+#: engines/scumm/help.cpp:75
msgid "Save / Load dialog"
msgstr "Finestra di salvataggio / caricamento"
-#: engines/scumm/help.cpp:76
+#: engines/scumm/help.cpp:77
msgid "Skip line of text"
msgstr "Salta battuta"
-#: engines/scumm/help.cpp:77
+#: engines/scumm/help.cpp:78
msgid "Esc"
msgstr "Esc"
-#: engines/scumm/help.cpp:77
+#: engines/scumm/help.cpp:78
msgid "Skip cutscene"
msgstr "Salta scena di intermezzo"
-#: engines/scumm/help.cpp:78
+#: engines/scumm/help.cpp:79
msgid "Space"
msgstr "Spazio"
-#: engines/scumm/help.cpp:78
+#: engines/scumm/help.cpp:79
msgid "Pause game"
msgstr "Metti in pausa"
-#: engines/scumm/help.cpp:79 engines/scumm/help.cpp:84
-#: engines/scumm/help.cpp:95 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: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:79
+#: engines/scumm/help.cpp:80
msgid "Load game state 1-10"
msgstr "Carica salvataggio 1-10"
-#: engines/scumm/help.cpp:80 engines/scumm/help.cpp:84
-#: engines/scumm/help.cpp:86 engines/scumm/help.cpp:100
-#: engines/scumm/help.cpp:101 engines/scumm/help.cpp:102
+#: 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:80
+#: engines/scumm/help.cpp:81
msgid "Save game state 1-10"
msgstr "Salva nella posizione 1-10"
-#: engines/scumm/help.cpp:86 engines/scumm/help.cpp:89
+#: engines/scumm/help.cpp:87 engines/scumm/help.cpp:90
msgid "Enter"
msgstr "Invio"
-#: engines/scumm/help.cpp:87
+#: engines/scumm/help.cpp:88
msgid "Music volume up / down"
msgstr "Volume musica su / giљ"
-#: engines/scumm/help.cpp:88
+#: engines/scumm/help.cpp:89
msgid "Text speed slower / faster"
msgstr "Testo piљ veloce / meno veloce"
-#: engines/scumm/help.cpp:89
+#: engines/scumm/help.cpp:90
msgid "Simulate left mouse button"
msgstr "Simula clic sinistro del mouse"
-#: engines/scumm/help.cpp:90
+#: engines/scumm/help.cpp:91
msgid "Tab"
msgstr "Tab"
-#: engines/scumm/help.cpp:90
+#: engines/scumm/help.cpp:91
msgid "Simulate right mouse button"
msgstr "Simula clic destro del mouse"
-#: engines/scumm/help.cpp:93
+#: engines/scumm/help.cpp:94
msgid "Special keyboard commands:"
msgstr "Comandi da tastiera speciali:"
-#: engines/scumm/help.cpp:94
+#: engines/scumm/help.cpp:95
msgid "Show / Hide console"
msgstr "Mostra/nascondi console"
-#: engines/scumm/help.cpp:95
+#: engines/scumm/help.cpp:96
msgid "Start the debugger"
msgstr "Avvia il debugger"
-#: engines/scumm/help.cpp:96
+#: engines/scumm/help.cpp:97
msgid "Show memory consumption"
msgstr "Mostra consumo memoria"
-#: engines/scumm/help.cpp:97
+#: engines/scumm/help.cpp:98
msgid "Run in fast mode (*)"
msgstr "Esegui in modalitр veloce (*)"
-#: engines/scumm/help.cpp:98
+#: engines/scumm/help.cpp:99
msgid "Run in really fast mode (*)"
msgstr "Esegui in modalitр molto veloce (*)"
-#: engines/scumm/help.cpp:99
+#: engines/scumm/help.cpp:100
msgid "Toggle mouse capture"
msgstr "Attiva / disattiva ancoraggio del mouse"
-#: engines/scumm/help.cpp:100
+#: engines/scumm/help.cpp:101
msgid "Switch between graphics filters"
msgstr "Cambia filtro grafico"
-#: engines/scumm/help.cpp:101
+#: engines/scumm/help.cpp:102
msgid "Increase / Decrease scale factor"
msgstr "Aumenta / diminuisci dimensioni"
-#: engines/scumm/help.cpp:102
+#: engines/scumm/help.cpp:103
msgid "Toggle aspect-ratio correction"
msgstr "Cambia correzione proporzioni"
-#: engines/scumm/help.cpp:107
+#: engines/scumm/help.cpp:108
msgid "* Note that using ctrl-f and"
msgstr "* Nota che l'utilizzo di ctrl-f e"
-#: engines/scumm/help.cpp:108
+#: engines/scumm/help.cpp:109
msgid " ctrl-g are not recommended"
msgstr " ctrl-g non ш consigliato perchщ"
-#: engines/scumm/help.cpp:109
+#: engines/scumm/help.cpp:110
msgid " since they may cause crashes"
msgstr " potrebbe causare blocchi o un"
-#: engines/scumm/help.cpp:110
+#: engines/scumm/help.cpp:111
msgid " or incorrect game behavior."
msgstr " o comportamento errato del gioco."
-#: engines/scumm/help.cpp:114
+#: engines/scumm/help.cpp:115
msgid "Spinning drafts on the keyboard:"
msgstr "Tessere melodie da tastiera:"
-#: engines/scumm/help.cpp:116
+#: engines/scumm/help.cpp:117
msgid "Main game controls:"
msgstr "Controlli principali di gioco:"
-#: engines/scumm/help.cpp:121 engines/scumm/help.cpp:136
-#: engines/scumm/help.cpp:161
+#: engines/scumm/help.cpp:122 engines/scumm/help.cpp:137
+#: engines/scumm/help.cpp:162
msgid "Push"
msgstr "Premi"
-#: engines/scumm/help.cpp:122 engines/scumm/help.cpp:137
-#: engines/scumm/help.cpp:162
+#: engines/scumm/help.cpp:123 engines/scumm/help.cpp:138
+#: engines/scumm/help.cpp:163
msgid "Pull"
msgstr "Tira"
-#: engines/scumm/help.cpp:123 engines/scumm/help.cpp:138
-#: engines/scumm/help.cpp:163 engines/scumm/help.cpp:197
-#: engines/scumm/help.cpp:207
+#: 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 "Dai"
-#: engines/scumm/help.cpp:124 engines/scumm/help.cpp:139
-#: engines/scumm/help.cpp:164 engines/scumm/help.cpp:190
-#: engines/scumm/help.cpp:208
+#: 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 "Apri"
-#: engines/scumm/help.cpp:126
+#: engines/scumm/help.cpp:127
msgid "Go to"
msgstr "Vai verso"
-#: engines/scumm/help.cpp:127
+#: engines/scumm/help.cpp:128
msgid "Get"
msgstr "Prendi"
-#: engines/scumm/help.cpp:128 engines/scumm/help.cpp:152
-#: engines/scumm/help.cpp:170 engines/scumm/help.cpp:198
-#: engines/scumm/help.cpp:213 engines/scumm/help.cpp:224
-#: engines/scumm/help.cpp:250
+#: 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 "Usa"
-#: engines/scumm/help.cpp:129 engines/scumm/help.cpp:141
+#: engines/scumm/help.cpp:130 engines/scumm/help.cpp:142
msgid "Read"
msgstr "Leggi"
-#: engines/scumm/help.cpp:130 engines/scumm/help.cpp:147
+#: engines/scumm/help.cpp:131 engines/scumm/help.cpp:148
msgid "New kid"
msgstr "Cambia personaggio"
-#: engines/scumm/help.cpp:131 engines/scumm/help.cpp:153
-#: engines/scumm/help.cpp:171
+#: engines/scumm/help.cpp:132 engines/scumm/help.cpp:154
+#: engines/scumm/help.cpp:172
msgid "Turn on"
msgstr "Accendi"
-#: engines/scumm/help.cpp:132 engines/scumm/help.cpp:154
-#: engines/scumm/help.cpp:172
+#: engines/scumm/help.cpp:133 engines/scumm/help.cpp:155
+#: engines/scumm/help.cpp:173
msgid "Turn off"
msgstr "Spegni"
-#: engines/scumm/help.cpp:142 engines/scumm/help.cpp:167
-#: engines/scumm/help.cpp:194
+#: engines/scumm/help.cpp:143 engines/scumm/help.cpp:168
+#: engines/scumm/help.cpp:195
msgid "Walk to"
msgstr "Cammina verso"
-#: engines/scumm/help.cpp:143 engines/scumm/help.cpp:168
-#: engines/scumm/help.cpp:195 engines/scumm/help.cpp:210
-#: engines/scumm/help.cpp:227
+#: 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 "Raccogli"
-#: engines/scumm/help.cpp:144 engines/scumm/help.cpp:169
+#: engines/scumm/help.cpp:145 engines/scumm/help.cpp:170
msgid "What is"
msgstr "Che cos'ш"
-#: engines/scumm/help.cpp:146
+#: engines/scumm/help.cpp:147
msgid "Unlock"
msgstr "Apri"
-#: engines/scumm/help.cpp:149
+#: engines/scumm/help.cpp:150
msgid "Put on"
msgstr "Indossa"
-#: engines/scumm/help.cpp:150
+#: engines/scumm/help.cpp:151
msgid "Take off"
msgstr "Togli"
-#: engines/scumm/help.cpp:156
+#: engines/scumm/help.cpp:157
msgid "Fix"
msgstr "Ripara"
-#: engines/scumm/help.cpp:158
+#: engines/scumm/help.cpp:159
msgid "Switch"
msgstr "Sposta"
-#: engines/scumm/help.cpp:166 engines/scumm/help.cpp:228
+#: engines/scumm/help.cpp:167 engines/scumm/help.cpp:229
msgid "Look"
msgstr "Guarda"
-#: engines/scumm/help.cpp:173 engines/scumm/help.cpp:223
+#: engines/scumm/help.cpp:174 engines/scumm/help.cpp:224
msgid "Talk"
msgstr "Parla"
-#: engines/scumm/help.cpp:174
+#: engines/scumm/help.cpp:175
msgid "Travel"
msgstr "Viaggio"
-#: engines/scumm/help.cpp:175
+#: engines/scumm/help.cpp:176
msgid "To Henry / To Indy"
msgstr "A Henry / a Indy"
#. I18N: These are different musical notes
-#: engines/scumm/help.cpp:179
+#: engines/scumm/help.cpp:180
msgid "play C minor on distaff"
msgstr "suona Do (C) minore sul bastone"
-#: engines/scumm/help.cpp:180
+#: engines/scumm/help.cpp:181
msgid "play D on distaff"
msgstr "suona Re (D) sul bastone"
-#: engines/scumm/help.cpp:181
+#: engines/scumm/help.cpp:182
msgid "play E on distaff"
msgstr "suona Mi (E) sul bastone"
-#: engines/scumm/help.cpp:182
+#: engines/scumm/help.cpp:183
msgid "play F on distaff"
msgstr "suona Fa (F) sul bastone"
-#: engines/scumm/help.cpp:183
+#: engines/scumm/help.cpp:184
msgid "play G on distaff"
msgstr "suona Sol (G) sul bastone"
-#: engines/scumm/help.cpp:184
+#: engines/scumm/help.cpp:185
msgid "play A on distaff"
msgstr "suona La (A) sul bastone"
-#: engines/scumm/help.cpp:185
+#: engines/scumm/help.cpp:186
msgid "play B on distaff"
msgstr "suona Si (B) sul bastone"
-#: engines/scumm/help.cpp:186
+#: engines/scumm/help.cpp:187
msgid "play C major on distaff"
msgstr "suona Do (C) maggiore sul bastone"
-#: engines/scumm/help.cpp:192 engines/scumm/help.cpp:214
+#: engines/scumm/help.cpp:193 engines/scumm/help.cpp:215
msgid "puSh"
msgstr "Premi"
-#: engines/scumm/help.cpp:193 engines/scumm/help.cpp:215
+#: engines/scumm/help.cpp:194 engines/scumm/help.cpp:216
msgid "pull (Yank)"
msgstr "Tira"
-#: engines/scumm/help.cpp:196 engines/scumm/help.cpp:212
-#: engines/scumm/help.cpp:248
+#: engines/scumm/help.cpp:197 engines/scumm/help.cpp:213
+#: engines/scumm/help.cpp:249
msgid "Talk to"
msgstr "Parla con"
-#: engines/scumm/help.cpp:199 engines/scumm/help.cpp:211
+#: engines/scumm/help.cpp:200 engines/scumm/help.cpp:212
msgid "Look at"
msgstr "Esamina"
-#: engines/scumm/help.cpp:200
+#: engines/scumm/help.cpp:201
msgid "turn oN"
msgstr "Accendi"
-#: engines/scumm/help.cpp:201
+#: engines/scumm/help.cpp:202
msgid "turn oFf"
msgstr "Spegni"
-#: engines/scumm/help.cpp:217
+#: engines/scumm/help.cpp:218
msgid "KeyUp"
msgstr "Tasto su"
-#: engines/scumm/help.cpp:217
+#: engines/scumm/help.cpp:218
msgid "Highlight prev dialogue"
msgstr "Evidenzia dialogo precedente"
-#: engines/scumm/help.cpp:218
+#: engines/scumm/help.cpp:219
msgid "KeyDown"
msgstr "Tasto giљ"
-#: engines/scumm/help.cpp:218
+#: engines/scumm/help.cpp:219
msgid "Highlight next dialogue"
msgstr "Evidenzia dialogo successivo"
-#: engines/scumm/help.cpp:222
+#: engines/scumm/help.cpp:223
msgid "Walk"
msgstr "Cammina"
-#: engines/scumm/help.cpp:225 engines/scumm/help.cpp:234
-#: engines/scumm/help.cpp:241 engines/scumm/help.cpp:249
+#: engines/scumm/help.cpp:226 engines/scumm/help.cpp:235
+#: engines/scumm/help.cpp:242 engines/scumm/help.cpp:250
msgid "Inventory"
msgstr "Inventario"
-#: engines/scumm/help.cpp:226
+#: engines/scumm/help.cpp:227
msgid "Object"
msgstr "Oggetto"
-#: engines/scumm/help.cpp:229
+#: engines/scumm/help.cpp:230
msgid "Black and White / Color"
msgstr "Bianco e nero / colori"
-#: engines/scumm/help.cpp:232
+#: engines/scumm/help.cpp:233
msgid "Eyes"
msgstr "Occhi"
-#: engines/scumm/help.cpp:233
+#: engines/scumm/help.cpp:234
msgid "Tongue"
msgstr "Lingua"
-#: engines/scumm/help.cpp:235
+#: engines/scumm/help.cpp:236
msgid "Punch"
msgstr "Pugno"
-#: engines/scumm/help.cpp:236
+#: engines/scumm/help.cpp:237
msgid "Kick"
msgstr "Calcio"
-#: engines/scumm/help.cpp:239 engines/scumm/help.cpp:247
+#: engines/scumm/help.cpp:240 engines/scumm/help.cpp:248
msgid "Examine"
msgstr "Esamina"
-#: engines/scumm/help.cpp:240
+#: engines/scumm/help.cpp:241
msgid "Regular cursor"
msgstr "Cursore normale"
#. I18N: Comm is a communication device
-#: engines/scumm/help.cpp:243
+#: engines/scumm/help.cpp:244
msgid "Comm"
msgstr "Comm"
-#: engines/scumm/help.cpp:246
+#: engines/scumm/help.cpp:247
msgid "Save / Load / Options"
msgstr "Salva / Carica / Opzioni"
-#: engines/scumm/help.cpp:255
+#: engines/scumm/help.cpp:256
msgid "Other game controls:"
msgstr "Altre opzioni di gioco:"
-#: engines/scumm/help.cpp:257 engines/scumm/help.cpp:267
+#: engines/scumm/help.cpp:258 engines/scumm/help.cpp:268
msgid "Inventory:"
msgstr "Inventario:"
-#: engines/scumm/help.cpp:258 engines/scumm/help.cpp:274
+#: engines/scumm/help.cpp:259 engines/scumm/help.cpp:275
msgid "Scroll list up"
msgstr "Scorri lista verso l'alto"
-#: engines/scumm/help.cpp:259 engines/scumm/help.cpp:275
+#: engines/scumm/help.cpp:260 engines/scumm/help.cpp:276
msgid "Scroll list down"
msgstr "Scorri lista verso il basso"
-#: engines/scumm/help.cpp:260 engines/scumm/help.cpp:268
+#: engines/scumm/help.cpp:261 engines/scumm/help.cpp:269
msgid "Upper left item"
msgstr "Oggetto in alto a sinistra"
-#: engines/scumm/help.cpp:261 engines/scumm/help.cpp:270
+#: engines/scumm/help.cpp:262 engines/scumm/help.cpp:271
msgid "Lower left item"
msgstr "Oggetto in basso a sinistra"
-#: engines/scumm/help.cpp:262 engines/scumm/help.cpp:271
+#: engines/scumm/help.cpp:263 engines/scumm/help.cpp:272
msgid "Upper right item"
msgstr "Oggetto in alto a destra"
-#: engines/scumm/help.cpp:263 engines/scumm/help.cpp:273
+#: engines/scumm/help.cpp:264 engines/scumm/help.cpp:274
msgid "Lower right item"
msgstr "Oggetto in basso a destra"
-#: engines/scumm/help.cpp:269
+#: engines/scumm/help.cpp:270
msgid "Middle left item"
msgstr "Oggetto al centro a sinistra"
-#: engines/scumm/help.cpp:272
+#: engines/scumm/help.cpp:273
msgid "Middle right item"
msgstr "Oggetto al centro a destra"
-#: engines/scumm/help.cpp:279 engines/scumm/help.cpp:284
+#: engines/scumm/help.cpp:280 engines/scumm/help.cpp:285
msgid "Switching characters:"
msgstr "Cambio personaggio:"
-#: engines/scumm/help.cpp:281
+#: engines/scumm/help.cpp:282
msgid "Second kid"
msgstr "Secondo ragazzo"
-#: engines/scumm/help.cpp:282
+#: engines/scumm/help.cpp:283
msgid "Third kid"
msgstr "Terzo ragazzo"
-#: engines/scumm/help.cpp:294
+#: engines/scumm/help.cpp:292
+#, fuzzy
+msgid "Toggle Inventory/IQ Points display"
+msgstr "Mostra/nascondi schermo centrale dati"
+
+#: engines/scumm/help.cpp:293
+msgid "Toggle Keyboard/Mouse Fighting (*)"
+msgstr ""
+
+#: engines/scumm/help.cpp:295
+msgid "* Keyboard Fighting is always on,"
+msgstr ""
+
+#: engines/scumm/help.cpp:296
+msgid " so despite the in-game message this"
+msgstr ""
+
+#: engines/scumm/help.cpp:297
+msgid " actually toggles Mouse Fighting Off/On"
+msgstr ""
+
+#: engines/scumm/help.cpp:304
msgid "Fighting controls (numpad):"
msgstr "Controlli di combattimento (tastierino numerico):"
-#: engines/scumm/help.cpp:295 engines/scumm/help.cpp:296
-#: engines/scumm/help.cpp:297
+#: engines/scumm/help.cpp:305 engines/scumm/help.cpp:306
+#: engines/scumm/help.cpp:307
msgid "Step back"
msgstr "Passo indietro"
-#: engines/scumm/help.cpp:298
+#: engines/scumm/help.cpp:308
msgid "Block high"
msgstr "Para in alto"
-#: engines/scumm/help.cpp:299
+#: engines/scumm/help.cpp:309
msgid "Block middle"
msgstr "Para al centro"
-#: engines/scumm/help.cpp:300
+#: engines/scumm/help.cpp:310
msgid "Block low"
msgstr "Para in basso"
-#: engines/scumm/help.cpp:301
+#: engines/scumm/help.cpp:311
msgid "Punch high"
msgstr "Colpisci in alto"
-#: engines/scumm/help.cpp:302
+#: engines/scumm/help.cpp:312
msgid "Punch middle"
msgstr "Colpisci al centro"
-#: engines/scumm/help.cpp:303
+#: engines/scumm/help.cpp:313
msgid "Punch low"
msgstr "Colpisci in basso"
-#: engines/scumm/help.cpp:306
+#: engines/scumm/help.cpp:315
+msgid "Sucker punch"
+msgstr ""
+
+#: engines/scumm/help.cpp:318
msgid "These are for Indy on left."
msgstr "Questi sono i controlli quando"
-#: engines/scumm/help.cpp:307
+#: engines/scumm/help.cpp:319
msgid "When Indy is on the right,"
msgstr "Indy ш sulla sinistra. Quando ш"
-#: engines/scumm/help.cpp:308
+#: engines/scumm/help.cpp:320
msgid "7, 4, and 1 are switched with"
msgstr "sulla destra, 7, 4 e 1 sostituiscono"
-#: engines/scumm/help.cpp:309
+#: engines/scumm/help.cpp:321
msgid "9, 6, and 3, respectively."
msgstr "rispettivamente 9, 6 e 3."
-#: engines/scumm/help.cpp:316
+#: engines/scumm/help.cpp:328
msgid "Biplane controls (numpad):"
msgstr "Controlli biplano (tastierino numerico):"
-#: engines/scumm/help.cpp:317
+#: engines/scumm/help.cpp:329
msgid "Fly to upper left"
msgstr "Vola in alto a sinistra"
-#: engines/scumm/help.cpp:318
+#: engines/scumm/help.cpp:330
msgid "Fly to left"
msgstr "Vola a sinistra"
-#: engines/scumm/help.cpp:319
+#: engines/scumm/help.cpp:331
msgid "Fly to lower left"
msgstr "Vola in basso a sinistra"
-#: engines/scumm/help.cpp:320
+#: engines/scumm/help.cpp:332
msgid "Fly upwards"
msgstr "Vola in alto"
-#: engines/scumm/help.cpp:321
+#: engines/scumm/help.cpp:333
msgid "Fly straight"
msgstr "Vola diritto"
-#: engines/scumm/help.cpp:322
+#: engines/scumm/help.cpp:334
msgid "Fly down"
msgstr "Vola in basso"
-#: engines/scumm/help.cpp:323
+#: engines/scumm/help.cpp:335
msgid "Fly to upper right"
msgstr "Vola in alto a destra"
-#: engines/scumm/help.cpp:324
+#: engines/scumm/help.cpp:336
msgid "Fly to right"
msgstr "Vola a destra"
-#: engines/scumm/help.cpp:325
+#: engines/scumm/help.cpp:337
msgid "Fly to lower right"
msgstr "Vola in basso a destra"
-#: engines/scumm/scumm.cpp:1823
+#: engines/scumm/scumm.cpp:1832
#, c-format
msgid ""
"Native MIDI support requires the Roland Upgrade from LucasArts,\n"
@@ -3194,11 +3284,12 @@ msgstr ""
"Il supporto nativo MIDI richiede il Roland Upgrade della LucasArts,\n"
"ma %s non ш presente. Verrр usato AdLib."
-#: engines/scumm/scumm.cpp:2594
+#: engines/scumm/scumm.cpp:2644
+#, fuzzy
msgid ""
-"Usually, Maniac Mansion would start now. But ScummVM doesn't do that yet. To "
-"play it, go to 'Add Game' in the ScummVM start menu and select the 'Maniac' "
-"directory inside the Tentacle game directory."
+"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 ""
"Originariamente, a questo punto dovrebbe partire Maniac Mansion. Ma ScummVM "
"non lo puђ ancora fare. Per giocarci, vai a \"Aggiungi gioco\" nel menu "
@@ -3340,6 +3431,48 @@ msgstr ""
msgid "Show the current number of frames per second in the upper left corner"
msgstr ""
+#: engines/zvision/detection.cpp:256
+msgid "Double FPS"
+msgstr ""
+
+#: engines/zvision/detection.cpp:257
+msgid "Increase game FPS from 30 to 60"
+msgstr ""
+
+#: engines/zvision/detection.cpp:266
+#, fuzzy
+msgid "Enable Venus"
+msgstr "Attiva la modalitр elio"
+
+#: engines/zvision/detection.cpp:267
+msgid "Enable the Venus help system"
+msgstr ""
+
+#: engines/zvision/detection.cpp:276
+msgid "Disable animation while turning"
+msgstr ""
+
+#: engines/zvision/detection.cpp:277
+msgid "Disable animation while turning in panoramic mode"
+msgstr ""
+
+#: engines/zvision/detection.cpp:286
+msgid "Use the hires MPEG movies"
+msgstr ""
+
+#: engines/zvision/detection.cpp:287
+#, fuzzy
+msgid ""
+"Use the hires MPEG movies of the DVD version, instead of the lowres AVI ones"
+msgstr ""
+"Usa il set alternativo di cursori d'argento al posto di quelli normali d'oro"
+
+#~ msgid "EGA undithering"
+#~ msgstr "Undithering EGA"
+
+#~ msgid "Enable undithering in EGA games"
+#~ msgstr "Attiva undithering nei giochi EGA"
+
#~ msgid "MPEG-2 cutscenes found but ScummVM has been built without MPEG-2"
#~ msgstr ""
#~ "Sono state trovare scene di intermezzo MPEG-2 ma ScummVM ш stato "
@@ -3349,9 +3482,6 @@ msgstr ""
#~ msgid "Mass Add..."
#~ msgstr "Agg. massa..."
-#~ msgid "Mass Add..."
-#~ msgstr "Agg. in massa..."
-
#~ msgid ""
#~ "Turns off General MIDI mapping for games with Roland MT-32 soundtrack"
#~ msgstr ""
diff --git a/po/nb_NO.po b/po/nb_NO.po
index fe04c50aca..1c73957a54 100644
--- a/po/nb_NO.po
+++ b/po/nb_NO.po
@@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: ScummVM 1.3.0svn\n"
"Report-Msgid-Bugs-To: scummvm-devel@lists.sf.net\n"
-"POT-Creation-Date: 2014-10-04 00:58+0100\n"
+"POT-Creation-Date: 2015-06-30 20:57+0100\n"
"PO-Revision-Date: 2014-07-11 00:02+0100\n"
"Last-Translator: Einar Johan Trјan Sјmхen <einarjohants@gmail.com>\n"
"Language-Team: somaen <einarjohants@gmail.com>\n"
@@ -55,10 +55,11 @@ msgstr "Oppover"
#: gui/browser.cpp:75 gui/chooser.cpp:46 gui/KeysDialog.cpp:43
#: gui/launcher.cpp:351 gui/massadd.cpp:95 gui/options.cpp:1239
+#: gui/recorderdialog.cpp:70 gui/recorderdialog.cpp:156
#: gui/saveload-dialog.cpp:216 gui/saveload-dialog.cpp:276
-#: gui/saveload-dialog.cpp:547 gui/saveload-dialog.cpp:922
+#: gui/saveload-dialog.cpp:547 gui/saveload-dialog.cpp:931
#: gui/themebrowser.cpp:55 gui/fluidsynth-dialog.cpp:152
-#: engines/engine.cpp:452 backends/platform/wii/options.cpp:48
+#: engines/engine.cpp:483 backends/platform/wii/options.cpp:48
#: backends/events/default/default-events.cpp:196
#: backends/events/default/default-events.cpp:218
#: engines/drascula/saveload.cpp:49 engines/parallaction/saveload.cpp:274
@@ -71,9 +72,9 @@ msgid "Choose"
msgstr "Velg"
#: gui/gui-manager.cpp:117 backends/keymapper/remap-dialog.cpp:53
-#: 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
+#: 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"
@@ -89,7 +90,7 @@ msgstr "Vis tastatur"
msgid "Remap keys"
msgstr "Omkoble taster"
-#: gui/gui-manager.cpp:131 base/main.cpp:326 engines/scumm/help.cpp:86
+#: gui/gui-manager.cpp:131 base/main.cpp:326 engines/scumm/help.cpp:87
msgid "Toggle fullscreen"
msgstr "Veksle fullskjerm"
@@ -103,13 +104,13 @@ 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:1240
-#: gui/saveload-dialog.cpp:923 gui/fluidsynth-dialog.cpp:153
-#: engines/engine.cpp:371 engines/engine.cpp:382
+#: 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:399 engines/parallaction/saveload.cpp:274
-#: engines/scumm/dialogs.cpp:193 engines/scumm/scumm.cpp:1825
+#: 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
@@ -479,7 +480,7 @@ msgstr ""
#: gui/launcher.cpp:793 gui/launcher.cpp:941 gui/launcher.cpp:1000
#: gui/fluidsynth-dialog.cpp:217
-#: backends/events/symbiansdl/symbiansdl-events.cpp:184
+#: 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
@@ -489,7 +490,7 @@ 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:184
+#: 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
@@ -526,6 +527,14 @@ 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
+msgid "Mass Add..."
+msgstr "Legg til flere..."
+
+#: gui/launcher.cpp:1161
+msgid "Record..."
+msgstr ""
+
#: gui/massadd.cpp:79 gui/massadd.cpp:82
msgid "... progress ..."
msgstr "... fremdrift ..."
@@ -626,7 +635,7 @@ msgid "Special dithering modes supported by some games"
msgstr "Spesiel dithering-modus stјttet av enkelte spill"
#: gui/options.cpp:760
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2249
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2298
msgid "Fullscreen mode"
msgstr "Fullskjermsmodus"
@@ -938,6 +947,43 @@ msgstr ""
"Temaet du valgte stјtter ikke det aktive sprхket. Hvis du vil bruke dette "
"temaet, mх du bytte til et annet sprхk fјrst."
+#: gui/recorderdialog.cpp:64
+msgid "Recorder or Playback Gameplay"
+msgstr ""
+
+#: gui/recorderdialog.cpp:69 gui/recorderdialog.cpp:156
+#: gui/saveload-dialog.cpp:220 gui/saveload-dialog.cpp:276
+msgid "Delete"
+msgstr "Slett"
+
+#: gui/recorderdialog.cpp:71
+msgid "Record"
+msgstr ""
+
+#: gui/recorderdialog.cpp:72
+#, fuzzy
+msgid "Playback"
+msgstr "Spill"
+
+#: gui/recorderdialog.cpp:74
+msgid "Edit"
+msgstr ""
+
+#: gui/recorderdialog.cpp:86 gui/recorderdialog.cpp:243
+#: gui/recorderdialog.cpp:253
+msgid "Author: "
+msgstr ""
+
+#: gui/recorderdialog.cpp:87 gui/recorderdialog.cpp:244
+#: gui/recorderdialog.cpp:254
+msgid "Notes: "
+msgstr ""
+
+#: gui/recorderdialog.cpp:155
+#, fuzzy
+msgid "Do you really want to delete this record?"
+msgstr "Vil du virkelig slette dette lagrede spillet?"
+
#: gui/saveload-dialog.cpp:167
msgid "List view"
msgstr "Listevisning"
@@ -958,23 +1004,19 @@ msgstr "Ingen tid lagret"
msgid "No playtime saved"
msgstr "Ingen spilltid lagret"
-#: gui/saveload-dialog.cpp:220 gui/saveload-dialog.cpp:276
-msgid "Delete"
-msgstr "Slett"
-
#: gui/saveload-dialog.cpp:275
msgid "Do you really want to delete this saved game?"
msgstr "Vil du virkelig slette dette lagrede spillet?"
-#: gui/saveload-dialog.cpp:385 gui/saveload-dialog.cpp:875
+#: gui/saveload-dialog.cpp:385 gui/saveload-dialog.cpp:884
msgid "Date: "
msgstr "Dato: "
-#: gui/saveload-dialog.cpp:389 gui/saveload-dialog.cpp:881
+#: gui/saveload-dialog.cpp:389 gui/saveload-dialog.cpp:890
msgid "Time: "
msgstr "Tid: "
-#: gui/saveload-dialog.cpp:395 gui/saveload-dialog.cpp:889
+#: gui/saveload-dialog.cpp:395 gui/saveload-dialog.cpp:898
msgid "Playtime: "
msgstr "Spilltid: "
@@ -990,19 +1032,19 @@ msgstr "Neste"
msgid "Prev"
msgstr "Forrige"
-#: gui/saveload-dialog.cpp:739
+#: gui/saveload-dialog.cpp:748
msgid "New Save"
msgstr "Nytt lagret spill"
-#: gui/saveload-dialog.cpp:739
+#: gui/saveload-dialog.cpp:748
msgid "Create a new save game"
msgstr "Opprett ett nytt lagret spill."
-#: gui/saveload-dialog.cpp:868
+#: gui/saveload-dialog.cpp:877
msgid "Name: "
msgstr "Navn:"
-#: gui/saveload-dialog.cpp:940
+#: gui/saveload-dialog.cpp:949
#, c-format
msgid "Enter a description for slot %d:"
msgstr "Gi en beskrivelse for posisjon %d:"
@@ -1154,7 +1196,7 @@ msgstr "Hopp over linje"
msgid "Error running game:"
msgstr "Problem ved kjјring av spill:"
-#: base/main.cpp:536
+#: base/main.cpp:554
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"
@@ -1272,7 +1314,7 @@ 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:758
+#: engines/pegasus/pegasus.cpp:377 engines/sci/engine/kfile.cpp:759
#: engines/toltecs/menu.cpp:281 engines/tsage/scenes.cpp:598
msgid "Save game:"
msgstr "Lagret spill:"
@@ -1285,7 +1327,7 @@ msgstr "Lagret spill:"
#: 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:758 engines/scumm/dialogs.cpp:188
+#: engines/sci/engine/kfile.cpp:759 engines/scumm/dialogs.cpp:188
#: engines/toltecs/menu.cpp:281 engines/tsage/scenes.cpp:598
msgid "Save"
msgstr "Lagre"
@@ -1323,23 +1365,23 @@ msgstr "~A~vbryt"
msgid "~K~eys"
msgstr "~T~aster"
-#: engines/engine.cpp:245
+#: engines/engine.cpp:276
msgid "Could not initialize color format."
msgstr "Kunne ikke initalisere fargeformat."
-#: engines/engine.cpp:253
+#: engines/engine.cpp:284
msgid "Could not switch to video mode: '"
msgstr "Kunne ikke veksle til videomodus: '"
-#: engines/engine.cpp:262
+#: engines/engine.cpp:293
msgid "Could not apply aspect ratio setting."
msgstr "Kunne ikke aktivere aspektrate-innstilling."
-#: engines/engine.cpp:267
+#: engines/engine.cpp:298
msgid "Could not apply fullscreen setting."
msgstr "Kunne ikke aktivere fullskjermsinnstilling."
-#: engines/engine.cpp:367
+#: engines/engine.cpp:398
msgid ""
"You appear to be playing this game directly\n"
"from the CD. This is known to cause problems,\n"
@@ -1353,7 +1395,7 @@ msgstr ""
"datafilene til harddisken din istedet.\n"
"Se README-filen for detaljer."
-#: engines/engine.cpp:378
+#: engines/engine.cpp:409
msgid ""
"This game has audio tracks in its disk. These\n"
"tracks need to be ripped from the disk using\n"
@@ -1367,7 +1409,7 @@ msgstr ""
"kunne hјre pх spillets musikk.\n"
"Se README-filen for detaljer."
-#: engines/engine.cpp:436
+#: engines/engine.cpp:467
#, c-format
msgid ""
"Gamestate load failed (%s)! Please consult the README for basic information, "
@@ -1376,7 +1418,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:449
+#: engines/engine.cpp:480
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 "
@@ -1386,7 +1428,7 @@ 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:452
+#: engines/engine.cpp:483
msgid "Start anyway"
msgstr "Start allikevel"
@@ -1596,11 +1638,11 @@ msgstr "Touchpad-modus aktivert."
msgid "Touchpad mode disabled."
msgstr "Touchpad-modus deaktivert."
-#: backends/platform/maemo/maemo.cpp:209
+#: backends/platform/maemo/maemo.cpp:208
msgid "Click Mode"
msgstr "Klikkmodus"
-#: backends/platform/maemo/maemo.cpp:215
+#: backends/platform/maemo/maemo.cpp:214
#: backends/platform/symbian/src/SymbianActions.cpp:42
#: backends/platform/wince/CEActionsPocket.cpp:60
#: backends/platform/wince/CEActionsSmartphone.cpp:43
@@ -1608,11 +1650,11 @@ msgstr "Klikkmodus"
msgid "Left Click"
msgstr "Venstreklikk"
-#: backends/platform/maemo/maemo.cpp:218
+#: backends/platform/maemo/maemo.cpp:217
msgid "Middle Click"
msgstr "Midtklikk"
-#: backends/platform/maemo/maemo.cpp:221
+#: 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
@@ -1649,19 +1691,19 @@ msgctxt "lowres"
msgid "Normal (no scaling)"
msgstr "Normal (ingen skalering)"
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2148
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2197
msgid "Enabled aspect ratio correction"
msgstr "Aspekt-rate korrigering aktivert"
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2154
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2203
msgid "Disabled aspect ratio correction"
msgstr "Aspekt-rate korrigering deaktivert"
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2209
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2258
msgid "Active graphics filter:"
msgstr "Aktivt grafikkfilter:"
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2251
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2300
msgid "Windowed mode"
msgstr "Vindusmodus"
@@ -1720,8 +1762,8 @@ msgstr "Rask modus"
#: 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:82
-#: engines/scumm/help.cpp:84
+#: engines/scumm/dialogs.cpp:192 engines/scumm/help.cpp:83
+#: engines/scumm/help.cpp:85
msgid "Quit"
msgstr "Avslutt"
@@ -1741,7 +1783,7 @@ msgstr "Virtuelt tastatur"
msgid "Key mapper"
msgstr "Tastkobler"
-#: backends/events/symbiansdl/symbiansdl-events.cpp:184
+#: backends/events/symbiansdl/symbiansdl-events.cpp:186
msgid "Do you want to quit ?"
msgstr "Vil du avslutte?"
@@ -2077,33 +2119,54 @@ msgstr "Klikking aktivert"
msgid "Clicking Disabled"
msgstr "Klikking deaktivert"
-#: engines/agi/detection.cpp:142 engines/drascula/detection.cpp:302
+#: 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.cpp:103
+#: engines/zvision/detection.cpp:246
msgid "Use original save/load screens"
msgstr "Bruk originale lagre/laste-skjermer"
-#: engines/agi/detection.cpp:143 engines/drascula/detection.cpp:303
+#: 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/zvision/detection.cpp:104
+#: engines/zvision/detection.cpp:247
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)"
+
+#: engines/agi/detection.cpp:158
+msgid ""
+"Use an alternative palette, common for all Amiga games. This was the old "
+"behavior"
+msgstr ""
+
+#: engines/agi/detection.cpp:167
+#, fuzzy
+msgid "Mouse support"
+msgstr "Hopp over"
+
+#: 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:857 engines/toltecs/menu.cpp:256
+#: engines/sci/engine/kfile.cpp:858 engines/toltecs/menu.cpp:256
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:857 engines/toltecs/menu.cpp:256
+#: engines/sci/engine/kfile.cpp:858 engines/toltecs/menu.cpp:256
msgid "Restore"
msgstr "Gjenopprett"
-#: engines/agos/saveload.cpp:160 engines/scumm/scumm.cpp:2368
+#: engines/agos/saveload.cpp:160 engines/scumm/scumm.cpp:2377
#, c-format
msgid ""
"Failed to load game state from file:\n"
@@ -2114,7 +2177,7 @@ msgstr ""
"\n"
"%s"
-#: engines/agos/saveload.cpp:195 engines/scumm/scumm.cpp:2361
+#: engines/agos/saveload.cpp:195 engines/scumm/scumm.cpp:2370
#, c-format
msgid ""
"Failed to save game state to file:\n"
@@ -2125,7 +2188,7 @@ msgstr ""
"\n"
"%s"
-#: engines/agos/saveload.cpp:203 engines/scumm/scumm.cpp:2379
+#: engines/agos/saveload.cpp:203 engines/scumm/scumm.cpp:2388
#, c-format
msgid ""
"Successfully saved game state in file:\n"
@@ -2141,12 +2204,12 @@ msgstr ""
msgid "Cutscene file '%s' not found!"
msgstr "Fant ikke cutscenefil '%s'!"
-#: engines/cge/detection.cpp:105 engines/cge2/detection.cpp:81
+#: engines/cge/detection.cpp:105 engines/cge2/detection.cpp:101
#, fuzzy
msgid "Color Blind Mode"
msgstr "Klikkmodus"
-#: engines/cge/detection.cpp:106 engines/cge2/detection.cpp:82
+#: engines/cge/detection.cpp:106 engines/cge2/detection.cpp:102
msgid "Enable Color Blind Mode by default"
msgstr ""
@@ -2198,7 +2261,7 @@ msgstr "Rask filmhastighet"
msgid "Play movies at an increased speed"
msgstr "Spill filmer med јkt hastighet"
-#: engines/groovie/script.cpp:399
+#: engines/groovie/script.cpp:408
msgid "Failed to save game"
msgstr "Klarte ikke х lagre spill."
@@ -2497,12 +2560,12 @@ msgid "Use an alternative game intro (CD version only)"
msgstr "Bruk en alternativ intro (Kun for CD-versjon)"
#: engines/sci/detection.cpp:374
-msgid "EGA undithering"
-msgstr "EGA av-dithering"
+msgid "Skip EGA dithering pass (full color backgrounds)"
+msgstr ""
#: engines/sci/detection.cpp:375
-msgid "Enable undithering in EGA games"
-msgstr "Aktiver av-dithering i EGA-spill"
+msgid "Skip dithering pass in EGA games, graphics are shown with full colors"
+msgstr ""
#: engines/sci/detection.cpp:384
msgid "Prefer digital sound effects"
@@ -2574,12 +2637,14 @@ msgstr "Spill pauset. Trykk pх MELLOMROMstasten for х fortsette."
#. "Moechten Sie wirklich neu starten? (J/N)J"
#. Will react to J as 'Yes'
#: engines/scumm/dialogs.cpp:183
-msgid "Are you sure you want to restart? (Y/N)"
+#, fuzzy
+msgid "Are you sure you want to restart? (Y/N)Y"
msgstr "Er du sikker pх at du vil avslutte? (Y/N)"
#. I18N: you may specify 'Yes' symbol at the end of the line. See previous comment
#: engines/scumm/dialogs.cpp:185
-msgid "Are you sure you want to quit? (Y/N)"
+#, fuzzy
+msgid "Are you sure you want to quit? (Y/N)Y"
msgstr "Er du sikker pх at du vil avslutte? (Y/N)"
#: engines/scumm/dialogs.cpp:190
@@ -2667,516 +2732,540 @@ msgstr "Trening"
msgid "Expert"
msgstr "Ekspert"
-#: engines/scumm/help.cpp:73
+#: engines/scumm/help.cpp:74
msgid "Common keyboard commands:"
msgstr "Vanlige tastaturkommandoer:"
-#: engines/scumm/help.cpp:74
+#: engines/scumm/help.cpp:75
msgid "Save / Load dialog"
msgstr "Lagre- / хpne-dialog"
-#: engines/scumm/help.cpp:76
+#: engines/scumm/help.cpp:77
msgid "Skip line of text"
msgstr "Hopp over tekstlinje"
-#: engines/scumm/help.cpp:77
+#: engines/scumm/help.cpp:78
msgid "Esc"
msgstr "Esc"
-#: engines/scumm/help.cpp:77
+#: engines/scumm/help.cpp:78
msgid "Skip cutscene"
msgstr "Hopp over cutscene"
-#: engines/scumm/help.cpp:78
+#: engines/scumm/help.cpp:79
msgid "Space"
msgstr "Space"
-#: engines/scumm/help.cpp:78
+#: engines/scumm/help.cpp:79
msgid "Pause game"
msgstr "Pause spill"
-#: engines/scumm/help.cpp:79 engines/scumm/help.cpp:84
-#: engines/scumm/help.cpp:95 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: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:79
+#: engines/scumm/help.cpp:80
msgid "Load game state 1-10"
msgstr "Хpne spilltilstand 1-10"
-#: engines/scumm/help.cpp:80 engines/scumm/help.cpp:84
-#: engines/scumm/help.cpp:86 engines/scumm/help.cpp:100
-#: engines/scumm/help.cpp:101 engines/scumm/help.cpp:102
+#: 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:80
+#: engines/scumm/help.cpp:81
msgid "Save game state 1-10"
msgstr "Lagre spilltilstand 1-10"
-#: engines/scumm/help.cpp:86 engines/scumm/help.cpp:89
+#: engines/scumm/help.cpp:87 engines/scumm/help.cpp:90
msgid "Enter"
msgstr "Enter"
-#: engines/scumm/help.cpp:87
+#: engines/scumm/help.cpp:88
msgid "Music volume up / down"
msgstr "Musikkvolum opp/ned"
-#: engines/scumm/help.cpp:88
+#: engines/scumm/help.cpp:89
msgid "Text speed slower / faster"
msgstr "Tekstfart saktere/raskere"
-#: engines/scumm/help.cpp:89
+#: engines/scumm/help.cpp:90
msgid "Simulate left mouse button"
msgstr "Simuler venstre mustast"
-#: engines/scumm/help.cpp:90
+#: engines/scumm/help.cpp:91
msgid "Tab"
msgstr "Tab"
-#: engines/scumm/help.cpp:90
+#: engines/scumm/help.cpp:91
msgid "Simulate right mouse button"
msgstr "Simuler hјyre mustast"
-#: engines/scumm/help.cpp:93
+#: engines/scumm/help.cpp:94
msgid "Special keyboard commands:"
msgstr "Spesielle tastaturkommandoer:"
-#: engines/scumm/help.cpp:94
+#: engines/scumm/help.cpp:95
msgid "Show / Hide console"
msgstr "Vis / Skjul konsollen"
-#: engines/scumm/help.cpp:95
+#: engines/scumm/help.cpp:96
msgid "Start the debugger"
msgstr "Start debuggeren"
-#: engines/scumm/help.cpp:96
+#: engines/scumm/help.cpp:97
msgid "Show memory consumption"
msgstr "Vis minneforbruk"
-#: engines/scumm/help.cpp:97
+#: engines/scumm/help.cpp:98
msgid "Run in fast mode (*)"
msgstr "Kjјr i rask modus (*)"
-#: engines/scumm/help.cpp:98
+#: engines/scumm/help.cpp:99
msgid "Run in really fast mode (*)"
msgstr "Kjјr i virkelig rask modus (*)"
-#: engines/scumm/help.cpp:99
+#: engines/scumm/help.cpp:100
msgid "Toggle mouse capture"
msgstr "Veksle muslхsing"
-#: engines/scumm/help.cpp:100
+#: engines/scumm/help.cpp:101
msgid "Switch between graphics filters"
msgstr "Bytt grafikkfiltre"
-#: engines/scumm/help.cpp:101
+#: engines/scumm/help.cpp:102
msgid "Increase / Decrease scale factor"
msgstr "иk / Minsk skaleringsfaktor"
-#: engines/scumm/help.cpp:102
+#: engines/scumm/help.cpp:103
msgid "Toggle aspect-ratio correction"
msgstr "Veksle aspekt-rate korrigering"
-#: engines/scumm/help.cpp:107
+#: engines/scumm/help.cpp:108
msgid "* Note that using ctrl-f and"
msgstr "* Merk at х bruke ctrl-f og"
-#: engines/scumm/help.cpp:108
+#: engines/scumm/help.cpp:109
msgid " ctrl-g are not recommended"
msgstr " ctrl-g anbefales ikke, siden"
-#: engines/scumm/help.cpp:109
+#: engines/scumm/help.cpp:110
msgid " since they may cause crashes"
msgstr " de kan forхrsake krцsj, eller"
-#: engines/scumm/help.cpp:110
+#: engines/scumm/help.cpp:111
msgid " or incorrect game behavior."
msgstr " eller feilaktig spilloppfјrsel."
-#: engines/scumm/help.cpp:114
+#: engines/scumm/help.cpp:115
msgid "Spinning drafts on the keyboard:"
msgstr "Spinne drafts pх tastaturet:"
-#: engines/scumm/help.cpp:116
+#: engines/scumm/help.cpp:117
msgid "Main game controls:"
msgstr "Hovedkontroller for spill:"
-#: engines/scumm/help.cpp:121 engines/scumm/help.cpp:136
-#: engines/scumm/help.cpp:161
+#: engines/scumm/help.cpp:122 engines/scumm/help.cpp:137
+#: engines/scumm/help.cpp:162
msgid "Push"
msgstr "Dytt"
-#: engines/scumm/help.cpp:122 engines/scumm/help.cpp:137
-#: engines/scumm/help.cpp:162
+#: engines/scumm/help.cpp:123 engines/scumm/help.cpp:138
+#: engines/scumm/help.cpp:163
msgid "Pull"
msgstr "Dra"
-#: engines/scumm/help.cpp:123 engines/scumm/help.cpp:138
-#: engines/scumm/help.cpp:163 engines/scumm/help.cpp:197
-#: engines/scumm/help.cpp:207
+#: 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 "Gi"
-#: engines/scumm/help.cpp:124 engines/scumm/help.cpp:139
-#: engines/scumm/help.cpp:164 engines/scumm/help.cpp:190
-#: engines/scumm/help.cpp:208
+#: 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 "Хpne"
-#: engines/scumm/help.cpp:126
+#: engines/scumm/help.cpp:127
msgid "Go to"
msgstr "Gх til"
-#: engines/scumm/help.cpp:127
+#: engines/scumm/help.cpp:128
msgid "Get"
msgstr "Fх"
-#: engines/scumm/help.cpp:128 engines/scumm/help.cpp:152
-#: engines/scumm/help.cpp:170 engines/scumm/help.cpp:198
-#: engines/scumm/help.cpp:213 engines/scumm/help.cpp:224
-#: engines/scumm/help.cpp:250
+#: 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 "Bruk"
-#: engines/scumm/help.cpp:129 engines/scumm/help.cpp:141
+#: engines/scumm/help.cpp:130 engines/scumm/help.cpp:142
msgid "Read"
msgstr "Les"
-#: engines/scumm/help.cpp:130 engines/scumm/help.cpp:147
+#: engines/scumm/help.cpp:131 engines/scumm/help.cpp:148
msgid "New kid"
msgstr "Bytt unge"
-#: engines/scumm/help.cpp:131 engines/scumm/help.cpp:153
-#: engines/scumm/help.cpp:171
+#: engines/scumm/help.cpp:132 engines/scumm/help.cpp:154
+#: engines/scumm/help.cpp:172
msgid "Turn on"
msgstr "Slх pх"
-#: engines/scumm/help.cpp:132 engines/scumm/help.cpp:154
-#: engines/scumm/help.cpp:172
+#: engines/scumm/help.cpp:133 engines/scumm/help.cpp:155
+#: engines/scumm/help.cpp:173
msgid "Turn off"
msgstr "Slх av"
-#: engines/scumm/help.cpp:142 engines/scumm/help.cpp:167
-#: engines/scumm/help.cpp:194
+#: engines/scumm/help.cpp:143 engines/scumm/help.cpp:168
+#: engines/scumm/help.cpp:195
msgid "Walk to"
msgstr "Gх til"
-#: engines/scumm/help.cpp:143 engines/scumm/help.cpp:168
-#: engines/scumm/help.cpp:195 engines/scumm/help.cpp:210
-#: engines/scumm/help.cpp:227
+#: 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 "Plukk opp"
-#: engines/scumm/help.cpp:144 engines/scumm/help.cpp:169
+#: engines/scumm/help.cpp:145 engines/scumm/help.cpp:170
msgid "What is"
msgstr "Hva er"
-#: engines/scumm/help.cpp:146
+#: engines/scumm/help.cpp:147
msgid "Unlock"
msgstr "Lхs opp"
-#: engines/scumm/help.cpp:149
+#: engines/scumm/help.cpp:150
msgid "Put on"
msgstr "Ta pх tјy"
-#: engines/scumm/help.cpp:150
+#: engines/scumm/help.cpp:151
msgid "Take off"
msgstr "Ta av tјy"
-#: engines/scumm/help.cpp:156
+#: engines/scumm/help.cpp:157
msgid "Fix"
msgstr "Fiks"
-#: engines/scumm/help.cpp:158
+#: engines/scumm/help.cpp:159
msgid "Switch"
msgstr "Bytt"
-#: engines/scumm/help.cpp:166 engines/scumm/help.cpp:228
+#: engines/scumm/help.cpp:167 engines/scumm/help.cpp:229
msgid "Look"
msgstr "Kikk"
-#: engines/scumm/help.cpp:173 engines/scumm/help.cpp:223
+#: engines/scumm/help.cpp:174 engines/scumm/help.cpp:224
msgid "Talk"
msgstr "Snakk"
-#: engines/scumm/help.cpp:174
+#: engines/scumm/help.cpp:175
msgid "Travel"
msgstr "Reis"
-#: engines/scumm/help.cpp:175
+#: engines/scumm/help.cpp:176
msgid "To Henry / To Indy"
msgstr "Til Henry / Til Indy"
#. I18N: These are different musical notes
-#: engines/scumm/help.cpp:179
+#: engines/scumm/help.cpp:180
msgid "play C minor on distaff"
msgstr "Spill C moll pх distaffen"
-#: engines/scumm/help.cpp:180
+#: engines/scumm/help.cpp:181
msgid "play D on distaff"
msgstr "spill D pх distaffen"
-#: engines/scumm/help.cpp:181
+#: engines/scumm/help.cpp:182
msgid "play E on distaff"
msgstr "spill E pх distaffen"
-#: engines/scumm/help.cpp:182
+#: engines/scumm/help.cpp:183
msgid "play F on distaff"
msgstr "spill F pх distaffen"
-#: engines/scumm/help.cpp:183
+#: engines/scumm/help.cpp:184
msgid "play G on distaff"
msgstr "spill G pх distaffen"
-#: engines/scumm/help.cpp:184
+#: engines/scumm/help.cpp:185
msgid "play A on distaff"
msgstr "spill A pх distaffen"
-#: engines/scumm/help.cpp:185
+#: engines/scumm/help.cpp:186
msgid "play B on distaff"
msgstr "spill H pх distaffen"
-#: engines/scumm/help.cpp:186
+#: engines/scumm/help.cpp:187
msgid "play C major on distaff"
msgstr "spill C dur pх distaffen"
-#: engines/scumm/help.cpp:192 engines/scumm/help.cpp:214
+#: engines/scumm/help.cpp:193 engines/scumm/help.cpp:215
msgid "puSh"
msgstr "Dytt"
-#: engines/scumm/help.cpp:193 engines/scumm/help.cpp:215
+#: engines/scumm/help.cpp:194 engines/scumm/help.cpp:216
msgid "pull (Yank)"
msgstr "Dra"
-#: engines/scumm/help.cpp:196 engines/scumm/help.cpp:212
-#: engines/scumm/help.cpp:248
+#: engines/scumm/help.cpp:197 engines/scumm/help.cpp:213
+#: engines/scumm/help.cpp:249
msgid "Talk to"
msgstr "Snakk til"
-#: engines/scumm/help.cpp:199 engines/scumm/help.cpp:211
+#: engines/scumm/help.cpp:200 engines/scumm/help.cpp:212
msgid "Look at"
msgstr "Se pх"
-#: engines/scumm/help.cpp:200
+#: engines/scumm/help.cpp:201
msgid "turn oN"
msgstr "Slх pх"
-#: engines/scumm/help.cpp:201
+#: engines/scumm/help.cpp:202
msgid "turn oFf"
msgstr "Slх av"
-#: engines/scumm/help.cpp:217
+#: engines/scumm/help.cpp:218
msgid "KeyUp"
msgstr "Ned-tast"
-#: engines/scumm/help.cpp:217
+#: engines/scumm/help.cpp:218
msgid "Highlight prev dialogue"
msgstr "Merk forrige dialog"
-#: engines/scumm/help.cpp:218
+#: engines/scumm/help.cpp:219
msgid "KeyDown"
msgstr "Opp-tast"
-#: engines/scumm/help.cpp:218
+#: engines/scumm/help.cpp:219
msgid "Highlight next dialogue"
msgstr "Merk neste dialog"
-#: engines/scumm/help.cpp:222
+#: engines/scumm/help.cpp:223
msgid "Walk"
msgstr "Gх"
-#: engines/scumm/help.cpp:225 engines/scumm/help.cpp:234
-#: engines/scumm/help.cpp:241 engines/scumm/help.cpp:249
+#: engines/scumm/help.cpp:226 engines/scumm/help.cpp:235
+#: engines/scumm/help.cpp:242 engines/scumm/help.cpp:250
msgid "Inventory"
msgstr "Inventar"
-#: engines/scumm/help.cpp:226
+#: engines/scumm/help.cpp:227
msgid "Object"
msgstr "Gjenstand"
-#: engines/scumm/help.cpp:229
+#: engines/scumm/help.cpp:230
msgid "Black and White / Color"
msgstr "Svart/Hvitt / Farger"
-#: engines/scumm/help.cpp:232
+#: engines/scumm/help.cpp:233
msgid "Eyes"
msgstr "иyne"
-#: engines/scumm/help.cpp:233
+#: engines/scumm/help.cpp:234
msgid "Tongue"
msgstr "Tunge"
-#: engines/scumm/help.cpp:235
+#: engines/scumm/help.cpp:236
msgid "Punch"
msgstr "Slх"
-#: engines/scumm/help.cpp:236
+#: engines/scumm/help.cpp:237
msgid "Kick"
msgstr "Spark"
-#: engines/scumm/help.cpp:239 engines/scumm/help.cpp:247
+#: engines/scumm/help.cpp:240 engines/scumm/help.cpp:248
msgid "Examine"
msgstr "Undersјk"
-#: engines/scumm/help.cpp:240
+#: engines/scumm/help.cpp:241
msgid "Regular cursor"
msgstr "Vanlig muspeker"
#. I18N: Comm is a communication device
-#: engines/scumm/help.cpp:243
+#: engines/scumm/help.cpp:244
msgid "Comm"
msgstr "Comm"
-#: engines/scumm/help.cpp:246
+#: engines/scumm/help.cpp:247
msgid "Save / Load / Options"
msgstr "Lagre / Хpne / Valg"
-#: engines/scumm/help.cpp:255
+#: engines/scumm/help.cpp:256
msgid "Other game controls:"
msgstr "Andre spillkontroller"
-#: engines/scumm/help.cpp:257 engines/scumm/help.cpp:267
+#: engines/scumm/help.cpp:258 engines/scumm/help.cpp:268
msgid "Inventory:"
msgstr "Inventar:"
-#: engines/scumm/help.cpp:258 engines/scumm/help.cpp:274
+#: engines/scumm/help.cpp:259 engines/scumm/help.cpp:275
msgid "Scroll list up"
msgstr "Bla liste opp"
-#: engines/scumm/help.cpp:259 engines/scumm/help.cpp:275
+#: engines/scumm/help.cpp:260 engines/scumm/help.cpp:276
msgid "Scroll list down"
msgstr "Bla liste ned"
-#: engines/scumm/help.cpp:260 engines/scumm/help.cpp:268
+#: engines/scumm/help.cpp:261 engines/scumm/help.cpp:269
msgid "Upper left item"
msgstr "иvre venstre gjenstand"
-#: engines/scumm/help.cpp:261 engines/scumm/help.cpp:270
+#: engines/scumm/help.cpp:262 engines/scumm/help.cpp:271
msgid "Lower left item"
msgstr "Nedre venstre gjenstand"
-#: engines/scumm/help.cpp:262 engines/scumm/help.cpp:271
+#: engines/scumm/help.cpp:263 engines/scumm/help.cpp:272
msgid "Upper right item"
msgstr "иvre hјyre gjenstand"
-#: engines/scumm/help.cpp:263 engines/scumm/help.cpp:273
+#: engines/scumm/help.cpp:264 engines/scumm/help.cpp:274
msgid "Lower right item"
msgstr "Nedre hјyre gjenstand"
-#: engines/scumm/help.cpp:269
+#: engines/scumm/help.cpp:270
msgid "Middle left item"
msgstr "Midtre venstre gjenstand"
-#: engines/scumm/help.cpp:272
+#: engines/scumm/help.cpp:273
msgid "Middle right item"
msgstr "Midtre hјyre gjenstand"
-#: engines/scumm/help.cpp:279 engines/scumm/help.cpp:284
+#: engines/scumm/help.cpp:280 engines/scumm/help.cpp:285
msgid "Switching characters:"
msgstr "Bytte av karakterer:"
-#: engines/scumm/help.cpp:281
+#: engines/scumm/help.cpp:282
msgid "Second kid"
msgstr "Andre unge"
-#: engines/scumm/help.cpp:282
+#: engines/scumm/help.cpp:283
msgid "Third kid"
msgstr "Tredje unge"
-#: engines/scumm/help.cpp:294
+#: engines/scumm/help.cpp:292
+msgid "Toggle Inventory/IQ Points display"
+msgstr ""
+
+#: engines/scumm/help.cpp:293
+msgid "Toggle Keyboard/Mouse Fighting (*)"
+msgstr ""
+
+#: engines/scumm/help.cpp:295
+msgid "* Keyboard Fighting is always on,"
+msgstr ""
+
+#: engines/scumm/help.cpp:296
+msgid " so despite the in-game message this"
+msgstr ""
+
+#: engines/scumm/help.cpp:297
+msgid " actually toggles Mouse Fighting Off/On"
+msgstr ""
+
+#: engines/scumm/help.cpp:304
msgid "Fighting controls (numpad):"
msgstr "Kampkontroller (talltastatur)"
-#: engines/scumm/help.cpp:295 engines/scumm/help.cpp:296
-#: engines/scumm/help.cpp:297
+#: engines/scumm/help.cpp:305 engines/scumm/help.cpp:306
+#: engines/scumm/help.cpp:307
msgid "Step back"
msgstr "Bakoversteg"
-#: engines/scumm/help.cpp:298
+#: engines/scumm/help.cpp:308
msgid "Block high"
msgstr "Hјy blokk"
-#: engines/scumm/help.cpp:299
+#: engines/scumm/help.cpp:309
msgid "Block middle"
msgstr "Mid-blokk"
-#: engines/scumm/help.cpp:300
+#: engines/scumm/help.cpp:310
msgid "Block low"
msgstr "Lav blokk"
-#: engines/scumm/help.cpp:301
+#: engines/scumm/help.cpp:311
msgid "Punch high"
msgstr "Slх hјyt"
-#: engines/scumm/help.cpp:302
+#: engines/scumm/help.cpp:312
msgid "Punch middle"
msgstr "Slх midje"
-#: engines/scumm/help.cpp:303
+#: engines/scumm/help.cpp:313
msgid "Punch low"
msgstr "Slх lavt"
-#: engines/scumm/help.cpp:306
+#: engines/scumm/help.cpp:315
+msgid "Sucker punch"
+msgstr ""
+
+#: engines/scumm/help.cpp:318
msgid "These are for Indy on left."
msgstr "Gjelder nхr Indy er til venstre."
-#: engines/scumm/help.cpp:307
+#: engines/scumm/help.cpp:319
msgid "When Indy is on the right,"
msgstr "Nхr Indy er til hјyre,"
-#: engines/scumm/help.cpp:308
+#: engines/scumm/help.cpp:320
msgid "7, 4, and 1 are switched with"
msgstr "Byttes 7, 4, og 1 med"
-#: engines/scumm/help.cpp:309
+#: engines/scumm/help.cpp:321
msgid "9, 6, and 3, respectively."
msgstr "henholdsvis 9, 6, og 3."
-#: engines/scumm/help.cpp:316
+#: engines/scumm/help.cpp:328
msgid "Biplane controls (numpad):"
msgstr "Flykontroller (talltastatur)"
-#: engines/scumm/help.cpp:317
+#: engines/scumm/help.cpp:329
msgid "Fly to upper left"
msgstr "Fly til јvre venstre"
-#: engines/scumm/help.cpp:318
+#: engines/scumm/help.cpp:330
msgid "Fly to left"
msgstr "Fly til venstre"
-#: engines/scumm/help.cpp:319
+#: engines/scumm/help.cpp:331
msgid "Fly to lower left"
msgstr "Fly til nedre venstre"
-#: engines/scumm/help.cpp:320
+#: engines/scumm/help.cpp:332
msgid "Fly upwards"
msgstr "Fly oppover"
-#: engines/scumm/help.cpp:321
+#: engines/scumm/help.cpp:333
msgid "Fly straight"
msgstr "Fly rett"
-#: engines/scumm/help.cpp:322
+#: engines/scumm/help.cpp:334
msgid "Fly down"
msgstr "Fly ned"
-#: engines/scumm/help.cpp:323
+#: engines/scumm/help.cpp:335
msgid "Fly to upper right"
msgstr "Fly til јvre hјyre"
-#: engines/scumm/help.cpp:324
+#: engines/scumm/help.cpp:336
msgid "Fly to right"
msgstr "Fly til hјyre"
-#: engines/scumm/help.cpp:325
+#: engines/scumm/help.cpp:337
msgid "Fly to lower right"
msgstr "Fly til nedre hјyre"
-#: engines/scumm/scumm.cpp:1823
+#: engines/scumm/scumm.cpp:1832
#, c-format
msgid ""
"Native MIDI support requires the Roland Upgrade from LucasArts,\n"
@@ -3185,11 +3274,12 @@ msgstr ""
"Ekte MIDI-stјtte krever ЋRoland UpgradeЛ fra LucasArts,\n"
"men %s mangler. Bruker AdLib istedet."
-#: engines/scumm/scumm.cpp:2594
+#: engines/scumm/scumm.cpp:2644
+#, fuzzy
msgid ""
-"Usually, Maniac Mansion would start now. But ScummVM doesn't do that yet. To "
-"play it, go to 'Add Game' in the ScummVM start menu and select the 'Maniac' "
-"directory inside the Tentacle game directory."
+"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-"
@@ -3323,6 +3413,48 @@ msgstr ""
msgid "Show the current number of frames per second in the upper left corner"
msgstr ""
+#: engines/zvision/detection.cpp:256
+msgid "Double FPS"
+msgstr ""
+
+#: engines/zvision/detection.cpp:257
+msgid "Increase game FPS from 30 to 60"
+msgstr ""
+
+#: engines/zvision/detection.cpp:266
+#, fuzzy
+msgid "Enable Venus"
+msgstr "Aktiver helium-modus"
+
+#: engines/zvision/detection.cpp:267
+msgid "Enable the Venus help system"
+msgstr ""
+
+#: engines/zvision/detection.cpp:276
+msgid "Disable animation while turning"
+msgstr ""
+
+#: engines/zvision/detection.cpp:277
+msgid "Disable animation while turning in panoramic mode"
+msgstr ""
+
+#: engines/zvision/detection.cpp:286
+msgid "Use the hires MPEG movies"
+msgstr ""
+
+#: engines/zvision/detection.cpp:287
+#, fuzzy
+msgid ""
+"Use the hires MPEG movies of the DVD version, instead of the lowres AVI ones"
+msgstr ""
+"Bruk det alternative settet med sјlvmuspekere, istedenfor de normale gylne."
+
+#~ msgid "EGA undithering"
+#~ msgstr "EGA av-dithering"
+
+#~ msgid "Enable undithering in EGA games"
+#~ msgstr "Aktiver av-dithering i EGA-spill"
+
#~ msgid "MPEG-2 cutscenes found but ScummVM has been built without MPEG-2"
#~ msgstr "MPEG2-cutscener funnet men ScummVM er bygd uten MPEG2-stјtte"
@@ -3330,9 +3462,6 @@ msgstr ""
#~ msgid "Mass Add..."
#~ msgstr "Legg til flere..."
-#~ msgid "Mass Add..."
-#~ msgstr "Legg til flere..."
-
#~ msgid ""
#~ "Turns off General MIDI mapping for games with Roland MT-32 soundtrack"
#~ msgstr "Slх av General MIDI-kobling for spill som har Roland MT-32-lydspor"
diff --git a/po/nl_NL.po b/po/nl_NL.po
index 48527ebe9c..970ff6ce8b 100644
--- a/po/nl_NL.po
+++ b/po/nl_NL.po
@@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: ScummVM 1.8.0git\n"
"Report-Msgid-Bugs-To: scummvm-devel@lists.sf.net\n"
-"POT-Creation-Date: 2014-11-25 20:41+0100\n"
+"POT-Creation-Date: 2015-06-30 20:57+0100\n"
"PO-Revision-Date: 2014-11-25 20:46+0100\n"
"Last-Translator: Ben Castricum <scummvm@bencastricum.nl>\n"
"Language-Team: Ben Castricum <scummvm@bencastricum.nl>\n"
@@ -55,10 +55,11 @@ msgstr "Ga omhoog"
#: gui/browser.cpp:75 gui/chooser.cpp:46 gui/KeysDialog.cpp:43
#: gui/launcher.cpp:351 gui/massadd.cpp:95 gui/options.cpp:1239
+#: gui/recorderdialog.cpp:70 gui/recorderdialog.cpp:156
#: gui/saveload-dialog.cpp:216 gui/saveload-dialog.cpp:276
-#: gui/saveload-dialog.cpp:547 gui/saveload-dialog.cpp:922
+#: gui/saveload-dialog.cpp:547 gui/saveload-dialog.cpp:931
#: gui/themebrowser.cpp:55 gui/fluidsynth-dialog.cpp:152
-#: engines/engine.cpp:452 backends/platform/wii/options.cpp:48
+#: engines/engine.cpp:483 backends/platform/wii/options.cpp:48
#: backends/events/default/default-events.cpp:196
#: backends/events/default/default-events.cpp:218
#: engines/drascula/saveload.cpp:49 engines/parallaction/saveload.cpp:274
@@ -71,9 +72,9 @@ msgid "Choose"
msgstr "Selecteer"
#: gui/gui-manager.cpp:117 backends/keymapper/remap-dialog.cpp:53
-#: 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
+#: 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"
@@ -89,7 +90,7 @@ msgstr "Toon toetsenbord"
msgid "Remap keys"
msgstr "Toetsen opnieuw koppelen"
-#: gui/gui-manager.cpp:131 base/main.cpp:326 engines/scumm/help.cpp:86
+#: gui/gui-manager.cpp:131 base/main.cpp:326 engines/scumm/help.cpp:87
msgid "Toggle fullscreen"
msgstr "Volledig scherm in-/uitschakelen"
@@ -103,13 +104,13 @@ 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:1240
-#: gui/saveload-dialog.cpp:923 gui/fluidsynth-dialog.cpp:153
-#: engines/engine.cpp:371 engines/engine.cpp:382
+#: 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:1825
+#: 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
@@ -481,7 +482,7 @@ msgstr ""
#: gui/launcher.cpp:793 gui/launcher.cpp:941 gui/launcher.cpp:1000
#: gui/fluidsynth-dialog.cpp:217
-#: backends/events/symbiansdl/symbiansdl-events.cpp:184
+#: 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
@@ -491,7 +492,7 @@ 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:184
+#: 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
@@ -529,6 +530,14 @@ msgstr ""
"ScummVM heeft geen engine gevonden die in staat was het geselecteerde spel "
"te spelen!"
+#: gui/launcher.cpp:1159
+msgid "Mass Add..."
+msgstr ""
+
+#: gui/launcher.cpp:1161
+msgid "Record..."
+msgstr ""
+
#: gui/massadd.cpp:79 gui/massadd.cpp:82
msgid "... progress ..."
msgstr "... voortgang ..."
@@ -631,7 +640,7 @@ msgid "Special dithering modes supported by some games"
msgstr "Speciale ditheringmodi die door sommige games ondersteund worden."
#: gui/options.cpp:760
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2249
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2298
msgid "Fullscreen mode"
msgstr "Volledig-scherm modus"
@@ -950,6 +959,43 @@ msgstr ""
"De thema die u heeft geselecteerd ondersteund uw gekozen taal niet. Als u "
"dit thema wilt gebruiken dient u eerst een andere taal te selecteren."
+#: gui/recorderdialog.cpp:64
+msgid "Recorder or Playback Gameplay"
+msgstr ""
+
+#: gui/recorderdialog.cpp:69 gui/recorderdialog.cpp:156
+#: gui/saveload-dialog.cpp:220 gui/saveload-dialog.cpp:276
+msgid "Delete"
+msgstr "Verwijderen"
+
+#: gui/recorderdialog.cpp:71
+msgid "Record"
+msgstr ""
+
+#: gui/recorderdialog.cpp:72
+#, fuzzy
+msgid "Playback"
+msgstr "Spelen"
+
+#: gui/recorderdialog.cpp:74
+msgid "Edit"
+msgstr ""
+
+#: gui/recorderdialog.cpp:86 gui/recorderdialog.cpp:243
+#: gui/recorderdialog.cpp:253
+msgid "Author: "
+msgstr ""
+
+#: gui/recorderdialog.cpp:87 gui/recorderdialog.cpp:244
+#: gui/recorderdialog.cpp:254
+msgid "Notes: "
+msgstr ""
+
+#: gui/recorderdialog.cpp:155
+#, fuzzy
+msgid "Do you really want to delete this record?"
+msgstr "Wilt u dit opgeslagen spel echt verwijderen?"
+
#: gui/saveload-dialog.cpp:167
msgid "List view"
msgstr "Lijstopmaak"
@@ -970,23 +1016,19 @@ msgstr "Geen tijd opgeslagen"
msgid "No playtime saved"
msgstr "Geen speeltijd opgeslagen"
-#: gui/saveload-dialog.cpp:220 gui/saveload-dialog.cpp:276
-msgid "Delete"
-msgstr "Verwijderen"
-
#: gui/saveload-dialog.cpp:275
msgid "Do you really want to delete this saved game?"
msgstr "Wilt u dit opgeslagen spel echt verwijderen?"
-#: gui/saveload-dialog.cpp:385 gui/saveload-dialog.cpp:875
+#: gui/saveload-dialog.cpp:385 gui/saveload-dialog.cpp:884
msgid "Date: "
msgstr "Datum: "
-#: gui/saveload-dialog.cpp:389 gui/saveload-dialog.cpp:881
+#: gui/saveload-dialog.cpp:389 gui/saveload-dialog.cpp:890
msgid "Time: "
msgstr "Tijd: "
-#: gui/saveload-dialog.cpp:395 gui/saveload-dialog.cpp:889
+#: gui/saveload-dialog.cpp:395 gui/saveload-dialog.cpp:898
msgid "Playtime: "
msgstr "Speeltijd: "
@@ -1002,19 +1044,19 @@ msgstr "Volgende"
msgid "Prev"
msgstr "Vorig"
-#: gui/saveload-dialog.cpp:739
+#: gui/saveload-dialog.cpp:748
msgid "New Save"
msgstr "Nieuw spel opslaan"
-#: gui/saveload-dialog.cpp:739
+#: gui/saveload-dialog.cpp:748
msgid "Create a new save game"
msgstr "Nieuw spel opslaan"
-#: gui/saveload-dialog.cpp:868
+#: gui/saveload-dialog.cpp:877
msgid "Name: "
msgstr "Naam: "
-#: gui/saveload-dialog.cpp:940
+#: gui/saveload-dialog.cpp:949
#, c-format
msgid "Enter a description for slot %d:"
msgstr "Geef een omschrijving voor slot %d:"
@@ -1167,7 +1209,7 @@ msgstr "Regel overslaan"
msgid "Error running game:"
msgstr "Fout tijdens het starten van spel:"
-#: base/main.cpp:536
+#: base/main.cpp:554
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"
@@ -1338,24 +1380,24 @@ msgstr "~A~nnuleer"
msgid "~K~eys"
msgstr "~T~oetsen"
-#: engines/engine.cpp:245
+#: engines/engine.cpp:276
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:253
+#: engines/engine.cpp:284
msgid "Could not switch to video mode: '"
msgstr "Kon niet schakelen naar videomodus: '"
-#: engines/engine.cpp:262
+#: engines/engine.cpp:293
msgid "Could not apply aspect ratio setting."
msgstr "Pixelverhoudinginstelling kon niet toegepast worden."
-#: engines/engine.cpp:267
+#: engines/engine.cpp:298
msgid "Could not apply fullscreen setting."
msgstr "Kon volledig-scherminstelling niet toepassen."
-#: engines/engine.cpp:367
+#: engines/engine.cpp:398
msgid ""
"You appear to be playing this game directly\n"
"from the CD. This is known to cause problems,\n"
@@ -1369,7 +1411,7 @@ msgstr ""
"bestanden naar uw harddisk te kopieren.\n"
"Voor details kijk in de README."
-#: engines/engine.cpp:378
+#: engines/engine.cpp:409
msgid ""
"This game has audio tracks in its disk. These\n"
"tracks need to be ripped from the disk using\n"
@@ -1382,7 +1424,7 @@ msgstr ""
"CD rip programma om te kunnen luisteren naar\n"
"het spelmuziek. Voor details kijk in de README."
-#: engines/engine.cpp:436
+#: engines/engine.cpp:467
#, c-format
msgid ""
"Gamestate load failed (%s)! Please consult the README for basic information, "
@@ -1392,7 +1434,7 @@ msgstr ""
"voor basisinformatie, en voor instructies voor het verkrijgen van verdere "
"assistentie."
-#: engines/engine.cpp:449
+#: engines/engine.cpp:480
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 "
@@ -1403,7 +1445,7 @@ msgstr ""
"instabiel is, en opgeslagen spellen zullen mogelijk niet werken in "
"toekomstige versies van ScummVM."
-#: engines/engine.cpp:452
+#: engines/engine.cpp:483
msgid "Start anyway"
msgstr "Evengoed starten"
@@ -1613,11 +1655,11 @@ msgstr "Touchpadmodus ingeschakeld."
msgid "Touchpad mode disabled."
msgstr "Touchpadmodus uitgeschakeld."
-#: backends/platform/maemo/maemo.cpp:209
+#: backends/platform/maemo/maemo.cpp:208
msgid "Click Mode"
msgstr "Klik Modus"
-#: backends/platform/maemo/maemo.cpp:215
+#: backends/platform/maemo/maemo.cpp:214
#: backends/platform/symbian/src/SymbianActions.cpp:42
#: backends/platform/wince/CEActionsPocket.cpp:60
#: backends/platform/wince/CEActionsSmartphone.cpp:43
@@ -1625,11 +1667,11 @@ msgstr "Klik Modus"
msgid "Left Click"
msgstr "Linker Klik"
-#: backends/platform/maemo/maemo.cpp:218
+#: backends/platform/maemo/maemo.cpp:217
msgid "Middle Click"
msgstr "Middelste Klik"
-#: backends/platform/maemo/maemo.cpp:221
+#: 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
@@ -1666,19 +1708,19 @@ msgctxt "lowres"
msgid "Normal (no scaling)"
msgstr "Normaal (niet schalen)"
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2148
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2197
msgid "Enabled aspect ratio correction"
msgstr "Pixelverhoudingcorrectie ingeschakeld"
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2154
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2203
msgid "Disabled aspect ratio correction"
msgstr "Pixelverhoudingcorrectie uitgeschakeld"
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2209
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2258
msgid "Active graphics filter:"
msgstr "Actieve grafische filter:"
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2251
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2300
msgid "Windowed mode"
msgstr "Venstermodus"
@@ -1737,8 +1779,8 @@ msgstr "Snelle modus"
#: 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:82
-#: engines/scumm/help.cpp:84
+#: engines/scumm/dialogs.cpp:192 engines/scumm/help.cpp:83
+#: engines/scumm/help.cpp:85
msgid "Quit"
msgstr "Stoppen"
@@ -1758,7 +1800,7 @@ msgstr "Virtueel toetsenbord"
msgid "Key mapper"
msgstr "Toets koppeltool"
-#: backends/events/symbiansdl/symbiansdl-events.cpp:184
+#: backends/events/symbiansdl/symbiansdl-events.cpp:186
msgid "Do you want to quit ?"
msgstr "Wilt u stoppen?"
@@ -2095,21 +2137,43 @@ msgstr "Klikken Aangezet"
msgid "Clicking Disabled"
msgstr "Klikken Uitgeschakeld"
-#: engines/agi/detection.cpp:142 engines/drascula/detection.cpp:302
+#: 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.cpp:103
+#: engines/zvision/detection.cpp:246
msgid "Use original save/load screens"
msgstr "Gebruik originele opslaan/laad schermen"
-#: engines/agi/detection.cpp:143 engines/drascula/detection.cpp:303
+#: 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/zvision/detection.cpp:104
+#: engines/zvision/detection.cpp:247
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)"
+
+#: engines/agi/detection.cpp:158
+msgid ""
+"Use an alternative palette, common for all Amiga games. This was the old "
+"behavior"
+msgstr ""
+
+#: engines/agi/detection.cpp:167
+#, fuzzy
+msgid "Mouse support"
+msgstr "Support overslaan"
+
+#: 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
@@ -2122,7 +2186,7 @@ msgstr "Laad opgeslagen spel:"
msgid "Restore"
msgstr "Laad"
-#: engines/agos/saveload.cpp:160 engines/scumm/scumm.cpp:2368
+#: engines/agos/saveload.cpp:160 engines/scumm/scumm.cpp:2377
#, c-format
msgid ""
"Failed to load game state from file:\n"
@@ -2133,7 +2197,7 @@ msgstr ""
"\n"
"%s"
-#: engines/agos/saveload.cpp:195 engines/scumm/scumm.cpp:2361
+#: engines/agos/saveload.cpp:195 engines/scumm/scumm.cpp:2370
#, c-format
msgid ""
"Failed to save game state to file:\n"
@@ -2144,7 +2208,7 @@ msgstr ""
"\n"
"%s"
-#: engines/agos/saveload.cpp:203 engines/scumm/scumm.cpp:2379
+#: engines/agos/saveload.cpp:203 engines/scumm/scumm.cpp:2388
#, c-format
msgid ""
"Successfully saved game state in file:\n"
@@ -2160,11 +2224,11 @@ msgstr ""
msgid "Cutscene file '%s' not found!"
msgstr "Cutscene bestand '%s' niet gevonden!"
-#: engines/cge/detection.cpp:105 engines/cge2/detection.cpp:91
+#: engines/cge/detection.cpp:105 engines/cge2/detection.cpp:101
msgid "Color Blind Mode"
msgstr "Kleurenblind Modus"
-#: engines/cge/detection.cpp:106 engines/cge2/detection.cpp:92
+#: engines/cge/detection.cpp:106 engines/cge2/detection.cpp:102
msgid "Enable Color Blind Mode by default"
msgstr "Schakel Kleurenblind modus standaard in"
@@ -2530,12 +2594,12 @@ msgstr ""
"Gebruik een alternatieve versie van de intro (alleen voor de CD versie)"
#: engines/sci/detection.cpp:374
-msgid "EGA undithering"
-msgstr "EGA undithering"
+msgid "Skip EGA dithering pass (full color backgrounds)"
+msgstr ""
#: engines/sci/detection.cpp:375
-msgid "Enable undithering in EGA games"
-msgstr "Undithering inschakelen in EGA spellen"
+msgid "Skip dithering pass in EGA games, graphics are shown with full colors"
+msgstr ""
#: engines/sci/detection.cpp:384
msgid "Prefer digital sound effects"
@@ -2703,516 +2767,541 @@ msgstr "Oefenen"
msgid "Expert"
msgstr "Expert"
-#: engines/scumm/help.cpp:73
+#: engines/scumm/help.cpp:74
msgid "Common keyboard commands:"
msgstr "Gebruikelijke toetsenbord commandos:"
-#: engines/scumm/help.cpp:74
+#: engines/scumm/help.cpp:75
msgid "Save / Load dialog"
msgstr "Opslaan / Laden dialoog"
-#: engines/scumm/help.cpp:76
+#: engines/scumm/help.cpp:77
msgid "Skip line of text"
msgstr "Regel text overslaan"
-#: engines/scumm/help.cpp:77
+#: engines/scumm/help.cpp:78
msgid "Esc"
msgstr "Esc"
-#: engines/scumm/help.cpp:77
+#: engines/scumm/help.cpp:78
msgid "Skip cutscene"
msgstr "Cutscene overslaan"
-#: engines/scumm/help.cpp:78
+#: engines/scumm/help.cpp:79
msgid "Space"
msgstr "Spatie"
-#: engines/scumm/help.cpp:78
+#: engines/scumm/help.cpp:79
msgid "Pause game"
msgstr "Spel pauzeren"
-#: engines/scumm/help.cpp:79 engines/scumm/help.cpp:84
-#: engines/scumm/help.cpp:95 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: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:79
+#: engines/scumm/help.cpp:80
msgid "Load game state 1-10"
msgstr "Laad opgeslagen spel 1-10"
-#: engines/scumm/help.cpp:80 engines/scumm/help.cpp:84
-#: engines/scumm/help.cpp:86 engines/scumm/help.cpp:100
-#: engines/scumm/help.cpp:101 engines/scumm/help.cpp:102
+#: 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:80
+#: engines/scumm/help.cpp:81
msgid "Save game state 1-10"
msgstr "Spel opslaan 1-10"
-#: engines/scumm/help.cpp:86 engines/scumm/help.cpp:89
+#: engines/scumm/help.cpp:87 engines/scumm/help.cpp:90
msgid "Enter"
msgstr "Enter"
-#: engines/scumm/help.cpp:87
+#: engines/scumm/help.cpp:88
msgid "Music volume up / down"
msgstr "Muziek volume omhoog / omlaag"
-#: engines/scumm/help.cpp:88
+#: engines/scumm/help.cpp:89
msgid "Text speed slower / faster"
msgstr "Tekst langzamer / sneller"
-#: engines/scumm/help.cpp:89
+#: engines/scumm/help.cpp:90
msgid "Simulate left mouse button"
msgstr "Simuleer linkermuisknop"
-#: engines/scumm/help.cpp:90
+#: engines/scumm/help.cpp:91
msgid "Tab"
msgstr "Tab"
-#: engines/scumm/help.cpp:90
+#: engines/scumm/help.cpp:91
msgid "Simulate right mouse button"
msgstr "Simuleer rechtermuisknop"
-#: engines/scumm/help.cpp:93
+#: engines/scumm/help.cpp:94
msgid "Special keyboard commands:"
msgstr "Speciale toetsenbord commando's:"
-#: engines/scumm/help.cpp:94
+#: engines/scumm/help.cpp:95
msgid "Show / Hide console"
msgstr "Toon / Verberg console"
-#: engines/scumm/help.cpp:95
+#: engines/scumm/help.cpp:96
msgid "Start the debugger"
msgstr "Start de debugger"
-#: engines/scumm/help.cpp:96
+#: engines/scumm/help.cpp:97
msgid "Show memory consumption"
msgstr "Toon geheugen gebruik"
-#: engines/scumm/help.cpp:97
+#: engines/scumm/help.cpp:98
msgid "Run in fast mode (*)"
msgstr "Draai in snelle modus (*)"
-#: engines/scumm/help.cpp:98
+#: engines/scumm/help.cpp:99
msgid "Run in really fast mode (*)"
msgstr "Draai in zeer snelle modus (*)"
-#: engines/scumm/help.cpp:99
+#: engines/scumm/help.cpp:100
msgid "Toggle mouse capture"
msgstr "Mousecapture In-/Uitschakelen"
-#: engines/scumm/help.cpp:100
+#: engines/scumm/help.cpp:101
msgid "Switch between graphics filters"
msgstr "Schakel tussen grafische filters"
-#: engines/scumm/help.cpp:101
+#: engines/scumm/help.cpp:102
msgid "Increase / Decrease scale factor"
msgstr "Verhoog / Verlaag schalingsfactor"
-#: engines/scumm/help.cpp:102
+#: engines/scumm/help.cpp:103
msgid "Toggle aspect-ratio correction"
msgstr "Schakel pixelverhoudingcorrectie aan/uit"
-#: engines/scumm/help.cpp:107
+#: engines/scumm/help.cpp:108
msgid "* Note that using ctrl-f and"
msgstr "* Het gebruik van Ctrl-F en"
-#: engines/scumm/help.cpp:108
+#: engines/scumm/help.cpp:109
msgid " ctrl-g are not recommended"
msgstr " Ctrl-G wordt niet aanbevolen"
-#: engines/scumm/help.cpp:109
+#: engines/scumm/help.cpp:110
msgid " since they may cause crashes"
msgstr " omdat dit crashes of andere"
-#: engines/scumm/help.cpp:110
+#: engines/scumm/help.cpp:111
msgid " or incorrect game behavior."
msgstr " effecten in het spel kan veroorzaken."
-#: engines/scumm/help.cpp:114
+#: engines/scumm/help.cpp:115
msgid "Spinning drafts on the keyboard:"
msgstr "Garen spinnen op het toetsenbord:"
-#: engines/scumm/help.cpp:116
+#: engines/scumm/help.cpp:117
msgid "Main game controls:"
msgstr "Hoofd spel besturing:"
-#: engines/scumm/help.cpp:121 engines/scumm/help.cpp:136
-#: engines/scumm/help.cpp:161
+#: engines/scumm/help.cpp:122 engines/scumm/help.cpp:137
+#: engines/scumm/help.cpp:162
msgid "Push"
msgstr "Duw"
-#: engines/scumm/help.cpp:122 engines/scumm/help.cpp:137
-#: engines/scumm/help.cpp:162
+#: engines/scumm/help.cpp:123 engines/scumm/help.cpp:138
+#: engines/scumm/help.cpp:163
msgid "Pull"
msgstr "Trek"
-#: engines/scumm/help.cpp:123 engines/scumm/help.cpp:138
-#: engines/scumm/help.cpp:163 engines/scumm/help.cpp:197
-#: engines/scumm/help.cpp:207
+#: 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 "Geef"
-#: engines/scumm/help.cpp:124 engines/scumm/help.cpp:139
-#: engines/scumm/help.cpp:164 engines/scumm/help.cpp:190
-#: engines/scumm/help.cpp:208
+#: 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 "Open"
-#: engines/scumm/help.cpp:126
+#: engines/scumm/help.cpp:127
msgid "Go to"
msgstr "Ga naar"
-#: engines/scumm/help.cpp:127
+#: engines/scumm/help.cpp:128
msgid "Get"
msgstr "Pak"
-#: engines/scumm/help.cpp:128 engines/scumm/help.cpp:152
-#: engines/scumm/help.cpp:170 engines/scumm/help.cpp:198
-#: engines/scumm/help.cpp:213 engines/scumm/help.cpp:224
-#: engines/scumm/help.cpp:250
+#: 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 "Gebruik"
-#: engines/scumm/help.cpp:129 engines/scumm/help.cpp:141
+#: engines/scumm/help.cpp:130 engines/scumm/help.cpp:142
msgid "Read"
msgstr "Lees"
-#: engines/scumm/help.cpp:130 engines/scumm/help.cpp:147
+#: engines/scumm/help.cpp:131 engines/scumm/help.cpp:148
msgid "New kid"
msgstr "Nieuw kind"
-#: engines/scumm/help.cpp:131 engines/scumm/help.cpp:153
-#: engines/scumm/help.cpp:171
+#: engines/scumm/help.cpp:132 engines/scumm/help.cpp:154
+#: engines/scumm/help.cpp:172
msgid "Turn on"
msgstr "Zet aan"
-#: engines/scumm/help.cpp:132 engines/scumm/help.cpp:154
-#: engines/scumm/help.cpp:172
+#: engines/scumm/help.cpp:133 engines/scumm/help.cpp:155
+#: engines/scumm/help.cpp:173
msgid "Turn off"
msgstr "Zet uit"
-#: engines/scumm/help.cpp:142 engines/scumm/help.cpp:167
-#: engines/scumm/help.cpp:194
+#: engines/scumm/help.cpp:143 engines/scumm/help.cpp:168
+#: engines/scumm/help.cpp:195
msgid "Walk to"
msgstr "Loop naar"
-#: engines/scumm/help.cpp:143 engines/scumm/help.cpp:168
-#: engines/scumm/help.cpp:195 engines/scumm/help.cpp:210
-#: engines/scumm/help.cpp:227
+#: 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 "Pak op"
-#: engines/scumm/help.cpp:144 engines/scumm/help.cpp:169
+#: engines/scumm/help.cpp:145 engines/scumm/help.cpp:170
msgid "What is"
msgstr "Wat is"
-#: engines/scumm/help.cpp:146
+#: engines/scumm/help.cpp:147
msgid "Unlock"
msgstr "Maak open"
-#: engines/scumm/help.cpp:149
+#: engines/scumm/help.cpp:150
msgid "Put on"
msgstr "Zet op"
-#: engines/scumm/help.cpp:150
+#: engines/scumm/help.cpp:151
msgid "Take off"
msgstr "Doe af"
-#: engines/scumm/help.cpp:156
+#: engines/scumm/help.cpp:157
msgid "Fix"
msgstr "Repareer"
-#: engines/scumm/help.cpp:158
+#: engines/scumm/help.cpp:159
msgid "Switch"
msgstr "Schakel"
-#: engines/scumm/help.cpp:166 engines/scumm/help.cpp:228
+#: engines/scumm/help.cpp:167 engines/scumm/help.cpp:229
msgid "Look"
msgstr "Kijk"
-#: engines/scumm/help.cpp:173 engines/scumm/help.cpp:223
+#: engines/scumm/help.cpp:174 engines/scumm/help.cpp:224
msgid "Talk"
msgstr "Praat"
-#: engines/scumm/help.cpp:174
+#: engines/scumm/help.cpp:175
msgid "Travel"
msgstr "Reis"
-#: engines/scumm/help.cpp:175
+#: engines/scumm/help.cpp:176
msgid "To Henry / To Indy"
msgstr "Naar Henry / Naar Indy"
#. I18N: These are different musical notes
-#: engines/scumm/help.cpp:179
+#: engines/scumm/help.cpp:180
msgid "play C minor on distaff"
msgstr "speel C mineur op spinrok"
-#: engines/scumm/help.cpp:180
+#: engines/scumm/help.cpp:181
msgid "play D on distaff"
msgstr "speel D op spinrok"
-#: engines/scumm/help.cpp:181
+#: engines/scumm/help.cpp:182
msgid "play E on distaff"
msgstr "speel E op spinrok"
-#: engines/scumm/help.cpp:182
+#: engines/scumm/help.cpp:183
msgid "play F on distaff"
msgstr "speel F op spinrok"
-#: engines/scumm/help.cpp:183
+#: engines/scumm/help.cpp:184
msgid "play G on distaff"
msgstr "speel G op spinrok"
-#: engines/scumm/help.cpp:184
+#: engines/scumm/help.cpp:185
msgid "play A on distaff"
msgstr "speel A op spinrok"
-#: engines/scumm/help.cpp:185
+#: engines/scumm/help.cpp:186
msgid "play B on distaff"
msgstr "speel B op spinrok"
-#: engines/scumm/help.cpp:186
+#: engines/scumm/help.cpp:187
msgid "play C major on distaff"
msgstr "speel C majeur op spinrok"
-#: engines/scumm/help.cpp:192 engines/scumm/help.cpp:214
+#: engines/scumm/help.cpp:193 engines/scumm/help.cpp:215
msgid "puSh"
msgstr "Duw"
-#: engines/scumm/help.cpp:193 engines/scumm/help.cpp:215
+#: engines/scumm/help.cpp:194 engines/scumm/help.cpp:216
msgid "pull (Yank)"
msgstr "Trek"
-#: engines/scumm/help.cpp:196 engines/scumm/help.cpp:212
-#: engines/scumm/help.cpp:248
+#: engines/scumm/help.cpp:197 engines/scumm/help.cpp:213
+#: engines/scumm/help.cpp:249
msgid "Talk to"
msgstr "Praat met"
-#: engines/scumm/help.cpp:199 engines/scumm/help.cpp:211
+#: engines/scumm/help.cpp:200 engines/scumm/help.cpp:212
msgid "Look at"
msgstr "Kijk naar"
-#: engines/scumm/help.cpp:200
+#: engines/scumm/help.cpp:201
msgid "turn oN"
msgstr "zet aaN"
-#: engines/scumm/help.cpp:201
+#: engines/scumm/help.cpp:202
msgid "turn oFf"
msgstr "zet uit"
-#: engines/scumm/help.cpp:217
+#: engines/scumm/help.cpp:218
msgid "KeyUp"
msgstr "ToetsOmhoog"
-#: engines/scumm/help.cpp:217
+#: engines/scumm/help.cpp:218
msgid "Highlight prev dialogue"
msgstr "Vorig dialoog oplichten"
-#: engines/scumm/help.cpp:218
+#: engines/scumm/help.cpp:219
msgid "KeyDown"
msgstr "ToetsOmlaag"
-#: engines/scumm/help.cpp:218
+#: engines/scumm/help.cpp:219
msgid "Highlight next dialogue"
msgstr "Volgend dialoog oplichten"
-#: engines/scumm/help.cpp:222
+#: engines/scumm/help.cpp:223
msgid "Walk"
msgstr "Loop"
-#: engines/scumm/help.cpp:225 engines/scumm/help.cpp:234
-#: engines/scumm/help.cpp:241 engines/scumm/help.cpp:249
+#: engines/scumm/help.cpp:226 engines/scumm/help.cpp:235
+#: engines/scumm/help.cpp:242 engines/scumm/help.cpp:250
msgid "Inventory"
msgstr "Inventaris"
-#: engines/scumm/help.cpp:226
+#: engines/scumm/help.cpp:227
msgid "Object"
msgstr "Object"
-#: engines/scumm/help.cpp:229
+#: engines/scumm/help.cpp:230
msgid "Black and White / Color"
msgstr "Zwart-Wit / Kleur"
-#: engines/scumm/help.cpp:232
+#: engines/scumm/help.cpp:233
msgid "Eyes"
msgstr "Ogen"
-#: engines/scumm/help.cpp:233
+#: engines/scumm/help.cpp:234
msgid "Tongue"
msgstr "Tong"
-#: engines/scumm/help.cpp:235
+#: engines/scumm/help.cpp:236
msgid "Punch"
msgstr "Stoot"
-#: engines/scumm/help.cpp:236
+#: engines/scumm/help.cpp:237
msgid "Kick"
msgstr "Schop"
-#: engines/scumm/help.cpp:239 engines/scumm/help.cpp:247
+#: engines/scumm/help.cpp:240 engines/scumm/help.cpp:248
msgid "Examine"
msgstr "Onderzoek"
-#: engines/scumm/help.cpp:240
+#: engines/scumm/help.cpp:241
msgid "Regular cursor"
msgstr "Normale cursor"
#. I18N: Comm is a communication device
-#: engines/scumm/help.cpp:243
+#: engines/scumm/help.cpp:244
msgid "Comm"
msgstr "Comm"
-#: engines/scumm/help.cpp:246
+#: engines/scumm/help.cpp:247
msgid "Save / Load / Options"
msgstr "Opslaan / Laden / Opties"
-#: engines/scumm/help.cpp:255
+#: engines/scumm/help.cpp:256
msgid "Other game controls:"
msgstr "Andere spel besturing:"
-#: engines/scumm/help.cpp:257 engines/scumm/help.cpp:267
+#: engines/scumm/help.cpp:258 engines/scumm/help.cpp:268
msgid "Inventory:"
msgstr "Inventaris:"
-#: engines/scumm/help.cpp:258 engines/scumm/help.cpp:274
+#: engines/scumm/help.cpp:259 engines/scumm/help.cpp:275
msgid "Scroll list up"
msgstr "Scroll lijst omhoog"
-#: engines/scumm/help.cpp:259 engines/scumm/help.cpp:275
+#: engines/scumm/help.cpp:260 engines/scumm/help.cpp:276
msgid "Scroll list down"
msgstr "Scroll lijst naar beneden"
-#: engines/scumm/help.cpp:260 engines/scumm/help.cpp:268
+#: engines/scumm/help.cpp:261 engines/scumm/help.cpp:269
msgid "Upper left item"
msgstr "Linker bovenste voorwerp"
-#: engines/scumm/help.cpp:261 engines/scumm/help.cpp:270
+#: engines/scumm/help.cpp:262 engines/scumm/help.cpp:271
msgid "Lower left item"
msgstr "Linker beneden voorwerp"
-#: engines/scumm/help.cpp:262 engines/scumm/help.cpp:271
+#: engines/scumm/help.cpp:263 engines/scumm/help.cpp:272
msgid "Upper right item"
msgstr "Rechter bovenste voorwerp"
-#: engines/scumm/help.cpp:263 engines/scumm/help.cpp:273
+#: engines/scumm/help.cpp:264 engines/scumm/help.cpp:274
msgid "Lower right item"
msgstr "Rechter beneden voorwerp"
-#: engines/scumm/help.cpp:269
+#: engines/scumm/help.cpp:270
msgid "Middle left item"
msgstr "Linker middelste voorwerp"
-#: engines/scumm/help.cpp:272
+#: engines/scumm/help.cpp:273
msgid "Middle right item"
msgstr "Rechter middelste voorwerp"
-#: engines/scumm/help.cpp:279 engines/scumm/help.cpp:284
+#: engines/scumm/help.cpp:280 engines/scumm/help.cpp:285
msgid "Switching characters:"
msgstr "Verwissel karakters:"
-#: engines/scumm/help.cpp:281
+#: engines/scumm/help.cpp:282
msgid "Second kid"
msgstr "Tweede kind"
-#: engines/scumm/help.cpp:282
+#: engines/scumm/help.cpp:283
msgid "Third kid"
msgstr "Derde kind"
-#: engines/scumm/help.cpp:294
+#: engines/scumm/help.cpp:292
+#, fuzzy
+msgid "Toggle Inventory/IQ Points display"
+msgstr "Aan-/Uitzetten centreren van Datascherm"
+
+#: engines/scumm/help.cpp:293
+msgid "Toggle Keyboard/Mouse Fighting (*)"
+msgstr ""
+
+#: engines/scumm/help.cpp:295
+msgid "* Keyboard Fighting is always on,"
+msgstr ""
+
+#: engines/scumm/help.cpp:296
+msgid " so despite the in-game message this"
+msgstr ""
+
+#: engines/scumm/help.cpp:297
+msgid " actually toggles Mouse Fighting Off/On"
+msgstr ""
+
+#: engines/scumm/help.cpp:304
msgid "Fighting controls (numpad):"
msgstr "Gevechtbesturing (numeriek toetsenblok):"
-#: engines/scumm/help.cpp:295 engines/scumm/help.cpp:296
-#: engines/scumm/help.cpp:297
+#: engines/scumm/help.cpp:305 engines/scumm/help.cpp:306
+#: engines/scumm/help.cpp:307
msgid "Step back"
msgstr "Stap terug"
-#: engines/scumm/help.cpp:298
+#: engines/scumm/help.cpp:308
msgid "Block high"
msgstr "Blokker hoog"
-#: engines/scumm/help.cpp:299
+#: engines/scumm/help.cpp:309
msgid "Block middle"
msgstr "Blokkeer midden"
-#: engines/scumm/help.cpp:300
+#: engines/scumm/help.cpp:310
msgid "Block low"
msgstr "Blokkeer laag"
-#: engines/scumm/help.cpp:301
+#: engines/scumm/help.cpp:311
msgid "Punch high"
msgstr "Stoot hoog"
-#: engines/scumm/help.cpp:302
+#: engines/scumm/help.cpp:312
msgid "Punch middle"
msgstr "Stoot in het midden"
-#: engines/scumm/help.cpp:303
+#: engines/scumm/help.cpp:313
msgid "Punch low"
msgstr "Stoot laag"
-#: engines/scumm/help.cpp:306
+#: engines/scumm/help.cpp:315
+msgid "Sucker punch"
+msgstr ""
+
+#: engines/scumm/help.cpp:318
msgid "These are for Indy on left."
msgstr "Deze zijn voor Indy op links."
-#: engines/scumm/help.cpp:307
+#: engines/scumm/help.cpp:319
msgid "When Indy is on the right,"
msgstr "Wanneer Indy rechts staat,"
-#: engines/scumm/help.cpp:308
+#: engines/scumm/help.cpp:320
msgid "7, 4, and 1 are switched with"
msgstr "7, 4 en 1 zijn verwisseld met"
-#: engines/scumm/help.cpp:309
+#: engines/scumm/help.cpp:321
msgid "9, 6, and 3, respectively."
msgstr "9, 6 en 3 respectievelijk."
-#: engines/scumm/help.cpp:316
+#: engines/scumm/help.cpp:328
msgid "Biplane controls (numpad):"
msgstr "Tweedekkerbesturing (numeriek toetsenbord):"
-#: engines/scumm/help.cpp:317
+#: engines/scumm/help.cpp:329
msgid "Fly to upper left"
msgstr "Vlieg naar links omhoog"
-#: engines/scumm/help.cpp:318
+#: engines/scumm/help.cpp:330
msgid "Fly to left"
msgstr "Vlieg naar links"
-#: engines/scumm/help.cpp:319
+#: engines/scumm/help.cpp:331
msgid "Fly to lower left"
msgstr "Vlieg naar links omlaag"
-#: engines/scumm/help.cpp:320
+#: engines/scumm/help.cpp:332
msgid "Fly upwards"
msgstr "Vlieg omhoog"
-#: engines/scumm/help.cpp:321
+#: engines/scumm/help.cpp:333
msgid "Fly straight"
msgstr "Vlieg recht"
-#: engines/scumm/help.cpp:322
+#: engines/scumm/help.cpp:334
msgid "Fly down"
msgstr "Vlieg omlaag"
-#: engines/scumm/help.cpp:323
+#: engines/scumm/help.cpp:335
msgid "Fly to upper right"
msgstr "Vlieg naar rechts omhoog"
-#: engines/scumm/help.cpp:324
+#: engines/scumm/help.cpp:336
msgid "Fly to right"
msgstr "Vlieg naar rechts"
-#: engines/scumm/help.cpp:325
+#: engines/scumm/help.cpp:337
msgid "Fly to lower right"
msgstr "Vlieg naar rechts omlaag"
-#: engines/scumm/scumm.cpp:1823
+#: engines/scumm/scumm.cpp:1832
#, c-format
msgid ""
"Native MIDI support requires the Roland Upgrade from LucasArts,\n"
@@ -3221,11 +3310,12 @@ msgstr ""
"Voor MIDI support is de Roland Upgrade van Lucasarts vereist,\n"
"maar %s ontbreekt. Er wordt nu AdLib gebruikt."
-#: engines/scumm/scumm.cpp:2594
+#: engines/scumm/scumm.cpp:2644
+#, fuzzy
msgid ""
-"Usually, Maniac Mansion would start now. But ScummVM doesn't do that yet. To "
-"play it, go to 'Add Game' in the ScummVM start menu and select the 'Maniac' "
-"directory inside the Tentacle game directory."
+"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 "
@@ -3367,3 +3457,46 @@ msgstr "Toon FPS-teller"
#: engines/wintermute/detection.cpp:59
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.cpp:256
+msgid "Double FPS"
+msgstr ""
+
+#: engines/zvision/detection.cpp:257
+msgid "Increase game FPS from 30 to 60"
+msgstr ""
+
+#: engines/zvision/detection.cpp:266
+#, fuzzy
+msgid "Enable Venus"
+msgstr "Helium-modus aangezet"
+
+#: engines/zvision/detection.cpp:267
+msgid "Enable the Venus help system"
+msgstr ""
+
+#: engines/zvision/detection.cpp:276
+msgid "Disable animation while turning"
+msgstr ""
+
+#: engines/zvision/detection.cpp:277
+msgid "Disable animation while turning in panoramic mode"
+msgstr ""
+
+#: engines/zvision/detection.cpp:286
+msgid "Use the hires MPEG movies"
+msgstr ""
+
+#: engines/zvision/detection.cpp:287
+#, fuzzy
+msgid ""
+"Use the hires MPEG movies of the DVD version, instead of the lowres AVI ones"
+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"
diff --git a/po/nn_NO.po b/po/nn_NO.po
index 13a19fe8d3..2741620b8e 100644
--- a/po/nn_NO.po
+++ b/po/nn_NO.po
@@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: ScummVM 1.3.0svn\n"
"Report-Msgid-Bugs-To: scummvm-devel@lists.sf.net\n"
-"POT-Creation-Date: 2014-10-04 00:58+0100\n"
+"POT-Creation-Date: 2015-06-30 20:57+0100\n"
"PO-Revision-Date: 2014-07-11 00:04+0100\n"
"Last-Translator: Einar Johan Trјan Sјmхen <einarjohants@gmail.com>\n"
"Language-Team: somaen <einarjohants@gmail.com>\n"
@@ -55,10 +55,11 @@ msgstr "Oppover"
#: gui/browser.cpp:75 gui/chooser.cpp:46 gui/KeysDialog.cpp:43
#: gui/launcher.cpp:351 gui/massadd.cpp:95 gui/options.cpp:1239
+#: gui/recorderdialog.cpp:70 gui/recorderdialog.cpp:156
#: gui/saveload-dialog.cpp:216 gui/saveload-dialog.cpp:276
-#: gui/saveload-dialog.cpp:547 gui/saveload-dialog.cpp:922
+#: gui/saveload-dialog.cpp:547 gui/saveload-dialog.cpp:931
#: gui/themebrowser.cpp:55 gui/fluidsynth-dialog.cpp:152
-#: engines/engine.cpp:452 backends/platform/wii/options.cpp:48
+#: engines/engine.cpp:483 backends/platform/wii/options.cpp:48
#: backends/events/default/default-events.cpp:196
#: backends/events/default/default-events.cpp:218
#: engines/drascula/saveload.cpp:49 engines/parallaction/saveload.cpp:274
@@ -71,9 +72,9 @@ msgid "Choose"
msgstr "Vel"
#: gui/gui-manager.cpp:117 backends/keymapper/remap-dialog.cpp:53
-#: 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
+#: 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"
@@ -89,7 +90,7 @@ msgstr "Syn Tastatur"
msgid "Remap keys"
msgstr "Omkople tastar"
-#: gui/gui-manager.cpp:131 base/main.cpp:326 engines/scumm/help.cpp:86
+#: gui/gui-manager.cpp:131 base/main.cpp:326 engines/scumm/help.cpp:87
msgid "Toggle fullscreen"
msgstr "Veksle fullskjerm"
@@ -103,13 +104,13 @@ 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:1240
-#: gui/saveload-dialog.cpp:923 gui/fluidsynth-dialog.cpp:153
-#: engines/engine.cpp:371 engines/engine.cpp:382
+#: 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:399 engines/parallaction/saveload.cpp:274
-#: engines/scumm/dialogs.cpp:193 engines/scumm/scumm.cpp:1825
+#: 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
@@ -478,7 +479,7 @@ msgstr ""
#: gui/launcher.cpp:793 gui/launcher.cpp:941 gui/launcher.cpp:1000
#: gui/fluidsynth-dialog.cpp:217
-#: backends/events/symbiansdl/symbiansdl-events.cpp:184
+#: 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
@@ -488,7 +489,7 @@ 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:184
+#: 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
@@ -526,6 +527,14 @@ msgstr ""
"ScummVM kunne ikkje finne nokon motor som var i stand til х kјyre det velde "
"spelet!"
+#: gui/launcher.cpp:1159
+msgid "Mass Add..."
+msgstr "Legg til fleire..."
+
+#: gui/launcher.cpp:1161
+msgid "Record..."
+msgstr ""
+
#: gui/massadd.cpp:79 gui/massadd.cpp:82
msgid "... progress ..."
msgstr "... fremdrift ..."
@@ -624,7 +633,7 @@ msgid "Special dithering modes supported by some games"
msgstr "Spesielle dithering-modus som stјttast av nokre spel"
#: gui/options.cpp:760
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2249
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2298
msgid "Fullscreen mode"
msgstr "Fullskjermsmodus"
@@ -937,6 +946,43 @@ msgstr ""
"Temaet du har valt stјttar ikkje det aktive sprхket. Om du vil nytte dette "
"temaet mх du bytte til eit anna sprхk fјrst."
+#: gui/recorderdialog.cpp:64
+msgid "Recorder or Playback Gameplay"
+msgstr ""
+
+#: gui/recorderdialog.cpp:69 gui/recorderdialog.cpp:156
+#: gui/saveload-dialog.cpp:220 gui/saveload-dialog.cpp:276
+msgid "Delete"
+msgstr "Slett"
+
+#: gui/recorderdialog.cpp:71
+msgid "Record"
+msgstr ""
+
+#: gui/recorderdialog.cpp:72
+#, fuzzy
+msgid "Playback"
+msgstr "Spel"
+
+#: gui/recorderdialog.cpp:74
+msgid "Edit"
+msgstr ""
+
+#: gui/recorderdialog.cpp:86 gui/recorderdialog.cpp:243
+#: gui/recorderdialog.cpp:253
+msgid "Author: "
+msgstr ""
+
+#: gui/recorderdialog.cpp:87 gui/recorderdialog.cpp:244
+#: gui/recorderdialog.cpp:254
+msgid "Notes: "
+msgstr ""
+
+#: gui/recorderdialog.cpp:155
+#, fuzzy
+msgid "Do you really want to delete this record?"
+msgstr "Vil du verkeleg slette det lagra spelet?"
+
#: gui/saveload-dialog.cpp:167
msgid "List view"
msgstr "Listevisning"
@@ -957,23 +1003,19 @@ msgstr "Inga tid lagra"
msgid "No playtime saved"
msgstr "Inga speletid lagra"
-#: gui/saveload-dialog.cpp:220 gui/saveload-dialog.cpp:276
-msgid "Delete"
-msgstr "Slett"
-
#: gui/saveload-dialog.cpp:275
msgid "Do you really want to delete this saved game?"
msgstr "Vil du verkeleg slette det lagra spelet?"
-#: gui/saveload-dialog.cpp:385 gui/saveload-dialog.cpp:875
+#: gui/saveload-dialog.cpp:385 gui/saveload-dialog.cpp:884
msgid "Date: "
msgstr "Dato: "
-#: gui/saveload-dialog.cpp:389 gui/saveload-dialog.cpp:881
+#: gui/saveload-dialog.cpp:389 gui/saveload-dialog.cpp:890
msgid "Time: "
msgstr "Tid: "
-#: gui/saveload-dialog.cpp:395 gui/saveload-dialog.cpp:889
+#: gui/saveload-dialog.cpp:395 gui/saveload-dialog.cpp:898
msgid "Playtime: "
msgstr "Speletid: "
@@ -989,19 +1031,19 @@ msgstr "Neste"
msgid "Prev"
msgstr "Forrige"
-#: gui/saveload-dialog.cpp:739
+#: gui/saveload-dialog.cpp:748
msgid "New Save"
msgstr "Ny Lagring"
-#: gui/saveload-dialog.cpp:739
+#: gui/saveload-dialog.cpp:748
msgid "Create a new save game"
msgstr "Lag eit nytt lagra spel"
-#: gui/saveload-dialog.cpp:868
+#: gui/saveload-dialog.cpp:877
msgid "Name: "
msgstr "Namn:"
-#: gui/saveload-dialog.cpp:940
+#: gui/saveload-dialog.cpp:949
#, c-format
msgid "Enter a description for slot %d:"
msgstr ""
@@ -1153,7 +1195,7 @@ msgstr "Hopp over linje"
msgid "Error running game:"
msgstr "Feil under kјyring av spel:"
-#: base/main.cpp:536
+#: base/main.cpp:554
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."
@@ -1271,7 +1313,7 @@ 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:758
+#: engines/pegasus/pegasus.cpp:377 engines/sci/engine/kfile.cpp:759
#: engines/toltecs/menu.cpp:281 engines/tsage/scenes.cpp:598
msgid "Save game:"
msgstr "Lagra spel:"
@@ -1284,7 +1326,7 @@ msgstr "Lagra spel:"
#: 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:758 engines/scumm/dialogs.cpp:188
+#: engines/sci/engine/kfile.cpp:759 engines/scumm/dialogs.cpp:188
#: engines/toltecs/menu.cpp:281 engines/tsage/scenes.cpp:598
msgid "Save"
msgstr "Lagre"
@@ -1317,24 +1359,24 @@ msgstr "~A~vbryt"
msgid "~K~eys"
msgstr "~T~astar"
-#: engines/engine.cpp:245
+#: engines/engine.cpp:276
msgid "Could not initialize color format."
msgstr ""
-#: engines/engine.cpp:253
+#: engines/engine.cpp:284
msgid "Could not switch to video mode: '"
msgstr "Kunne ikkje veksle til videomodus: '"
-#: engines/engine.cpp:262
+#: engines/engine.cpp:293
#, fuzzy
msgid "Could not apply aspect ratio setting."
msgstr "Veksle aspekt-korrigering"
-#: engines/engine.cpp:267
+#: engines/engine.cpp:298
msgid "Could not apply fullscreen setting."
msgstr ""
-#: engines/engine.cpp:367
+#: engines/engine.cpp:398
msgid ""
"You appear to be playing this game directly\n"
"from the CD. This is known to cause problems,\n"
@@ -1343,7 +1385,7 @@ msgid ""
"See the README file for details."
msgstr ""
-#: engines/engine.cpp:378
+#: engines/engine.cpp:409
msgid ""
"This game has audio tracks in its disk. These\n"
"tracks need to be ripped from the disk using\n"
@@ -1352,14 +1394,14 @@ msgid ""
"See the README file for details."
msgstr ""
-#: engines/engine.cpp:436
+#: engines/engine.cpp:467
#, 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:449
+#: engines/engine.cpp:480
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 "
@@ -1369,7 +1411,7 @@ 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:452
+#: engines/engine.cpp:483
msgid "Start anyway"
msgstr "Start allikevel"
@@ -1575,11 +1617,11 @@ msgstr "~O~vergangar aktivert"
msgid "Touchpad mode disabled."
msgstr "Deaktivert GFX"
-#: backends/platform/maemo/maemo.cpp:209
+#: backends/platform/maemo/maemo.cpp:208
msgid "Click Mode"
msgstr "Klikkmodus"
-#: backends/platform/maemo/maemo.cpp:215
+#: backends/platform/maemo/maemo.cpp:214
#: backends/platform/symbian/src/SymbianActions.cpp:42
#: backends/platform/wince/CEActionsPocket.cpp:60
#: backends/platform/wince/CEActionsSmartphone.cpp:43
@@ -1587,11 +1629,11 @@ msgstr "Klikkmodus"
msgid "Left Click"
msgstr "Venstreklikk"
-#: backends/platform/maemo/maemo.cpp:218
+#: backends/platform/maemo/maemo.cpp:217
msgid "Middle Click"
msgstr "Midtklikk"
-#: backends/platform/maemo/maemo.cpp:221
+#: 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
@@ -1628,21 +1670,21 @@ msgctxt "lowres"
msgid "Normal (no scaling)"
msgstr "Normal (ikkje skaler)"
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2148
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2197
#, fuzzy
msgid "Enabled aspect ratio correction"
msgstr "Aspekt-korrigering"
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2154
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2203
#, fuzzy
msgid "Disabled aspect ratio correction"
msgstr "Aspekt-korrigering"
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2209
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2258
msgid "Active graphics filter:"
msgstr "Aktivt grafikkfilter:"
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2251
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2300
msgid "Windowed mode"
msgstr "Vindusmodus"
@@ -1702,8 +1744,8 @@ msgstr "Rask modus"
#: 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:82
-#: engines/scumm/help.cpp:84
+#: engines/scumm/dialogs.cpp:192 engines/scumm/help.cpp:83
+#: engines/scumm/help.cpp:85
msgid "Quit"
msgstr "Avslutt"
@@ -1723,7 +1765,7 @@ msgstr "Virtuelt tastatur"
msgid "Key mapper"
msgstr "Tastkopler"
-#: backends/events/symbiansdl/symbiansdl-events.cpp:184
+#: backends/events/symbiansdl/symbiansdl-events.cpp:186
msgid "Do you want to quit ?"
msgstr "Vil du avslutte?"
@@ -2071,33 +2113,54 @@ msgstr "~O~vergangar aktivert"
msgid "Clicking Disabled"
msgstr "Klikking Deaktivert"
-#: engines/agi/detection.cpp:142 engines/drascula/detection.cpp:302
+#: 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.cpp:103
+#: engines/zvision/detection.cpp:246
msgid "Use original save/load screens"
msgstr "Nytt opprinnelege skjermar for lagring/lasting"
-#: engines/agi/detection.cpp:143 engines/drascula/detection.cpp:303
+#: 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/zvision/detection.cpp:104
+#: engines/zvision/detection.cpp:247
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)"
+
+#: engines/agi/detection.cpp:158
+msgid ""
+"Use an alternative palette, common for all Amiga games. This was the old "
+"behavior"
+msgstr ""
+
+#: engines/agi/detection.cpp:167
+#, fuzzy
+msgid "Mouse support"
+msgstr "Hopp over"
+
+#: 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:857 engines/toltecs/menu.cpp:256
+#: engines/sci/engine/kfile.cpp:858 engines/toltecs/menu.cpp:256
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:857 engines/toltecs/menu.cpp:256
+#: engines/sci/engine/kfile.cpp:858 engines/toltecs/menu.cpp:256
msgid "Restore"
msgstr "Gjenopprett"
-#: engines/agos/saveload.cpp:160 engines/scumm/scumm.cpp:2368
+#: engines/agos/saveload.cpp:160 engines/scumm/scumm.cpp:2377
#, c-format
msgid ""
"Failed to load game state from file:\n"
@@ -2105,7 +2168,7 @@ msgid ""
"%s"
msgstr ""
-#: engines/agos/saveload.cpp:195 engines/scumm/scumm.cpp:2361
+#: engines/agos/saveload.cpp:195 engines/scumm/scumm.cpp:2370
#, c-format
msgid ""
"Failed to save game state to file:\n"
@@ -2113,7 +2176,7 @@ msgid ""
"%s"
msgstr ""
-#: engines/agos/saveload.cpp:203 engines/scumm/scumm.cpp:2379
+#: engines/agos/saveload.cpp:203 engines/scumm/scumm.cpp:2388
#, c-format
msgid ""
"Successfully saved game state in file:\n"
@@ -2126,12 +2189,12 @@ msgstr ""
msgid "Cutscene file '%s' not found!"
msgstr ""
-#: engines/cge/detection.cpp:105 engines/cge2/detection.cpp:81
+#: engines/cge/detection.cpp:105 engines/cge2/detection.cpp:101
#, fuzzy
msgid "Color Blind Mode"
msgstr "Klikkmodus"
-#: engines/cge/detection.cpp:106 engines/cge2/detection.cpp:82
+#: engines/cge/detection.cpp:106 engines/cge2/detection.cpp:102
msgid "Enable Color Blind Mode by default"
msgstr ""
@@ -2178,7 +2241,7 @@ msgstr "Rask modus"
msgid "Play movies at an increased speed"
msgstr "Spel filmar med auka hastighet"
-#: engines/groovie/script.cpp:399
+#: engines/groovie/script.cpp:408
#, fuzzy
msgid "Failed to save game"
msgstr "Lagra spel:"
@@ -2478,11 +2541,11 @@ msgid "Use an alternative game intro (CD version only)"
msgstr "Nytt diskettversjonens хpning (Kun CD-versjon)"
#: engines/sci/detection.cpp:374
-msgid "EGA undithering"
+msgid "Skip EGA dithering pass (full color backgrounds)"
msgstr ""
#: engines/sci/detection.cpp:375
-msgid "Enable undithering in EGA games"
+msgid "Skip dithering pass in EGA games, graphics are shown with full colors"
msgstr ""
#: engines/sci/detection.cpp:384
@@ -2552,12 +2615,14 @@ msgstr "Spelet er pausa. Trykk MELLOMROM for х fortsette."
#. "Moechten Sie wirklich neu starten? (J/N)J"
#. Will react to J as 'Yes'
#: engines/scumm/dialogs.cpp:183
-msgid "Are you sure you want to restart? (Y/N)"
+#, fuzzy
+msgid "Are you sure you want to restart? (Y/N)Y"
msgstr "Er du sikker pх at du vil starte pх nytt (Y/N)?"
#. I18N: you may specify 'Yes' symbol at the end of the line. See previous comment
#: engines/scumm/dialogs.cpp:185
-msgid "Are you sure you want to quit? (Y/N)"
+#, fuzzy
+msgid "Are you sure you want to quit? (Y/N)Y"
msgstr "Er du sikker pх at du vil avslutte (Y/N)?"
#: engines/scumm/dialogs.cpp:190
@@ -2648,528 +2713,553 @@ msgstr ""
msgid "Expert"
msgstr "Ekspert"
-#: engines/scumm/help.cpp:73
+#: engines/scumm/help.cpp:74
msgid "Common keyboard commands:"
msgstr "Vanlege tastaturkommandoar:"
-#: engines/scumm/help.cpp:74
+#: engines/scumm/help.cpp:75
msgid "Save / Load dialog"
msgstr "Хpne- / Lagre-dialog"
-#: engines/scumm/help.cpp:76
+#: engines/scumm/help.cpp:77
msgid "Skip line of text"
msgstr "Hopp over tekstlinje"
-#: engines/scumm/help.cpp:77
+#: engines/scumm/help.cpp:78
msgid "Esc"
msgstr "Esc"
-#: engines/scumm/help.cpp:77
+#: engines/scumm/help.cpp:78
msgid "Skip cutscene"
msgstr "Hopp over cutscene"
-#: engines/scumm/help.cpp:78
+#: engines/scumm/help.cpp:79
msgid "Space"
msgstr "Opprom"
-#: engines/scumm/help.cpp:78
+#: engines/scumm/help.cpp:79
msgid "Pause game"
msgstr "Pause spel"
-#: engines/scumm/help.cpp:79 engines/scumm/help.cpp:84
-#: engines/scumm/help.cpp:95 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: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:79
+#: engines/scumm/help.cpp:80
msgid "Load game state 1-10"
msgstr "Хpne speltilstand 1-10"
-#: engines/scumm/help.cpp:80 engines/scumm/help.cpp:84
-#: engines/scumm/help.cpp:86 engines/scumm/help.cpp:100
-#: engines/scumm/help.cpp:101 engines/scumm/help.cpp:102
+#: 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:80
+#: engines/scumm/help.cpp:81
msgid "Save game state 1-10"
msgstr "Lagre speltilstand 1-10"
-#: engines/scumm/help.cpp:86 engines/scumm/help.cpp:89
+#: engines/scumm/help.cpp:87 engines/scumm/help.cpp:90
msgid "Enter"
msgstr "Enter"
-#: engines/scumm/help.cpp:87
+#: engines/scumm/help.cpp:88
msgid "Music volume up / down"
msgstr "Musikkvolum opp / ned"
-#: engines/scumm/help.cpp:88
+#: engines/scumm/help.cpp:89
msgid "Text speed slower / faster"
msgstr "Tekstfart saktare / fortare"
-#: engines/scumm/help.cpp:89
+#: engines/scumm/help.cpp:90
msgid "Simulate left mouse button"
msgstr "Simuler venstre musknapp"
-#: engines/scumm/help.cpp:90
+#: engines/scumm/help.cpp:91
msgid "Tab"
msgstr "Tab"
-#: engines/scumm/help.cpp:90
+#: engines/scumm/help.cpp:91
msgid "Simulate right mouse button"
msgstr "Simuler hјgre musknapp"
-#: engines/scumm/help.cpp:93
+#: engines/scumm/help.cpp:94
msgid "Special keyboard commands:"
msgstr "Spesielle tastaturkommandoar:"
-#: engines/scumm/help.cpp:94
+#: engines/scumm/help.cpp:95
msgid "Show / Hide console"
msgstr "Vis / Skjul konsoll"
-#: engines/scumm/help.cpp:95
+#: engines/scumm/help.cpp:96
msgid "Start the debugger"
msgstr "Start debuggaren"
-#: engines/scumm/help.cpp:96
+#: engines/scumm/help.cpp:97
msgid "Show memory consumption"
msgstr "Vis minneforbruk"
-#: engines/scumm/help.cpp:97
+#: engines/scumm/help.cpp:98
msgid "Run in fast mode (*)"
msgstr "Kјyr i rask modus (*)"
-#: engines/scumm/help.cpp:98
+#: engines/scumm/help.cpp:99
msgid "Run in really fast mode (*)"
msgstr "Kјyr i verkeleg rask modus (*)"
-#: engines/scumm/help.cpp:99
+#: engines/scumm/help.cpp:100
msgid "Toggle mouse capture"
msgstr "Veksle muslхsing"
-#: engines/scumm/help.cpp:100
+#: engines/scumm/help.cpp:101
msgid "Switch between graphics filters"
msgstr "Veksle grafikkfiltre"
-#: engines/scumm/help.cpp:101
+#: engines/scumm/help.cpp:102
msgid "Increase / Decrease scale factor"
msgstr "иk/Minsk skaleringsfaktor"
-#: engines/scumm/help.cpp:102
+#: engines/scumm/help.cpp:103
msgid "Toggle aspect-ratio correction"
msgstr "Veksle aspekt-korrigering"
-#: engines/scumm/help.cpp:107
+#: engines/scumm/help.cpp:108
msgid "* Note that using ctrl-f and"
msgstr "* Merk at х bruke ctrl-f og"
-#: engines/scumm/help.cpp:108
+#: engines/scumm/help.cpp:109
msgid " ctrl-g are not recommended"
msgstr " ctrl-g er ikkje anbefalt dх"
-#: engines/scumm/help.cpp:109
+#: engines/scumm/help.cpp:110
msgid " since they may cause crashes"
msgstr " dei kan forхrsake krцsj og"
-#: engines/scumm/help.cpp:110
+#: engines/scumm/help.cpp:111
#, fuzzy
msgid " or incorrect game behavior."
msgstr "Spel"
-#: engines/scumm/help.cpp:114
+#: engines/scumm/help.cpp:115
msgid "Spinning drafts on the keyboard:"
msgstr "Spinne drafts pх tastaturet:"
-#: engines/scumm/help.cpp:116
+#: engines/scumm/help.cpp:117
msgid "Main game controls:"
msgstr "Hovedkontrollar for spel:"
-#: engines/scumm/help.cpp:121 engines/scumm/help.cpp:136
-#: engines/scumm/help.cpp:161
+#: engines/scumm/help.cpp:122 engines/scumm/help.cpp:137
+#: engines/scumm/help.cpp:162
msgid "Push"
msgstr "Dytt"
-#: engines/scumm/help.cpp:122 engines/scumm/help.cpp:137
-#: engines/scumm/help.cpp:162
+#: engines/scumm/help.cpp:123 engines/scumm/help.cpp:138
+#: engines/scumm/help.cpp:163
msgid "Pull"
msgstr "Dra"
-#: engines/scumm/help.cpp:123 engines/scumm/help.cpp:138
-#: engines/scumm/help.cpp:163 engines/scumm/help.cpp:197
-#: engines/scumm/help.cpp:207
+#: 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 "Gi"
-#: engines/scumm/help.cpp:124 engines/scumm/help.cpp:139
-#: engines/scumm/help.cpp:164 engines/scumm/help.cpp:190
-#: engines/scumm/help.cpp:208
+#: 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 "Хpne"
-#: engines/scumm/help.cpp:126
+#: engines/scumm/help.cpp:127
msgid "Go to"
msgstr "Gх til"
-#: engines/scumm/help.cpp:127
+#: engines/scumm/help.cpp:128
msgid "Get"
msgstr "Fх"
-#: engines/scumm/help.cpp:128 engines/scumm/help.cpp:152
-#: engines/scumm/help.cpp:170 engines/scumm/help.cpp:198
-#: engines/scumm/help.cpp:213 engines/scumm/help.cpp:224
-#: engines/scumm/help.cpp:250
+#: 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 "Nytt"
-#: engines/scumm/help.cpp:129 engines/scumm/help.cpp:141
+#: engines/scumm/help.cpp:130 engines/scumm/help.cpp:142
msgid "Read"
msgstr "Les"
-#: engines/scumm/help.cpp:130 engines/scumm/help.cpp:147
+#: engines/scumm/help.cpp:131 engines/scumm/help.cpp:148
msgid "New kid"
msgstr "Bytt unge"
-#: engines/scumm/help.cpp:131 engines/scumm/help.cpp:153
-#: engines/scumm/help.cpp:171
+#: engines/scumm/help.cpp:132 engines/scumm/help.cpp:154
+#: engines/scumm/help.cpp:172
msgid "Turn on"
msgstr "Slх pх"
-#: engines/scumm/help.cpp:132 engines/scumm/help.cpp:154
-#: engines/scumm/help.cpp:172
+#: engines/scumm/help.cpp:133 engines/scumm/help.cpp:155
+#: engines/scumm/help.cpp:173
msgid "Turn off"
msgstr "Slх av"
-#: engines/scumm/help.cpp:142 engines/scumm/help.cpp:167
-#: engines/scumm/help.cpp:194
+#: engines/scumm/help.cpp:143 engines/scumm/help.cpp:168
+#: engines/scumm/help.cpp:195
msgid "Walk to"
msgstr "Gх til"
-#: engines/scumm/help.cpp:143 engines/scumm/help.cpp:168
-#: engines/scumm/help.cpp:195 engines/scumm/help.cpp:210
-#: engines/scumm/help.cpp:227
+#: 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 "Plukk opp"
-#: engines/scumm/help.cpp:144 engines/scumm/help.cpp:169
+#: engines/scumm/help.cpp:145 engines/scumm/help.cpp:170
msgid "What is"
msgstr "Kva er"
-#: engines/scumm/help.cpp:146
+#: engines/scumm/help.cpp:147
msgid "Unlock"
msgstr "Lхs opp"
-#: engines/scumm/help.cpp:149
+#: engines/scumm/help.cpp:150
msgid "Put on"
msgstr "Ta pх (klede)"
-#: engines/scumm/help.cpp:150
+#: engines/scumm/help.cpp:151
msgid "Take off"
msgstr "Ta av (klede)"
-#: engines/scumm/help.cpp:156
+#: engines/scumm/help.cpp:157
msgid "Fix"
msgstr "Fiks"
-#: engines/scumm/help.cpp:158
+#: engines/scumm/help.cpp:159
msgid "Switch"
msgstr "Bytt"
-#: engines/scumm/help.cpp:166 engines/scumm/help.cpp:228
+#: engines/scumm/help.cpp:167 engines/scumm/help.cpp:229
msgid "Look"
msgstr "Kikk"
-#: engines/scumm/help.cpp:173 engines/scumm/help.cpp:223
+#: engines/scumm/help.cpp:174 engines/scumm/help.cpp:224
msgid "Talk"
msgstr "Snakk"
-#: engines/scumm/help.cpp:174
+#: engines/scumm/help.cpp:175
msgid "Travel"
msgstr "Reis"
-#: engines/scumm/help.cpp:175
+#: engines/scumm/help.cpp:176
msgid "To Henry / To Indy"
msgstr "Til Henry / Til Indy"
#. I18N: These are different musical notes
-#: engines/scumm/help.cpp:179
+#: engines/scumm/help.cpp:180
msgid "play C minor on distaff"
msgstr "spel C moll pх distaffen "
-#: engines/scumm/help.cpp:180
+#: engines/scumm/help.cpp:181
msgid "play D on distaff"
msgstr "spel D pх distaffen"
-#: engines/scumm/help.cpp:181
+#: engines/scumm/help.cpp:182
msgid "play E on distaff"
msgstr "spel E pх distaffen"
-#: engines/scumm/help.cpp:182
+#: engines/scumm/help.cpp:183
msgid "play F on distaff"
msgstr "spel F pх distaffen"
-#: engines/scumm/help.cpp:183
+#: engines/scumm/help.cpp:184
msgid "play G on distaff"
msgstr "spel G pх distaffen"
-#: engines/scumm/help.cpp:184
+#: engines/scumm/help.cpp:185
msgid "play A on distaff"
msgstr "spel A pх distaffen"
-#: engines/scumm/help.cpp:185
+#: engines/scumm/help.cpp:186
msgid "play B on distaff"
msgstr "spel H pх distaffen"
-#: engines/scumm/help.cpp:186
+#: engines/scumm/help.cpp:187
msgid "play C major on distaff"
msgstr "spel C dur pх distaffen"
-#: engines/scumm/help.cpp:192 engines/scumm/help.cpp:214
+#: engines/scumm/help.cpp:193 engines/scumm/help.cpp:215
msgid "puSh"
msgstr "Dytt"
-#: engines/scumm/help.cpp:193 engines/scumm/help.cpp:215
+#: engines/scumm/help.cpp:194 engines/scumm/help.cpp:216
msgid "pull (Yank)"
msgstr "Dra"
-#: engines/scumm/help.cpp:196 engines/scumm/help.cpp:212
-#: engines/scumm/help.cpp:248
+#: engines/scumm/help.cpp:197 engines/scumm/help.cpp:213
+#: engines/scumm/help.cpp:249
msgid "Talk to"
msgstr "Snakk til"
-#: engines/scumm/help.cpp:199 engines/scumm/help.cpp:211
+#: engines/scumm/help.cpp:200 engines/scumm/help.cpp:212
msgid "Look at"
msgstr "Se pх"
-#: engines/scumm/help.cpp:200
+#: engines/scumm/help.cpp:201
msgid "turn oN"
msgstr "Slх pх"
-#: engines/scumm/help.cpp:201
+#: engines/scumm/help.cpp:202
msgid "turn oFf"
msgstr "Slх av"
-#: engines/scumm/help.cpp:217
+#: engines/scumm/help.cpp:218
msgid "KeyUp"
msgstr "Opp-tast"
-#: engines/scumm/help.cpp:217
+#: engines/scumm/help.cpp:218
msgid "Highlight prev dialogue"
msgstr "Merk forrige dialog"
-#: engines/scumm/help.cpp:218
+#: engines/scumm/help.cpp:219
msgid "KeyDown"
msgstr "Ned-tast"
-#: engines/scumm/help.cpp:218
+#: engines/scumm/help.cpp:219
msgid "Highlight next dialogue"
msgstr "Merk neste dialog"
-#: engines/scumm/help.cpp:222
+#: engines/scumm/help.cpp:223
msgid "Walk"
msgstr "Gх"
-#: engines/scumm/help.cpp:225 engines/scumm/help.cpp:234
-#: engines/scumm/help.cpp:241 engines/scumm/help.cpp:249
+#: engines/scumm/help.cpp:226 engines/scumm/help.cpp:235
+#: engines/scumm/help.cpp:242 engines/scumm/help.cpp:250
msgid "Inventory"
msgstr "Inventar"
-#: engines/scumm/help.cpp:226
+#: engines/scumm/help.cpp:227
msgid "Object"
msgstr "Objekt"
-#: engines/scumm/help.cpp:229
+#: engines/scumm/help.cpp:230
msgid "Black and White / Color"
msgstr "Svart-Kvitt / Fargar"
-#: engines/scumm/help.cpp:232
+#: engines/scumm/help.cpp:233
msgid "Eyes"
msgstr "Auger"
-#: engines/scumm/help.cpp:233
+#: engines/scumm/help.cpp:234
msgid "Tongue"
msgstr "Tunge"
-#: engines/scumm/help.cpp:235
+#: engines/scumm/help.cpp:236
msgid "Punch"
msgstr "Slх"
-#: engines/scumm/help.cpp:236
+#: engines/scumm/help.cpp:237
msgid "Kick"
msgstr "Spark"
-#: engines/scumm/help.cpp:239 engines/scumm/help.cpp:247
+#: engines/scumm/help.cpp:240 engines/scumm/help.cpp:248
msgid "Examine"
msgstr "Undersјk"
-#: engines/scumm/help.cpp:240
+#: engines/scumm/help.cpp:241
msgid "Regular cursor"
msgstr "Vanleg peikar"
#. I18N: Comm is a communication device
-#: engines/scumm/help.cpp:243
+#: engines/scumm/help.cpp:244
msgid "Comm"
msgstr "Comm"
-#: engines/scumm/help.cpp:246
+#: engines/scumm/help.cpp:247
msgid "Save / Load / Options"
msgstr "Хpne / Lagre / Val"
-#: engines/scumm/help.cpp:255
+#: engines/scumm/help.cpp:256
msgid "Other game controls:"
msgstr "Andre spelkontrollar:"
-#: engines/scumm/help.cpp:257 engines/scumm/help.cpp:267
+#: engines/scumm/help.cpp:258 engines/scumm/help.cpp:268
msgid "Inventory:"
msgstr "Inventar:"
-#: engines/scumm/help.cpp:258 engines/scumm/help.cpp:274
+#: engines/scumm/help.cpp:259 engines/scumm/help.cpp:275
msgid "Scroll list up"
msgstr "Bla liste opp"
-#: engines/scumm/help.cpp:259 engines/scumm/help.cpp:275
+#: engines/scumm/help.cpp:260 engines/scumm/help.cpp:276
msgid "Scroll list down"
msgstr "Bla liste ned"
-#: engines/scumm/help.cpp:260 engines/scumm/help.cpp:268
+#: engines/scumm/help.cpp:261 engines/scumm/help.cpp:269
msgid "Upper left item"
msgstr "иvre venstre gjenstand"
-#: engines/scumm/help.cpp:261 engines/scumm/help.cpp:270
+#: engines/scumm/help.cpp:262 engines/scumm/help.cpp:271
msgid "Lower left item"
msgstr "Nedre venstre gjenstand"
-#: engines/scumm/help.cpp:262 engines/scumm/help.cpp:271
+#: engines/scumm/help.cpp:263 engines/scumm/help.cpp:272
msgid "Upper right item"
msgstr "иvre hјgre gjenstand"
-#: engines/scumm/help.cpp:263 engines/scumm/help.cpp:273
+#: engines/scumm/help.cpp:264 engines/scumm/help.cpp:274
msgid "Lower right item"
msgstr "Nedre hјgre gjenstand"
-#: engines/scumm/help.cpp:269
+#: engines/scumm/help.cpp:270
msgid "Middle left item"
msgstr "Midtre venstre gjenstand"
-#: engines/scumm/help.cpp:272
+#: engines/scumm/help.cpp:273
msgid "Middle right item"
msgstr "Midtre hјgre gjenstand"
-#: engines/scumm/help.cpp:279 engines/scumm/help.cpp:284
+#: engines/scumm/help.cpp:280 engines/scumm/help.cpp:285
msgid "Switching characters:"
msgstr "Veksle karakterar:"
-#: engines/scumm/help.cpp:281
+#: engines/scumm/help.cpp:282
msgid "Second kid"
msgstr "Andre unge"
-#: engines/scumm/help.cpp:282
+#: engines/scumm/help.cpp:283
msgid "Third kid"
msgstr "Tredje unge"
-#: engines/scumm/help.cpp:294
+#: engines/scumm/help.cpp:292
+msgid "Toggle Inventory/IQ Points display"
+msgstr ""
+
+#: engines/scumm/help.cpp:293
+msgid "Toggle Keyboard/Mouse Fighting (*)"
+msgstr ""
+
+#: engines/scumm/help.cpp:295
+msgid "* Keyboard Fighting is always on,"
+msgstr ""
+
+#: engines/scumm/help.cpp:296
+msgid " so despite the in-game message this"
+msgstr ""
+
+#: engines/scumm/help.cpp:297
+msgid " actually toggles Mouse Fighting Off/On"
+msgstr ""
+
+#: engines/scumm/help.cpp:304
msgid "Fighting controls (numpad):"
msgstr "Kampkontrollar (taltastatur)"
-#: engines/scumm/help.cpp:295 engines/scumm/help.cpp:296
-#: engines/scumm/help.cpp:297
+#: engines/scumm/help.cpp:305 engines/scumm/help.cpp:306
+#: engines/scumm/help.cpp:307
msgid "Step back"
msgstr "Bakoversteg"
-#: engines/scumm/help.cpp:298
+#: engines/scumm/help.cpp:308
msgid "Block high"
msgstr "Hјg blokk"
-#: engines/scumm/help.cpp:299
+#: engines/scumm/help.cpp:309
msgid "Block middle"
msgstr "Midt blokk"
-#: engines/scumm/help.cpp:300
+#: engines/scumm/help.cpp:310
msgid "Block low"
msgstr "Lav blokk"
-#: engines/scumm/help.cpp:301
+#: engines/scumm/help.cpp:311
msgid "Punch high"
msgstr "Hјgt slag"
-#: engines/scumm/help.cpp:302
+#: engines/scumm/help.cpp:312
msgid "Punch middle"
msgstr "Midtslag"
-#: engines/scumm/help.cpp:303
+#: engines/scumm/help.cpp:313
msgid "Punch low"
msgstr "Lavt slag"
-#: engines/scumm/help.cpp:306
+#: engines/scumm/help.cpp:315
+msgid "Sucker punch"
+msgstr ""
+
+#: engines/scumm/help.cpp:318
msgid "These are for Indy on left."
msgstr "Gjeld Indy pх Venstre side."
-#: engines/scumm/help.cpp:307
+#: engines/scumm/help.cpp:319
msgid "When Indy is on the right,"
msgstr "Med Indy pх hјgre side,"
-#: engines/scumm/help.cpp:308
+#: engines/scumm/help.cpp:320
msgid "7, 4, and 1 are switched with"
msgstr "byttast 7, 4, og 1 med"
-#: engines/scumm/help.cpp:309
+#: engines/scumm/help.cpp:321
msgid "9, 6, and 3, respectively."
msgstr "9, 6, og 3, henhaldsvis."
-#: engines/scumm/help.cpp:316
+#: engines/scumm/help.cpp:328
msgid "Biplane controls (numpad):"
msgstr "Flykontrollar (taltastatur)"
-#: engines/scumm/help.cpp:317
+#: engines/scumm/help.cpp:329
msgid "Fly to upper left"
msgstr "Fly til јvre venstre"
-#: engines/scumm/help.cpp:318
+#: engines/scumm/help.cpp:330
msgid "Fly to left"
msgstr "Fly til venstre"
-#: engines/scumm/help.cpp:319
+#: engines/scumm/help.cpp:331
msgid "Fly to lower left"
msgstr "Fly til nedre venstre"
-#: engines/scumm/help.cpp:320
+#: engines/scumm/help.cpp:332
msgid "Fly upwards"
msgstr "Fly oppover"
-#: engines/scumm/help.cpp:321
+#: engines/scumm/help.cpp:333
msgid "Fly straight"
msgstr "Fly rett"
-#: engines/scumm/help.cpp:322
+#: engines/scumm/help.cpp:334
msgid "Fly down"
msgstr "Fly ned"
-#: engines/scumm/help.cpp:323
+#: engines/scumm/help.cpp:335
msgid "Fly to upper right"
msgstr "Fly til јvre hјgre"
-#: engines/scumm/help.cpp:324
+#: engines/scumm/help.cpp:336
msgid "Fly to right"
msgstr "Fly til hјgre"
-#: engines/scumm/help.cpp:325
+#: engines/scumm/help.cpp:337
msgid "Fly to lower right"
msgstr "Fly til nedre hјgre"
-#: engines/scumm/scumm.cpp:1823
+#: engines/scumm/scumm.cpp:1832
#, 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:2594
+#: engines/scumm/scumm.cpp:2644
+#, fuzzy
msgid ""
-"Usually, Maniac Mansion would start now. But ScummVM doesn't do that yet. To "
-"play it, go to 'Add Game' in the ScummVM start menu and select the 'Maniac' "
-"directory inside the Tentacle game directory."
+"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-"
@@ -3291,10 +3381,42 @@ msgstr ""
msgid "Show the current number of frames per second in the upper left corner"
msgstr ""
-#~ msgctxt "lowres"
-#~ msgid "Mass Add..."
-#~ msgstr "Legg til fleire..."
+#: engines/zvision/detection.cpp:256
+msgid "Double FPS"
+msgstr ""
+#: engines/zvision/detection.cpp:257
+msgid "Increase game FPS from 30 to 60"
+msgstr ""
+
+#: engines/zvision/detection.cpp:266
+#, fuzzy
+msgid "Enable Venus"
+msgstr "Grafikkmodus:"
+
+#: engines/zvision/detection.cpp:267
+msgid "Enable the Venus help system"
+msgstr ""
+
+#: engines/zvision/detection.cpp:276
+msgid "Disable animation while turning"
+msgstr ""
+
+#: engines/zvision/detection.cpp:277
+msgid "Disable animation while turning in panoramic mode"
+msgstr ""
+
+#: engines/zvision/detection.cpp:286
+msgid "Use the hires MPEG movies"
+msgstr ""
+
+#: engines/zvision/detection.cpp:287
+#, fuzzy
+msgid ""
+"Use the hires MPEG movies of the DVD version, instead of the lowres AVI ones"
+msgstr "Nytt det alternative settet med sјlvpeikarar, istaden for dei gylne"
+
+#~ msgctxt "lowres"
#~ msgid "Mass Add..."
#~ msgstr "Legg til fleire..."
diff --git a/po/pl_PL.po b/po/pl_PL.po
index 87163748cd..c131023dfc 100644
--- a/po/pl_PL.po
+++ b/po/pl_PL.po
@@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: ScummVM 1.3.0\n"
"Report-Msgid-Bugs-To: scummvm-devel@lists.sf.net\n"
-"POT-Creation-Date: 2014-10-04 00:58+0100\n"
+"POT-Creation-Date: 2015-06-30 20:57+0100\n"
"PO-Revision-Date: 2014-07-02 12:28+0100\n"
"Last-Translator: MichaГ ZiБbkowski <mziab@o2.pl>\n"
"Language-Team: Grajpopolsku.pl <grajpopolsku@gmail.com>\n"
@@ -56,10 +56,11 @@ msgstr "W gѓrъ"
#: gui/browser.cpp:75 gui/chooser.cpp:46 gui/KeysDialog.cpp:43
#: gui/launcher.cpp:351 gui/massadd.cpp:95 gui/options.cpp:1239
+#: gui/recorderdialog.cpp:70 gui/recorderdialog.cpp:156
#: gui/saveload-dialog.cpp:216 gui/saveload-dialog.cpp:276
-#: gui/saveload-dialog.cpp:547 gui/saveload-dialog.cpp:922
+#: gui/saveload-dialog.cpp:547 gui/saveload-dialog.cpp:931
#: gui/themebrowser.cpp:55 gui/fluidsynth-dialog.cpp:152
-#: engines/engine.cpp:452 backends/platform/wii/options.cpp:48
+#: engines/engine.cpp:483 backends/platform/wii/options.cpp:48
#: backends/events/default/default-events.cpp:196
#: backends/events/default/default-events.cpp:218
#: engines/drascula/saveload.cpp:49 engines/parallaction/saveload.cpp:274
@@ -72,9 +73,9 @@ msgid "Choose"
msgstr "Wybierz"
#: gui/gui-manager.cpp:117 backends/keymapper/remap-dialog.cpp:53
-#: 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
+#: 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"
@@ -90,7 +91,7 @@ msgstr "WyЖwietl klawiaturъ"
msgid "Remap keys"
msgstr "Dostosuj klawisze"
-#: gui/gui-manager.cpp:131 base/main.cpp:326 engines/scumm/help.cpp:86
+#: gui/gui-manager.cpp:131 base/main.cpp:326 engines/scumm/help.cpp:87
msgid "Toggle fullscreen"
msgstr "WГБcz/wyГБcz peГny ekran"
@@ -104,13 +105,13 @@ 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:1240
-#: gui/saveload-dialog.cpp:923 gui/fluidsynth-dialog.cpp:153
-#: engines/engine.cpp:371 engines/engine.cpp:382
+#: 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:399 engines/parallaction/saveload.cpp:274
-#: engines/scumm/dialogs.cpp:193 engines/scumm/scumm.cpp:1825
+#: 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
@@ -477,7 +478,7 @@ msgstr ""
#: gui/launcher.cpp:793 gui/launcher.cpp:941 gui/launcher.cpp:1000
#: gui/fluidsynth-dialog.cpp:217
-#: backends/events/symbiansdl/symbiansdl-events.cpp:184
+#: 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
@@ -487,7 +488,7 @@ 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:184
+#: 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
@@ -523,6 +524,14 @@ msgstr "Ta gra nie wspiera wczytywania z launchera."
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
+msgid "Mass Add..."
+msgstr "Masowe dodawanie..."
+
+#: gui/launcher.cpp:1161
+msgid "Record..."
+msgstr ""
+
#: gui/massadd.cpp:79 gui/massadd.cpp:82
msgid "... progress ..."
msgstr "... postъp ..."
@@ -621,7 +630,7 @@ msgid "Special dithering modes supported by some games"
msgstr "Specjalne tryby ditheringu wspierane przez niektѓre gry"
#: gui/options.cpp:760
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2249
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2298
msgid "Fullscreen mode"
msgstr "PeГny ekran"
@@ -938,6 +947,43 @@ msgstr ""
"Wybrany styl nie obsГuguje obecnego jъzyka. JeЖli chcesz go uПywaц, zmieё "
"najpierw swѓj jъzyk."
+#: gui/recorderdialog.cpp:64
+msgid "Recorder or Playback Gameplay"
+msgstr ""
+
+#: gui/recorderdialog.cpp:69 gui/recorderdialog.cpp:156
+#: gui/saveload-dialog.cpp:220 gui/saveload-dialog.cpp:276
+msgid "Delete"
+msgstr "Skasuj"
+
+#: gui/recorderdialog.cpp:71
+msgid "Record"
+msgstr ""
+
+#: gui/recorderdialog.cpp:72
+#, fuzzy
+msgid "Playback"
+msgstr "Uruchom"
+
+#: gui/recorderdialog.cpp:74
+msgid "Edit"
+msgstr ""
+
+#: gui/recorderdialog.cpp:86 gui/recorderdialog.cpp:243
+#: gui/recorderdialog.cpp:253
+msgid "Author: "
+msgstr ""
+
+#: gui/recorderdialog.cpp:87 gui/recorderdialog.cpp:244
+#: gui/recorderdialog.cpp:254
+msgid "Notes: "
+msgstr ""
+
+#: gui/recorderdialog.cpp:155
+#, fuzzy
+msgid "Do you really want to delete this record?"
+msgstr "Na pewno chcesz skasowaц ten zapis?"
+
#: gui/saveload-dialog.cpp:167
msgid "List view"
msgstr "Widok listy"
@@ -958,23 +1004,19 @@ msgstr "Brak godziny"
msgid "No playtime saved"
msgstr "Brak czasu gry"
-#: gui/saveload-dialog.cpp:220 gui/saveload-dialog.cpp:276
-msgid "Delete"
-msgstr "Skasuj"
-
#: gui/saveload-dialog.cpp:275
msgid "Do you really want to delete this saved game?"
msgstr "Na pewno chcesz skasowaц ten zapis?"
-#: gui/saveload-dialog.cpp:385 gui/saveload-dialog.cpp:875
+#: gui/saveload-dialog.cpp:385 gui/saveload-dialog.cpp:884
msgid "Date: "
msgstr "Data: "
-#: gui/saveload-dialog.cpp:389 gui/saveload-dialog.cpp:881
+#: gui/saveload-dialog.cpp:389 gui/saveload-dialog.cpp:890
msgid "Time: "
msgstr "Czas: "
-#: gui/saveload-dialog.cpp:395 gui/saveload-dialog.cpp:889
+#: gui/saveload-dialog.cpp:395 gui/saveload-dialog.cpp:898
msgid "Playtime: "
msgstr "Czas gry: "
@@ -990,19 +1032,19 @@ msgstr "Nastъpny"
msgid "Prev"
msgstr "Poprzedni"
-#: gui/saveload-dialog.cpp:739
+#: gui/saveload-dialog.cpp:748
msgid "New Save"
msgstr "Nowy zapis"
-#: gui/saveload-dialog.cpp:739
+#: gui/saveload-dialog.cpp:748
msgid "Create a new save game"
msgstr "Stwѓrz nowy zapis"
-#: gui/saveload-dialog.cpp:868
+#: gui/saveload-dialog.cpp:877
msgid "Name: "
msgstr "Nazwa: "
-#: gui/saveload-dialog.cpp:940
+#: gui/saveload-dialog.cpp:949
#, c-format
msgid "Enter a description for slot %d:"
msgstr "Podaj opis dla slotu %d:"
@@ -1154,7 +1196,7 @@ msgstr "Pomiё liniъ"
msgid "Error running game:"
msgstr "BГБd podczas uruchamiania gry:"
-#: base/main.cpp:536
+#: base/main.cpp:554
msgid "Could not find any engine capable of running the selected game"
msgstr "Nie udaГo siъ znaleМц silnika zdolnego do uruchomienia zaznaczonej gry"
@@ -1271,7 +1313,7 @@ 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:758
+#: engines/pegasus/pegasus.cpp:377 engines/sci/engine/kfile.cpp:759
#: engines/toltecs/menu.cpp:281 engines/tsage/scenes.cpp:598
msgid "Save game:"
msgstr "Zapis:"
@@ -1284,7 +1326,7 @@ msgstr "Zapis:"
#: 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:758 engines/scumm/dialogs.cpp:188
+#: engines/sci/engine/kfile.cpp:759 engines/scumm/dialogs.cpp:188
#: engines/toltecs/menu.cpp:281 engines/tsage/scenes.cpp:598
msgid "Save"
msgstr "Zapisz"
@@ -1322,23 +1364,23 @@ msgstr "~A~nuluj"
msgid "~K~eys"
msgstr "~K~lawisze"
-#: engines/engine.cpp:245
+#: engines/engine.cpp:276
msgid "Could not initialize color format."
msgstr "Nie udaГo siъ zainicjalizowaц formatu kolorѓw."
-#: engines/engine.cpp:253
+#: engines/engine.cpp:284
msgid "Could not switch to video mode: '"
msgstr "Nie udaГo siъ przeГБczyц w tryb wideo: '"
-#: engines/engine.cpp:262
+#: engines/engine.cpp:293
msgid "Could not apply aspect ratio setting."
msgstr "Nie udaГo siъ zastosowaц ustawienia formatu obrazu."
-#: engines/engine.cpp:267
+#: engines/engine.cpp:298
msgid "Could not apply fullscreen setting."
msgstr "Nie udaГo siъ zastosowaц ustawienia peГnego ekranu."
-#: engines/engine.cpp:367
+#: engines/engine.cpp:398
msgid ""
"You appear to be playing this game directly\n"
"from the CD. This is known to cause problems,\n"
@@ -1350,7 +1392,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:378
+#: engines/engine.cpp:409
msgid ""
"This game has audio tracks in its disk. These\n"
"tracks need to be ripped from the disk using\n"
@@ -1362,7 +1404,7 @@ msgstr ""
"skopiowaц na dysk za pomocБ odpowiedniego rippera CD audio.\n"
"Dalsze informacje sБ dostъpne w pliku README."
-#: engines/engine.cpp:436
+#: engines/engine.cpp:467
#, c-format
msgid ""
"Gamestate load failed (%s)! Please consult the README for basic information, "
@@ -1371,7 +1413,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:449
+#: engines/engine.cpp:480
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 "
@@ -1381,7 +1423,7 @@ 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:452
+#: engines/engine.cpp:483
msgid "Start anyway"
msgstr "WГБcz mimo tego"
@@ -1591,11 +1633,11 @@ msgstr "Tryb touchpada wГБczony."
msgid "Touchpad mode disabled."
msgstr "Tryb touchpada wyГБczony."
-#: backends/platform/maemo/maemo.cpp:209
+#: backends/platform/maemo/maemo.cpp:208
msgid "Click Mode"
msgstr "Tryb klikania"
-#: backends/platform/maemo/maemo.cpp:215
+#: backends/platform/maemo/maemo.cpp:214
#: backends/platform/symbian/src/SymbianActions.cpp:42
#: backends/platform/wince/CEActionsPocket.cpp:60
#: backends/platform/wince/CEActionsSmartphone.cpp:43
@@ -1603,11 +1645,11 @@ msgstr "Tryb klikania"
msgid "Left Click"
msgstr "Klikniъcie LPM"
-#: backends/platform/maemo/maemo.cpp:218
+#: backends/platform/maemo/maemo.cpp:217
msgid "Middle Click"
msgstr "Іrodkowy przycisk"
-#: backends/platform/maemo/maemo.cpp:221
+#: 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
@@ -1644,19 +1686,19 @@ msgctxt "lowres"
msgid "Normal (no scaling)"
msgstr "ZwykГy (bez skalowania)"
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2148
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2197
msgid "Enabled aspect ratio correction"
msgstr "WГБczono korekcjъ formatu obrazu"
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2154
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2203
msgid "Disabled aspect ratio correction"
msgstr "WyГБczono korekcjъ formatu obrazu"
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2209
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2258
msgid "Active graphics filter:"
msgstr "Aktywny filtr graficzny:"
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2251
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2300
msgid "Windowed mode"
msgstr "Okno"
@@ -1715,8 +1757,8 @@ msgstr "Tryb szybki"
#: 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:82
-#: engines/scumm/help.cpp:84
+#: engines/scumm/dialogs.cpp:192 engines/scumm/help.cpp:83
+#: engines/scumm/help.cpp:85
msgid "Quit"
msgstr "Zakoёcz"
@@ -1736,7 +1778,7 @@ msgstr "Wirtualna klawiatura"
msgid "Key mapper"
msgstr "Mapper klawiszy"
-#: backends/events/symbiansdl/symbiansdl-events.cpp:184
+#: backends/events/symbiansdl/symbiansdl-events.cpp:186
msgid "Do you want to quit ?"
msgstr "Chcesz wyjЖц?"
@@ -2069,33 +2111,54 @@ msgstr "Klikanie wГБczone"
msgid "Clicking Disabled"
msgstr "Klikanie wyГБczone"
-#: engines/agi/detection.cpp:142 engines/drascula/detection.cpp:302
+#: 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.cpp:103
+#: engines/zvision/detection.cpp:246
msgid "Use original save/load screens"
msgstr "UПyj oryginalnych ekranѓw odczytu/zapisu"
-#: engines/agi/detection.cpp:143 engines/drascula/detection.cpp:303
+#: 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/zvision/detection.cpp:104
+#: engines/zvision/detection.cpp:247
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)"
+
+#: engines/agi/detection.cpp:158
+msgid ""
+"Use an alternative palette, common for all Amiga games. This was the old "
+"behavior"
+msgstr ""
+
+#: engines/agi/detection.cpp:167
+#, fuzzy
+msgid "Mouse support"
+msgstr "ObsГuga pomijania"
+
+#: 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:857 engines/toltecs/menu.cpp:256
+#: engines/sci/engine/kfile.cpp:858 engines/toltecs/menu.cpp:256
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:857 engines/toltecs/menu.cpp:256
+#: engines/sci/engine/kfile.cpp:858 engines/toltecs/menu.cpp:256
msgid "Restore"
msgstr "Wznѓw"
-#: engines/agos/saveload.cpp:160 engines/scumm/scumm.cpp:2368
+#: engines/agos/saveload.cpp:160 engines/scumm/scumm.cpp:2377
#, c-format
msgid ""
"Failed to load game state from file:\n"
@@ -2106,7 +2169,7 @@ msgstr ""
"\n"
"%s"
-#: engines/agos/saveload.cpp:195 engines/scumm/scumm.cpp:2361
+#: engines/agos/saveload.cpp:195 engines/scumm/scumm.cpp:2370
#, c-format
msgid ""
"Failed to save game state to file:\n"
@@ -2117,7 +2180,7 @@ msgstr ""
"\n"
"%s"
-#: engines/agos/saveload.cpp:203 engines/scumm/scumm.cpp:2379
+#: engines/agos/saveload.cpp:203 engines/scumm/scumm.cpp:2388
#, c-format
msgid ""
"Successfully saved game state in file:\n"
@@ -2133,12 +2196,12 @@ msgstr ""
msgid "Cutscene file '%s' not found!"
msgstr "Nie znaleziono pliku przerywnika '%s'!"
-#: engines/cge/detection.cpp:105 engines/cge2/detection.cpp:81
+#: engines/cge/detection.cpp:105 engines/cge2/detection.cpp:101
#, fuzzy
msgid "Color Blind Mode"
msgstr "Tryb klikania"
-#: engines/cge/detection.cpp:106 engines/cge2/detection.cpp:82
+#: engines/cge/detection.cpp:106 engines/cge2/detection.cpp:102
msgid "Enable Color Blind Mode by default"
msgstr ""
@@ -2189,7 +2252,7 @@ msgstr "PrzyЖpieszone filmy"
msgid "Play movies at an increased speed"
msgstr "Odtwarzaj filmy ze zwiъkszonБ prъdkoЖciБ"
-#: engines/groovie/script.cpp:399
+#: engines/groovie/script.cpp:408
msgid "Failed to save game"
msgstr "Nie udaГo siъ zapisaц stanu gry"
@@ -2485,12 +2548,12 @@ msgid "Use an alternative game intro (CD version only)"
msgstr "UПyj alternatywnego intra (tylko dla wersji CD)"
#: engines/sci/detection.cpp:374
-msgid "EGA undithering"
-msgstr "Anty-dithering EGA"
+msgid "Skip EGA dithering pass (full color backgrounds)"
+msgstr ""
#: engines/sci/detection.cpp:375
-msgid "Enable undithering in EGA games"
-msgstr "WГБcz anty-dithering we wspieranych grach EGA"
+msgid "Skip dithering pass in EGA games, graphics are shown with full colors"
+msgstr ""
#: engines/sci/detection.cpp:384
msgid "Prefer digital sound effects"
@@ -2563,12 +2626,14 @@ msgstr "Gra wstrzymana. NaciЖnij spacjъ, aby wznowiц."
#. "Moechten Sie wirklich neu starten? (J/N)J"
#. Will react to J as 'Yes'
#: engines/scumm/dialogs.cpp:183
-msgid "Are you sure you want to restart? (Y/N)"
+#, fuzzy
+msgid "Are you sure you want to restart? (Y/N)Y"
msgstr "Na pewno chcesz zrestartowaц grъ? (T/N)T"
#. I18N: you may specify 'Yes' symbol at the end of the line. See previous comment
#: engines/scumm/dialogs.cpp:185
-msgid "Are you sure you want to quit? (Y/N)"
+#, fuzzy
+msgid "Are you sure you want to quit? (Y/N)Y"
msgstr "Na pewno chcesz wyjЖц? (T/N)T"
#: engines/scumm/dialogs.cpp:190
@@ -2656,516 +2721,541 @@ msgstr "Trening"
msgid "Expert"
msgstr "Ekspert"
-#: engines/scumm/help.cpp:73
+#: engines/scumm/help.cpp:74
msgid "Common keyboard commands:"
msgstr "Skrѓty klawiaturowe:"
-#: engines/scumm/help.cpp:74
+#: engines/scumm/help.cpp:75
msgid "Save / Load dialog"
msgstr "Okno Zapisz / Wczytaj"
-#: engines/scumm/help.cpp:76
+#: engines/scumm/help.cpp:77
msgid "Skip line of text"
msgstr "Pomiё linijkъ tekstu"
-#: engines/scumm/help.cpp:77
+#: engines/scumm/help.cpp:78
msgid "Esc"
msgstr "Esc"
-#: engines/scumm/help.cpp:77
+#: engines/scumm/help.cpp:78
msgid "Skip cutscene"
msgstr "Pomiё scenkъ"
-#: engines/scumm/help.cpp:78
+#: engines/scumm/help.cpp:79
msgid "Space"
msgstr "Spacja"
-#: engines/scumm/help.cpp:78
+#: engines/scumm/help.cpp:79
msgid "Pause game"
msgstr "Wstrzymaj grъ"
-#: engines/scumm/help.cpp:79 engines/scumm/help.cpp:84
-#: engines/scumm/help.cpp:95 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: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:79
+#: engines/scumm/help.cpp:80
msgid "Load game state 1-10"
msgstr "Wczytaj stan gry 1-10"
-#: engines/scumm/help.cpp:80 engines/scumm/help.cpp:84
-#: engines/scumm/help.cpp:86 engines/scumm/help.cpp:100
-#: engines/scumm/help.cpp:101 engines/scumm/help.cpp:102
+#: 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:80
+#: engines/scumm/help.cpp:81
msgid "Save game state 1-10"
msgstr "Zapisz stan gry 1-10"
-#: engines/scumm/help.cpp:86 engines/scumm/help.cpp:89
+#: engines/scumm/help.cpp:87 engines/scumm/help.cpp:90
msgid "Enter"
msgstr "Enter"
-#: engines/scumm/help.cpp:87
+#: engines/scumm/help.cpp:88
msgid "Music volume up / down"
msgstr "Zwiъksz/zmniejsz gГoЖnoЖц muzyki"
-#: engines/scumm/help.cpp:88
+#: engines/scumm/help.cpp:89
msgid "Text speed slower / faster"
msgstr "Zwiъksz/zmniejsz prъdkoЖц tekstu"
-#: engines/scumm/help.cpp:89
+#: engines/scumm/help.cpp:90
msgid "Simulate left mouse button"
msgstr "Symuluje lewy przycisk myszy"
-#: engines/scumm/help.cpp:90
+#: engines/scumm/help.cpp:91
msgid "Tab"
msgstr "Tab"
-#: engines/scumm/help.cpp:90
+#: engines/scumm/help.cpp:91
msgid "Simulate right mouse button"
msgstr "Symuluje prawy przycisk myszy"
-#: engines/scumm/help.cpp:93
+#: engines/scumm/help.cpp:94
msgid "Special keyboard commands:"
msgstr "Specjalne skrѓty klawiaturowe:"
-#: engines/scumm/help.cpp:94
+#: engines/scumm/help.cpp:95
msgid "Show / Hide console"
msgstr "Schowaj / pokaП konsolъ"
-#: engines/scumm/help.cpp:95
+#: engines/scumm/help.cpp:96
msgid "Start the debugger"
msgstr "WГБcz debugger"
-#: engines/scumm/help.cpp:96
+#: engines/scumm/help.cpp:97
msgid "Show memory consumption"
msgstr "PokaП zuПycie pamiъci"
-#: engines/scumm/help.cpp:97
+#: engines/scumm/help.cpp:98
msgid "Run in fast mode (*)"
msgstr "WГБcz w trybie szybkim (*)"
-#: engines/scumm/help.cpp:98
+#: engines/scumm/help.cpp:99
msgid "Run in really fast mode (*)"
msgstr "WГБcz w trybie bardzo szybkim (*)"
-#: engines/scumm/help.cpp:99
+#: engines/scumm/help.cpp:100
msgid "Toggle mouse capture"
msgstr "WГБcz/wyГБcz przechwytywanie myszy"
-#: engines/scumm/help.cpp:100
+#: engines/scumm/help.cpp:101
msgid "Switch between graphics filters"
msgstr "PrzeГБczaj pomiъdzy filtrami grafiki"
-#: engines/scumm/help.cpp:101
+#: engines/scumm/help.cpp:102
msgid "Increase / Decrease scale factor"
msgstr "Zwiъksz / zmniejsz wspѓГczynnik skalowania"
-#: engines/scumm/help.cpp:102
+#: engines/scumm/help.cpp:103
msgid "Toggle aspect-ratio correction"
msgstr "WГБcz/wyГБcz korekcjъ formatu obrazu"
-#: engines/scumm/help.cpp:107
+#: engines/scumm/help.cpp:108
msgid "* Note that using ctrl-f and"
msgstr "* Miej na uwadze, Пe uПywanie ctrl-f"
-#: engines/scumm/help.cpp:108
+#: engines/scumm/help.cpp:109
msgid " ctrl-g are not recommended"
msgstr " i ctrl-g nie jest wskazane"
-#: engines/scumm/help.cpp:109
+#: engines/scumm/help.cpp:110
msgid " since they may cause crashes"
msgstr " poniewaП mogБ one spowodowaц zawieszenie siъ,"
-#: engines/scumm/help.cpp:110
+#: engines/scumm/help.cpp:111
msgid " or incorrect game behavior."
msgstr " bБdМ nieodpowiednie zachowanie gry."
-#: engines/scumm/help.cpp:114
+#: engines/scumm/help.cpp:115
msgid "Spinning drafts on the keyboard:"
msgstr "Tkanie splotѓw na klawiaturze:"
-#: engines/scumm/help.cpp:116
+#: engines/scumm/help.cpp:117
msgid "Main game controls:"
msgstr "GГѓwne sterowanie gry:"
-#: engines/scumm/help.cpp:121 engines/scumm/help.cpp:136
-#: engines/scumm/help.cpp:161
+#: engines/scumm/help.cpp:122 engines/scumm/help.cpp:137
+#: engines/scumm/help.cpp:162
msgid "Push"
msgstr "Pchnij"
-#: engines/scumm/help.cpp:122 engines/scumm/help.cpp:137
-#: engines/scumm/help.cpp:162
+#: engines/scumm/help.cpp:123 engines/scumm/help.cpp:138
+#: engines/scumm/help.cpp:163
msgid "Pull"
msgstr "PociБgnij"
-#: engines/scumm/help.cpp:123 engines/scumm/help.cpp:138
-#: engines/scumm/help.cpp:163 engines/scumm/help.cpp:197
-#: engines/scumm/help.cpp:207
+#: 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 "Daj"
-#: engines/scumm/help.cpp:124 engines/scumm/help.cpp:139
-#: engines/scumm/help.cpp:164 engines/scumm/help.cpp:190
-#: engines/scumm/help.cpp:208
+#: 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 "Otwѓrz"
-#: engines/scumm/help.cpp:126
+#: engines/scumm/help.cpp:127
msgid "Go to"
msgstr "IdМ do"
-#: engines/scumm/help.cpp:127
+#: engines/scumm/help.cpp:128
msgid "Get"
msgstr "WeМ"
-#: engines/scumm/help.cpp:128 engines/scumm/help.cpp:152
-#: engines/scumm/help.cpp:170 engines/scumm/help.cpp:198
-#: engines/scumm/help.cpp:213 engines/scumm/help.cpp:224
-#: engines/scumm/help.cpp:250
+#: 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 "UПyj"
-#: engines/scumm/help.cpp:129 engines/scumm/help.cpp:141
+#: engines/scumm/help.cpp:130 engines/scumm/help.cpp:142
msgid "Read"
msgstr "Czytaj"
-#: engines/scumm/help.cpp:130 engines/scumm/help.cpp:147
+#: engines/scumm/help.cpp:131 engines/scumm/help.cpp:148
msgid "New kid"
msgstr "Nowy dzieciak"
-#: engines/scumm/help.cpp:131 engines/scumm/help.cpp:153
-#: engines/scumm/help.cpp:171
+#: engines/scumm/help.cpp:132 engines/scumm/help.cpp:154
+#: engines/scumm/help.cpp:172
msgid "Turn on"
msgstr "WГБcz"
-#: engines/scumm/help.cpp:132 engines/scumm/help.cpp:154
-#: engines/scumm/help.cpp:172
+#: engines/scumm/help.cpp:133 engines/scumm/help.cpp:155
+#: engines/scumm/help.cpp:173
msgid "Turn off"
msgstr "WyГБcz"
-#: engines/scumm/help.cpp:142 engines/scumm/help.cpp:167
-#: engines/scumm/help.cpp:194
+#: engines/scumm/help.cpp:143 engines/scumm/help.cpp:168
+#: engines/scumm/help.cpp:195
msgid "Walk to"
msgstr "PodejdМ do"
-#: engines/scumm/help.cpp:143 engines/scumm/help.cpp:168
-#: engines/scumm/help.cpp:195 engines/scumm/help.cpp:210
-#: engines/scumm/help.cpp:227
+#: 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 "PodnieЖ"
-#: engines/scumm/help.cpp:144 engines/scumm/help.cpp:169
+#: engines/scumm/help.cpp:145 engines/scumm/help.cpp:170
msgid "What is"
msgstr "Czym jest"
-#: engines/scumm/help.cpp:146
+#: engines/scumm/help.cpp:147
msgid "Unlock"
msgstr "Otwѓrz"
-#: engines/scumm/help.cpp:149
+#: engines/scumm/help.cpp:150
msgid "Put on"
msgstr "ZaГѓП"
-#: engines/scumm/help.cpp:150
+#: engines/scumm/help.cpp:151
msgid "Take off"
msgstr "Zdejmij"
-#: engines/scumm/help.cpp:156
+#: engines/scumm/help.cpp:157
msgid "Fix"
msgstr "Napraw"
-#: engines/scumm/help.cpp:158
+#: engines/scumm/help.cpp:159
msgid "Switch"
msgstr "PrzeГБcz"
-#: engines/scumm/help.cpp:166 engines/scumm/help.cpp:228
+#: engines/scumm/help.cpp:167 engines/scumm/help.cpp:229
msgid "Look"
msgstr "Spѓjrz"
-#: engines/scumm/help.cpp:173 engines/scumm/help.cpp:223
+#: engines/scumm/help.cpp:174 engines/scumm/help.cpp:224
msgid "Talk"
msgstr "Rozmawiaj"
-#: engines/scumm/help.cpp:174
+#: engines/scumm/help.cpp:175
msgid "Travel"
msgstr "PodrѓПuj"
-#: engines/scumm/help.cpp:175
+#: engines/scumm/help.cpp:176
msgid "To Henry / To Indy"
msgstr "Do Henry'ego / Do Indy'ego"
#. I18N: These are different musical notes
-#: engines/scumm/help.cpp:179
+#: engines/scumm/help.cpp:180
msgid "play C minor on distaff"
msgstr "zagraj c-moll na kБdzieli"
-#: engines/scumm/help.cpp:180
+#: engines/scumm/help.cpp:181
msgid "play D on distaff"
msgstr "zagraj D na kБdzieli"
-#: engines/scumm/help.cpp:181
+#: engines/scumm/help.cpp:182
msgid "play E on distaff"
msgstr "zagraj E na kБdzieli"
-#: engines/scumm/help.cpp:182
+#: engines/scumm/help.cpp:183
msgid "play F on distaff"
msgstr "zagraj F na kБdzieli"
-#: engines/scumm/help.cpp:183
+#: engines/scumm/help.cpp:184
msgid "play G on distaff"
msgstr "zagraj G na kБdzieli"
-#: engines/scumm/help.cpp:184
+#: engines/scumm/help.cpp:185
msgid "play A on distaff"
msgstr "zagraj A na kБdzieli"
-#: engines/scumm/help.cpp:185
+#: engines/scumm/help.cpp:186
msgid "play B on distaff"
msgstr "zagraj B na kБdzieli"
-#: engines/scumm/help.cpp:186
+#: engines/scumm/help.cpp:187
msgid "play C major on distaff"
msgstr "zagraj C-dur na kБdzieli"
-#: engines/scumm/help.cpp:192 engines/scumm/help.cpp:214
+#: engines/scumm/help.cpp:193 engines/scumm/help.cpp:215
msgid "puSh"
msgstr "pchnij"
-#: engines/scumm/help.cpp:193 engines/scumm/help.cpp:215
+#: engines/scumm/help.cpp:194 engines/scumm/help.cpp:216
msgid "pull (Yank)"
msgstr "pociБgnij"
-#: engines/scumm/help.cpp:196 engines/scumm/help.cpp:212
-#: engines/scumm/help.cpp:248
+#: engines/scumm/help.cpp:197 engines/scumm/help.cpp:213
+#: engines/scumm/help.cpp:249
msgid "Talk to"
msgstr "Rozmawiaj z"
-#: engines/scumm/help.cpp:199 engines/scumm/help.cpp:211
+#: engines/scumm/help.cpp:200 engines/scumm/help.cpp:212
msgid "Look at"
msgstr "Spѓjrz na"
-#: engines/scumm/help.cpp:200
+#: engines/scumm/help.cpp:201
msgid "turn oN"
msgstr "wГБcz"
-#: engines/scumm/help.cpp:201
+#: engines/scumm/help.cpp:202
msgid "turn oFf"
msgstr "wyГБcz"
-#: engines/scumm/help.cpp:217
+#: engines/scumm/help.cpp:218
msgid "KeyUp"
msgstr "StrzaГka do gѓry"
-#: engines/scumm/help.cpp:217
+#: engines/scumm/help.cpp:218
msgid "Highlight prev dialogue"
msgstr "PodЖwietl poprzedni dialog"
-#: engines/scumm/help.cpp:218
+#: engines/scumm/help.cpp:219
msgid "KeyDown"
msgstr "StrzaГka w dѓГ"
-#: engines/scumm/help.cpp:218
+#: engines/scumm/help.cpp:219
msgid "Highlight next dialogue"
msgstr "PodЖwietl nastъpny dialog"
-#: engines/scumm/help.cpp:222
+#: engines/scumm/help.cpp:223
msgid "Walk"
msgstr "IdМ"
-#: engines/scumm/help.cpp:225 engines/scumm/help.cpp:234
-#: engines/scumm/help.cpp:241 engines/scumm/help.cpp:249
+#: engines/scumm/help.cpp:226 engines/scumm/help.cpp:235
+#: engines/scumm/help.cpp:242 engines/scumm/help.cpp:250
msgid "Inventory"
msgstr "Ekwipunek"
-#: engines/scumm/help.cpp:226
+#: engines/scumm/help.cpp:227
msgid "Object"
msgstr "Przedmiot"
-#: engines/scumm/help.cpp:229
+#: engines/scumm/help.cpp:230
msgid "Black and White / Color"
msgstr "Czarno-biaГy / Kolorowy"
-#: engines/scumm/help.cpp:232
+#: engines/scumm/help.cpp:233
msgid "Eyes"
msgstr "Oczy"
-#: engines/scumm/help.cpp:233
+#: engines/scumm/help.cpp:234
msgid "Tongue"
msgstr "Jъzyk"
-#: engines/scumm/help.cpp:235
+#: engines/scumm/help.cpp:236
msgid "Punch"
msgstr "PiъЖц"
-#: engines/scumm/help.cpp:236
+#: engines/scumm/help.cpp:237
msgid "Kick"
msgstr "Kopniъcie"
-#: engines/scumm/help.cpp:239 engines/scumm/help.cpp:247
+#: engines/scumm/help.cpp:240 engines/scumm/help.cpp:248
msgid "Examine"
msgstr "Zbadaj"
-#: engines/scumm/help.cpp:240
+#: engines/scumm/help.cpp:241
msgid "Regular cursor"
msgstr "ZwykГy kursor"
#. I18N: Comm is a communication device
-#: engines/scumm/help.cpp:243
+#: engines/scumm/help.cpp:244
msgid "Comm"
msgstr "Kom."
-#: engines/scumm/help.cpp:246
+#: engines/scumm/help.cpp:247
msgid "Save / Load / Options"
msgstr "Zapis / Odczyt / Opcje"
-#: engines/scumm/help.cpp:255
+#: engines/scumm/help.cpp:256
msgid "Other game controls:"
msgstr "Reszta sterowania gry:"
-#: engines/scumm/help.cpp:257 engines/scumm/help.cpp:267
+#: engines/scumm/help.cpp:258 engines/scumm/help.cpp:268
msgid "Inventory:"
msgstr "Ekwipunek:"
-#: engines/scumm/help.cpp:258 engines/scumm/help.cpp:274
+#: engines/scumm/help.cpp:259 engines/scumm/help.cpp:275
msgid "Scroll list up"
msgstr "Przewiё listъ do gѓry"
-#: engines/scumm/help.cpp:259 engines/scumm/help.cpp:275
+#: engines/scumm/help.cpp:260 engines/scumm/help.cpp:276
msgid "Scroll list down"
msgstr "Przewiё listъ w dѓГ"
-#: engines/scumm/help.cpp:260 engines/scumm/help.cpp:268
+#: engines/scumm/help.cpp:261 engines/scumm/help.cpp:269
msgid "Upper left item"
msgstr "Przedmiot u gѓry, z lewej"
-#: engines/scumm/help.cpp:261 engines/scumm/help.cpp:270
+#: engines/scumm/help.cpp:262 engines/scumm/help.cpp:271
msgid "Lower left item"
msgstr "Przedmiot na dole, z lewej"
-#: engines/scumm/help.cpp:262 engines/scumm/help.cpp:271
+#: engines/scumm/help.cpp:263 engines/scumm/help.cpp:272
msgid "Upper right item"
msgstr "Przedmiot u gѓry, z prawej"
-#: engines/scumm/help.cpp:263 engines/scumm/help.cpp:273
+#: engines/scumm/help.cpp:264 engines/scumm/help.cpp:274
msgid "Lower right item"
msgstr "Przedmiot na dole, z prawej"
-#: engines/scumm/help.cpp:269
+#: engines/scumm/help.cpp:270
msgid "Middle left item"
msgstr "Przedmiot na Жrodku, z lewej"
-#: engines/scumm/help.cpp:272
+#: engines/scumm/help.cpp:273
msgid "Middle right item"
msgstr "Przedmiot na Жrodku, z prawej"
-#: engines/scumm/help.cpp:279 engines/scumm/help.cpp:284
+#: engines/scumm/help.cpp:280 engines/scumm/help.cpp:285
msgid "Switching characters:"
msgstr "Zmiana postaci:"
-#: engines/scumm/help.cpp:281
+#: engines/scumm/help.cpp:282
msgid "Second kid"
msgstr "Drugi dzieciak"
-#: engines/scumm/help.cpp:282
+#: engines/scumm/help.cpp:283
msgid "Third kid"
msgstr "Trzeci dzieciak"
-#: engines/scumm/help.cpp:294
+#: engines/scumm/help.cpp:292
+#, fuzzy
+msgid "Toggle Inventory/IQ Points display"
+msgstr "WГБcz/wyГБcz widok danych"
+
+#: engines/scumm/help.cpp:293
+msgid "Toggle Keyboard/Mouse Fighting (*)"
+msgstr ""
+
+#: engines/scumm/help.cpp:295
+msgid "* Keyboard Fighting is always on,"
+msgstr ""
+
+#: engines/scumm/help.cpp:296
+msgid " so despite the in-game message this"
+msgstr ""
+
+#: engines/scumm/help.cpp:297
+msgid " actually toggles Mouse Fighting Off/On"
+msgstr ""
+
+#: engines/scumm/help.cpp:304
msgid "Fighting controls (numpad):"
msgstr "Sterowanie podczas walki (klaw. num.):"
-#: engines/scumm/help.cpp:295 engines/scumm/help.cpp:296
-#: engines/scumm/help.cpp:297
+#: engines/scumm/help.cpp:305 engines/scumm/help.cpp:306
+#: engines/scumm/help.cpp:307
msgid "Step back"
msgstr "Odsuё siъ"
-#: engines/scumm/help.cpp:298
+#: engines/scumm/help.cpp:308
msgid "Block high"
msgstr "Wysoki blok"
-#: engines/scumm/help.cpp:299
+#: engines/scumm/help.cpp:309
msgid "Block middle"
msgstr "Іrodkowy blok"
-#: engines/scumm/help.cpp:300
+#: engines/scumm/help.cpp:310
msgid "Block low"
msgstr "Dolny blok"
-#: engines/scumm/help.cpp:301
+#: engines/scumm/help.cpp:311
msgid "Punch high"
msgstr "Wysokie uderzenie"
-#: engines/scumm/help.cpp:302
+#: engines/scumm/help.cpp:312
msgid "Punch middle"
msgstr "Іrodkowe uderzenie"
-#: engines/scumm/help.cpp:303
+#: engines/scumm/help.cpp:313
msgid "Punch low"
msgstr "Niskie uderzenie"
-#: engines/scumm/help.cpp:306
+#: engines/scumm/help.cpp:315
+msgid "Sucker punch"
+msgstr ""
+
+#: engines/scumm/help.cpp:318
msgid "These are for Indy on left."
msgstr "Te sБ dla Indy'ego po lewej."
-#: engines/scumm/help.cpp:307
+#: engines/scumm/help.cpp:319
msgid "When Indy is on the right,"
msgstr "Kiedy Indy jest po prawej,"
-#: engines/scumm/help.cpp:308
+#: engines/scumm/help.cpp:320
msgid "7, 4, and 1 are switched with"
msgstr "7, 4 i 1 zostajБ zamienione"
-#: engines/scumm/help.cpp:309
+#: engines/scumm/help.cpp:321
msgid "9, 6, and 3, respectively."
msgstr "na 9, 6 i 3."
-#: engines/scumm/help.cpp:316
+#: engines/scumm/help.cpp:328
msgid "Biplane controls (numpad):"
msgstr "Sterowanie dwupГatowcem (klaw. num.):"
-#: engines/scumm/help.cpp:317
+#: engines/scumm/help.cpp:329
msgid "Fly to upper left"
msgstr "Leц do gѓry, w lewo"
-#: engines/scumm/help.cpp:318
+#: engines/scumm/help.cpp:330
msgid "Fly to left"
msgstr "Leц w lewo"
-#: engines/scumm/help.cpp:319
+#: engines/scumm/help.cpp:331
msgid "Fly to lower left"
msgstr "Leц na dѓГ, w lewo"
-#: engines/scumm/help.cpp:320
+#: engines/scumm/help.cpp:332
msgid "Fly upwards"
msgstr "Leц do gѓry"
-#: engines/scumm/help.cpp:321
+#: engines/scumm/help.cpp:333
msgid "Fly straight"
msgstr "Leц prosto"
-#: engines/scumm/help.cpp:322
+#: engines/scumm/help.cpp:334
msgid "Fly down"
msgstr "Leц w dѓГ"
-#: engines/scumm/help.cpp:323
+#: engines/scumm/help.cpp:335
msgid "Fly to upper right"
msgstr "Leц do gѓry, w prawo"
-#: engines/scumm/help.cpp:324
+#: engines/scumm/help.cpp:336
msgid "Fly to right"
msgstr "Leц w prawo"
-#: engines/scumm/help.cpp:325
+#: engines/scumm/help.cpp:337
msgid "Fly to lower right"
msgstr "Leц w dѓГ, w prawo"
-#: engines/scumm/scumm.cpp:1823
+#: engines/scumm/scumm.cpp:1832
#, c-format
msgid ""
"Native MIDI support requires the Roland Upgrade from LucasArts,\n"
@@ -3174,11 +3264,12 @@ msgstr ""
"Natywne wsparcie MIDI wymaga aktualizacji Rolanda od LucasArts,\n"
"ale brakuje %s. PrzeГБczam na tryb AdLib."
-#: engines/scumm/scumm.cpp:2594
+#: engines/scumm/scumm.cpp:2644
+#, fuzzy
msgid ""
-"Usually, Maniac Mansion would start now. But ScummVM doesn't do that yet. To "
-"play it, go to 'Add Game' in the ScummVM start menu and select the 'Maniac' "
-"directory inside the Tentacle game directory."
+"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 "
@@ -3320,6 +3411,48 @@ msgstr ""
msgid "Show the current number of frames per second in the upper left corner"
msgstr ""
+#: engines/zvision/detection.cpp:256
+msgid "Double FPS"
+msgstr ""
+
+#: engines/zvision/detection.cpp:257
+msgid "Increase game FPS from 30 to 60"
+msgstr ""
+
+#: engines/zvision/detection.cpp:266
+#, fuzzy
+msgid "Enable Venus"
+msgstr "WГБcz tryb helowy"
+
+#: engines/zvision/detection.cpp:267
+msgid "Enable the Venus help system"
+msgstr ""
+
+#: engines/zvision/detection.cpp:276
+msgid "Disable animation while turning"
+msgstr ""
+
+#: engines/zvision/detection.cpp:277
+msgid "Disable animation while turning in panoramic mode"
+msgstr ""
+
+#: engines/zvision/detection.cpp:286
+msgid "Use the hires MPEG movies"
+msgstr ""
+
+#: engines/zvision/detection.cpp:287
+#, fuzzy
+msgid ""
+"Use the hires MPEG movies of the DVD version, instead of the lowres AVI ones"
+msgstr ""
+"UПyj alternatywnego zestawu srebrnych kursorѓw zamiast zwykГych zГotych"
+
+#~ msgid "EGA undithering"
+#~ msgstr "Anty-dithering EGA"
+
+#~ msgid "Enable undithering in EGA games"
+#~ msgstr "WГБcz anty-dithering we wspieranych grach EGA"
+
#~ msgid "MPEG-2 cutscenes found but ScummVM has been built without MPEG-2"
#~ msgstr ""
#~ "Znaleziono przerywniki w formacie MPEG-2, ale ScummVM jest skompilowany "
@@ -3329,9 +3462,6 @@ msgstr ""
#~ msgid "Mass Add..."
#~ msgstr "Masowe dodawanie..."
-#~ msgid "Mass Add..."
-#~ msgstr "Masowe dodawanie..."
-
#~ msgid ""
#~ "Turns off General MIDI mapping for games with Roland MT-32 soundtrack"
#~ msgstr ""
diff --git a/po/pt_BR.po b/po/pt_BR.po
index aa517ef1ed..8280b28154 100644
--- a/po/pt_BR.po
+++ b/po/pt_BR.po
@@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: ScummVM 1.3.0svn\n"
"Report-Msgid-Bugs-To: scummvm-devel@lists.sf.net\n"
-"POT-Creation-Date: 2014-10-04 00:58+0100\n"
+"POT-Creation-Date: 2015-06-30 20:57+0100\n"
"PO-Revision-Date: 2011-10-21 21:30-0300\n"
"Last-Translator: Saulo Benigno <saulobenigno@gmail.com>\n"
"Language-Team: ScummBR (www.scummbr.com) <scummbr@yahoo.com.br>\n"
@@ -57,10 +57,11 @@ msgstr "Acima"
#: gui/browser.cpp:75 gui/chooser.cpp:46 gui/KeysDialog.cpp:43
#: gui/launcher.cpp:351 gui/massadd.cpp:95 gui/options.cpp:1239
+#: gui/recorderdialog.cpp:70 gui/recorderdialog.cpp:156
#: gui/saveload-dialog.cpp:216 gui/saveload-dialog.cpp:276
-#: gui/saveload-dialog.cpp:547 gui/saveload-dialog.cpp:922
+#: gui/saveload-dialog.cpp:547 gui/saveload-dialog.cpp:931
#: gui/themebrowser.cpp:55 gui/fluidsynth-dialog.cpp:152
-#: engines/engine.cpp:452 backends/platform/wii/options.cpp:48
+#: engines/engine.cpp:483 backends/platform/wii/options.cpp:48
#: backends/events/default/default-events.cpp:196
#: backends/events/default/default-events.cpp:218
#: engines/drascula/saveload.cpp:49 engines/parallaction/saveload.cpp:274
@@ -73,9 +74,9 @@ msgid "Choose"
msgstr "Escolher"
#: gui/gui-manager.cpp:117 backends/keymapper/remap-dialog.cpp:53
-#: 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
+#: 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"
@@ -91,7 +92,7 @@ msgstr "Mostrar teclado"
msgid "Remap keys"
msgstr "Remapear teclas"
-#: gui/gui-manager.cpp:131 base/main.cpp:326 engines/scumm/help.cpp:86
+#: gui/gui-manager.cpp:131 base/main.cpp:326 engines/scumm/help.cpp:87
#, fuzzy
msgid "Toggle fullscreen"
msgstr "Habilita Tela Cheia"
@@ -106,13 +107,13 @@ 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:1240
-#: gui/saveload-dialog.cpp:923 gui/fluidsynth-dialog.cpp:153
-#: engines/engine.cpp:371 engines/engine.cpp:382
+#: 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:399 engines/parallaction/saveload.cpp:274
-#: engines/scumm/dialogs.cpp:193 engines/scumm/scumm.cpp:1825
+#: 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
@@ -482,7 +483,7 @@ msgstr ""
#: gui/launcher.cpp:793 gui/launcher.cpp:941 gui/launcher.cpp:1000
#: gui/fluidsynth-dialog.cpp:217
-#: backends/events/symbiansdl/symbiansdl-events.cpp:184
+#: 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
@@ -492,7 +493,7 @@ 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:184
+#: 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
@@ -531,6 +532,14 @@ msgstr ""
"ScummVM nуo conseguiu encontrar qualquer programa capaz de rodar o jogo "
"selecionado!"
+#: gui/launcher.cpp:1159
+msgid "Mass Add..."
+msgstr "Multi-Adiчуo..."
+
+#: gui/launcher.cpp:1161
+msgid "Record..."
+msgstr ""
+
#: gui/massadd.cpp:79 gui/massadd.cpp:82
msgid "... progress ..."
msgstr "... progresso ..."
@@ -633,7 +642,7 @@ msgid "Special dithering modes supported by some games"
msgstr "Modos especiais de dithering suportados por alguns jogos"
#: gui/options.cpp:760
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2249
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2298
msgid "Fullscreen mode"
msgstr "Modo Tela Cheia"
@@ -950,6 +959,43 @@ msgstr ""
"O tema que vocъ selecionou nуo suporta seu idioma atual. Se vocъ quiser usar "
"este tema vocъ precisa mudar para outro idioma."
+#: gui/recorderdialog.cpp:64
+msgid "Recorder or Playback Gameplay"
+msgstr ""
+
+#: gui/recorderdialog.cpp:69 gui/recorderdialog.cpp:156
+#: gui/saveload-dialog.cpp:220 gui/saveload-dialog.cpp:276
+msgid "Delete"
+msgstr "Excluir"
+
+#: gui/recorderdialog.cpp:71
+msgid "Record"
+msgstr ""
+
+#: gui/recorderdialog.cpp:72
+#, fuzzy
+msgid "Playback"
+msgstr "Jogar"
+
+#: gui/recorderdialog.cpp:74
+msgid "Edit"
+msgstr ""
+
+#: gui/recorderdialog.cpp:86 gui/recorderdialog.cpp:243
+#: gui/recorderdialog.cpp:253
+msgid "Author: "
+msgstr ""
+
+#: gui/recorderdialog.cpp:87 gui/recorderdialog.cpp:244
+#: gui/recorderdialog.cpp:254
+msgid "Notes: "
+msgstr ""
+
+#: gui/recorderdialog.cpp:155
+#, fuzzy
+msgid "Do you really want to delete this record?"
+msgstr "Vocъ realmente quer excluir este jogo salvo?"
+
#: gui/saveload-dialog.cpp:167
msgid "List view"
msgstr ""
@@ -970,23 +1016,19 @@ msgstr "Sem hora salva"
msgid "No playtime saved"
msgstr "Sem tempo de jogo salvo"
-#: gui/saveload-dialog.cpp:220 gui/saveload-dialog.cpp:276
-msgid "Delete"
-msgstr "Excluir"
-
#: gui/saveload-dialog.cpp:275
msgid "Do you really want to delete this saved game?"
msgstr "Vocъ realmente quer excluir este jogo salvo?"
-#: gui/saveload-dialog.cpp:385 gui/saveload-dialog.cpp:875
+#: gui/saveload-dialog.cpp:385 gui/saveload-dialog.cpp:884
msgid "Date: "
msgstr "Data:"
-#: gui/saveload-dialog.cpp:389 gui/saveload-dialog.cpp:881
+#: gui/saveload-dialog.cpp:389 gui/saveload-dialog.cpp:890
msgid "Time: "
msgstr "Hora:"
-#: gui/saveload-dialog.cpp:395 gui/saveload-dialog.cpp:889
+#: gui/saveload-dialog.cpp:395 gui/saveload-dialog.cpp:898
msgid "Playtime: "
msgstr "Tempo de jogo:"
@@ -1002,22 +1044,22 @@ msgstr ""
msgid "Prev"
msgstr ""
-#: gui/saveload-dialog.cpp:739
+#: gui/saveload-dialog.cpp:748
#, fuzzy
msgid "New Save"
msgstr "Salvar"
-#: gui/saveload-dialog.cpp:739
+#: gui/saveload-dialog.cpp:748
#, fuzzy
msgid "Create a new save game"
msgstr "Falha ao salvar o jogo"
-#: gui/saveload-dialog.cpp:868
+#: gui/saveload-dialog.cpp:877
#, fuzzy
msgid "Name: "
msgstr "Nome:"
-#: gui/saveload-dialog.cpp:940
+#: gui/saveload-dialog.cpp:949
#, c-format
msgid "Enter a description for slot %d:"
msgstr ""
@@ -1176,7 +1218,7 @@ msgstr "Pula linha"
msgid "Error running game:"
msgstr "Erro ao executar o jogo:"
-#: base/main.cpp:536
+#: base/main.cpp:554
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 "
@@ -1296,7 +1338,7 @@ 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:758
+#: engines/pegasus/pegasus.cpp:377 engines/sci/engine/kfile.cpp:759
#: engines/toltecs/menu.cpp:281 engines/tsage/scenes.cpp:598
msgid "Save game:"
msgstr "Salvar jogo:"
@@ -1309,7 +1351,7 @@ msgstr "Salvar jogo:"
#: 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:758 engines/scumm/dialogs.cpp:188
+#: engines/sci/engine/kfile.cpp:759 engines/scumm/dialogs.cpp:188
#: engines/toltecs/menu.cpp:281 engines/tsage/scenes.cpp:598
msgid "Save"
msgstr "Salvar"
@@ -1348,23 +1390,23 @@ msgstr "~C~ancelar"
msgid "~K~eys"
msgstr "~T~eclas"
-#: engines/engine.cpp:245
+#: engines/engine.cpp:276
msgid "Could not initialize color format."
msgstr "Nуo foi possэvel inicializar o formato de cor."
-#: engines/engine.cpp:253
+#: engines/engine.cpp:284
msgid "Could not switch to video mode: '"
msgstr "Nуo foi possэvel alternar o modo de vэdeo atual:"
-#: engines/engine.cpp:262
+#: engines/engine.cpp:293
msgid "Could not apply aspect ratio setting."
msgstr "Nуo foi possэvel aplicar a correчуo de proporчуo"
-#: engines/engine.cpp:267
+#: engines/engine.cpp:298
msgid "Could not apply fullscreen setting."
msgstr "Nуo foi possэvel aplicar a configuraчуo de tela cheia."
-#: engines/engine.cpp:367
+#: engines/engine.cpp:398
msgid ""
"You appear to be playing this game directly\n"
"from the CD. This is known to cause problems,\n"
@@ -1378,7 +1420,7 @@ msgstr ""
"os arquivos de dados para o disco rэgido.\n"
"Consulte o arquivo README para mais detalhes."
-#: engines/engine.cpp:378
+#: engines/engine.cpp:409
msgid ""
"This game has audio tracks in its disk. These\n"
"tracks need to be ripped from the disk using\n"
@@ -1392,7 +1434,7 @@ msgstr ""
"para ouvir a mњsica do jogo.\n"
"Consulte o arquivo README para mais detalhes."
-#: engines/engine.cpp:436
+#: engines/engine.cpp:467
#, fuzzy, c-format
msgid ""
"Gamestate load failed (%s)! Please consult the README for basic information, "
@@ -1402,7 +1444,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:449
+#: engines/engine.cpp:480
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 "
@@ -1412,7 +1454,7 @@ 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:452
+#: engines/engine.cpp:483
msgid "Start anyway"
msgstr "Iniciar de qualquer maneira"
@@ -1623,11 +1665,11 @@ msgstr "Modo Touchpad ligado."
msgid "Touchpad mode disabled."
msgstr "Modo Touchpad desligado."
-#: backends/platform/maemo/maemo.cpp:209
+#: backends/platform/maemo/maemo.cpp:208
msgid "Click Mode"
msgstr ""
-#: backends/platform/maemo/maemo.cpp:215
+#: backends/platform/maemo/maemo.cpp:214
#: backends/platform/symbian/src/SymbianActions.cpp:42
#: backends/platform/wince/CEActionsPocket.cpp:60
#: backends/platform/wince/CEActionsSmartphone.cpp:43
@@ -1635,12 +1677,12 @@ msgstr ""
msgid "Left Click"
msgstr "Clique com o botуo esquerdo"
-#: backends/platform/maemo/maemo.cpp:218
+#: backends/platform/maemo/maemo.cpp:217
#, fuzzy
msgid "Middle Click"
msgstr "Item do meio na esquerda"
-#: backends/platform/maemo/maemo.cpp:221
+#: 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
@@ -1677,19 +1719,19 @@ msgctxt "lowres"
msgid "Normal (no scaling)"
msgstr "Normal (sem escala)"
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2148
+#: 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:2154
+#: 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:2209
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2258
msgid "Active graphics filter:"
msgstr "Ativa os filtros grсficos"
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2251
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2300
msgid "Windowed mode"
msgstr "Modo janela"
@@ -1749,8 +1791,8 @@ msgstr "Modo rсpido"
#: 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:82
-#: engines/scumm/help.cpp:84
+#: engines/scumm/dialogs.cpp:192 engines/scumm/help.cpp:83
+#: engines/scumm/help.cpp:85
msgid "Quit"
msgstr "Sair"
@@ -1770,7 +1812,7 @@ msgstr "Teclado virtual"
msgid "Key mapper"
msgstr "Mapeador de Teclas"
-#: backends/events/symbiansdl/symbiansdl-events.cpp:184
+#: backends/events/symbiansdl/symbiansdl-events.cpp:186
msgid "Do you want to quit ?"
msgstr "Vocъ deseja sair ?"
@@ -2107,33 +2149,52 @@ msgstr "Clicando Habilitado"
msgid "Clicking Disabled"
msgstr "Clicando Desabilitado"
-#: engines/agi/detection.cpp:142 engines/drascula/detection.cpp:302
+#: 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.cpp:103
+#: engines/zvision/detection.cpp:246
msgid "Use original save/load screens"
msgstr ""
-#: engines/agi/detection.cpp:143 engines/drascula/detection.cpp:303
+#: 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/zvision/detection.cpp:104
+#: engines/zvision/detection.cpp:247
msgid "Use the original save/load screens, instead of the ScummVM ones"
msgstr ""
+#: engines/agi/detection.cpp:157
+msgid "Use an alternative palette"
+msgstr ""
+
+#: engines/agi/detection.cpp:158
+msgid ""
+"Use an alternative palette, common for all Amiga games. This was the old "
+"behavior"
+msgstr ""
+
+#: engines/agi/detection.cpp:167
+msgid "Mouse support"
+msgstr ""
+
+#: 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:857 engines/toltecs/menu.cpp:256
+#: engines/sci/engine/kfile.cpp:858 engines/toltecs/menu.cpp:256
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:857 engines/toltecs/menu.cpp:256
+#: engines/sci/engine/kfile.cpp:858 engines/toltecs/menu.cpp:256
msgid "Restore"
msgstr "Restaurar"
-#: engines/agos/saveload.cpp:160 engines/scumm/scumm.cpp:2368
+#: engines/agos/saveload.cpp:160 engines/scumm/scumm.cpp:2377
#, c-format
msgid ""
"Failed to load game state from file:\n"
@@ -2144,7 +2205,7 @@ msgstr ""
"\n"
"%s"
-#: engines/agos/saveload.cpp:195 engines/scumm/scumm.cpp:2361
+#: engines/agos/saveload.cpp:195 engines/scumm/scumm.cpp:2370
#, c-format
msgid ""
"Failed to save game state to file:\n"
@@ -2155,7 +2216,7 @@ msgstr ""
"\n"
"%s"
-#: engines/agos/saveload.cpp:203 engines/scumm/scumm.cpp:2379
+#: engines/agos/saveload.cpp:203 engines/scumm/scumm.cpp:2388
#, c-format
msgid ""
"Successfully saved game state in file:\n"
@@ -2171,11 +2232,11 @@ msgstr ""
msgid "Cutscene file '%s' not found!"
msgstr "Arquivo de vэdeo '%s' nуo encontrado!"
-#: engines/cge/detection.cpp:105 engines/cge2/detection.cpp:81
+#: engines/cge/detection.cpp:105 engines/cge2/detection.cpp:101
msgid "Color Blind Mode"
msgstr ""
-#: engines/cge/detection.cpp:106 engines/cge2/detection.cpp:82
+#: engines/cge/detection.cpp:106 engines/cge2/detection.cpp:102
msgid "Enable Color Blind Mode by default"
msgstr ""
@@ -2236,7 +2297,7 @@ msgstr "Modo rсpido"
msgid "Play movies at an increased speed"
msgstr ""
-#: engines/groovie/script.cpp:399
+#: engines/groovie/script.cpp:408
msgid "Failed to save game"
msgstr "Falha ao salvar o jogo"
@@ -2544,13 +2605,12 @@ msgid "Use an alternative game intro (CD version only)"
msgstr ""
#: engines/sci/detection.cpp:374
-msgid "EGA undithering"
-msgstr "EGA sem dithering"
+msgid "Skip EGA dithering pass (full color backgrounds)"
+msgstr ""
#: engines/sci/detection.cpp:375
-#, fuzzy
-msgid "Enable undithering in EGA games"
-msgstr "Habilita EGA sem dithering em jogos com suporte"
+msgid "Skip dithering pass in EGA games, graphics are shown with full colors"
+msgstr ""
#: engines/sci/detection.cpp:384
#, fuzzy
@@ -2621,12 +2681,14 @@ msgstr "Jogo pausado. Pressione ESPAЧO para continuar."
#. "Moechten Sie wirklich neu starten? (J/N)J"
#. Will react to J as 'Yes'
#: engines/scumm/dialogs.cpp:183
-msgid "Are you sure you want to restart? (Y/N)"
+#, 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
-msgid "Are you sure you want to quit? (Y/N)"
+#, 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
@@ -2714,516 +2776,540 @@ msgstr ""
msgid "Expert"
msgstr ""
-#: engines/scumm/help.cpp:73
+#: engines/scumm/help.cpp:74
msgid "Common keyboard commands:"
msgstr "Comandos de teclado comuns:"
-#: engines/scumm/help.cpp:74
+#: engines/scumm/help.cpp:75
msgid "Save / Load dialog"
msgstr "Menu Salvar / Carregar"
-#: engines/scumm/help.cpp:76
+#: engines/scumm/help.cpp:77
msgid "Skip line of text"
msgstr "Pula linha de texto"
-#: engines/scumm/help.cpp:77
+#: engines/scumm/help.cpp:78
msgid "Esc"
msgstr "Esc"
-#: engines/scumm/help.cpp:77
+#: engines/scumm/help.cpp:78
msgid "Skip cutscene"
msgstr "Pula cena"
-#: engines/scumm/help.cpp:78
+#: engines/scumm/help.cpp:79
msgid "Space"
msgstr "Espaчo"
-#: engines/scumm/help.cpp:78
+#: engines/scumm/help.cpp:79
msgid "Pause game"
msgstr "Pausar jogo:"
-#: engines/scumm/help.cpp:79 engines/scumm/help.cpp:84
-#: engines/scumm/help.cpp:95 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: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:79
+#: engines/scumm/help.cpp:80
msgid "Load game state 1-10"
msgstr "Carregar estado do jogo 1-10"
-#: engines/scumm/help.cpp:80 engines/scumm/help.cpp:84
-#: engines/scumm/help.cpp:86 engines/scumm/help.cpp:100
-#: engines/scumm/help.cpp:101 engines/scumm/help.cpp:102
+#: 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:80
+#: engines/scumm/help.cpp:81
msgid "Save game state 1-10"
msgstr "Salvar estado do jogo 1-10"
-#: engines/scumm/help.cpp:86 engines/scumm/help.cpp:89
+#: engines/scumm/help.cpp:87 engines/scumm/help.cpp:90
msgid "Enter"
msgstr "Enter"
-#: engines/scumm/help.cpp:87
+#: engines/scumm/help.cpp:88
msgid "Music volume up / down"
msgstr "Volume da mњsica"
-#: engines/scumm/help.cpp:88
+#: engines/scumm/help.cpp:89
msgid "Text speed slower / faster"
msgstr "Velocidade do texto devagar / rсpido"
-#: engines/scumm/help.cpp:89
+#: engines/scumm/help.cpp:90
msgid "Simulate left mouse button"
msgstr "Simula botуo esquerdo do mouse"
-#: engines/scumm/help.cpp:90
+#: engines/scumm/help.cpp:91
msgid "Tab"
msgstr "Tab"
-#: engines/scumm/help.cpp:90
+#: engines/scumm/help.cpp:91
msgid "Simulate right mouse button"
msgstr "Simula botуo direito do mouse"
-#: engines/scumm/help.cpp:93
+#: engines/scumm/help.cpp:94
msgid "Special keyboard commands:"
msgstr "Comandos de teclado especiais:"
-#: engines/scumm/help.cpp:94
+#: engines/scumm/help.cpp:95
msgid "Show / Hide console"
msgstr "Mostrar / Ocultar console"
-#: engines/scumm/help.cpp:95
+#: engines/scumm/help.cpp:96
msgid "Start the debugger"
msgstr "Inicia o depurador"
-#: engines/scumm/help.cpp:96
+#: engines/scumm/help.cpp:97
msgid "Show memory consumption"
msgstr "Exibe o consumo de memѓria"
-#: engines/scumm/help.cpp:97
+#: engines/scumm/help.cpp:98
msgid "Run in fast mode (*)"
msgstr "Joga em modo rсpido (*)"
-#: engines/scumm/help.cpp:98
+#: engines/scumm/help.cpp:99
msgid "Run in really fast mode (*)"
msgstr "Joga em modo super rсpido (*)"
-#: engines/scumm/help.cpp:99
+#: engines/scumm/help.cpp:100
msgid "Toggle mouse capture"
msgstr "Habilita captura do mouse"
-#: engines/scumm/help.cpp:100
+#: engines/scumm/help.cpp:101
msgid "Switch between graphics filters"
msgstr "Alterna entre os filtros grсficos"
-#: engines/scumm/help.cpp:101
+#: engines/scumm/help.cpp:102
msgid "Increase / Decrease scale factor"
msgstr "Aumenta / Diminui o fator de escala"
-#: engines/scumm/help.cpp:102
+#: engines/scumm/help.cpp:103
msgid "Toggle aspect-ratio correction"
msgstr "Habilita correчуo de proporчуo"
-#: engines/scumm/help.cpp:107
+#: engines/scumm/help.cpp:108
msgid "* Note that using ctrl-f and"
msgstr "* A utilizaчуo de ctrl-f ou"
-#: engines/scumm/help.cpp:108
+#: engines/scumm/help.cpp:109
msgid " ctrl-g are not recommended"
msgstr " ctrl-g nуo щ recomendada"
-#: engines/scumm/help.cpp:109
+#: engines/scumm/help.cpp:110
msgid " since they may cause crashes"
msgstr " visto que poderс causar travas"
-#: engines/scumm/help.cpp:110
+#: engines/scumm/help.cpp:111
msgid " or incorrect game behavior."
msgstr " ou procedimentos estranhos nos jogos."
-#: engines/scumm/help.cpp:114
+#: engines/scumm/help.cpp:115
msgid "Spinning drafts on the keyboard:"
msgstr "Tecer feitiчos no teclado:"
-#: engines/scumm/help.cpp:116
+#: engines/scumm/help.cpp:117
msgid "Main game controls:"
msgstr "Controles principais do jogo:"
-#: engines/scumm/help.cpp:121 engines/scumm/help.cpp:136
-#: engines/scumm/help.cpp:161
+#: engines/scumm/help.cpp:122 engines/scumm/help.cpp:137
+#: engines/scumm/help.cpp:162
msgid "Push"
msgstr "Empurar"
-#: engines/scumm/help.cpp:122 engines/scumm/help.cpp:137
-#: engines/scumm/help.cpp:162
+#: engines/scumm/help.cpp:123 engines/scumm/help.cpp:138
+#: engines/scumm/help.cpp:163
msgid "Pull"
msgstr "Puxar"
-#: engines/scumm/help.cpp:123 engines/scumm/help.cpp:138
-#: engines/scumm/help.cpp:163 engines/scumm/help.cpp:197
-#: engines/scumm/help.cpp:207
+#: 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 "Dar"
-#: engines/scumm/help.cpp:124 engines/scumm/help.cpp:139
-#: engines/scumm/help.cpp:164 engines/scumm/help.cpp:190
-#: engines/scumm/help.cpp:208
+#: 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 "Abrir"
-#: engines/scumm/help.cpp:126
+#: engines/scumm/help.cpp:127
msgid "Go to"
msgstr "Ir para"
-#: engines/scumm/help.cpp:127
+#: engines/scumm/help.cpp:128
msgid "Get"
msgstr "Pegar"
-#: engines/scumm/help.cpp:128 engines/scumm/help.cpp:152
-#: engines/scumm/help.cpp:170 engines/scumm/help.cpp:198
-#: engines/scumm/help.cpp:213 engines/scumm/help.cpp:224
-#: engines/scumm/help.cpp:250
+#: 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 "Usar"
-#: engines/scumm/help.cpp:129 engines/scumm/help.cpp:141
+#: engines/scumm/help.cpp:130 engines/scumm/help.cpp:142
msgid "Read"
msgstr "Ler"
-#: engines/scumm/help.cpp:130 engines/scumm/help.cpp:147
+#: engines/scumm/help.cpp:131 engines/scumm/help.cpp:148
msgid "New kid"
msgstr "Nova crianчa"
-#: engines/scumm/help.cpp:131 engines/scumm/help.cpp:153
-#: engines/scumm/help.cpp:171
+#: engines/scumm/help.cpp:132 engines/scumm/help.cpp:154
+#: engines/scumm/help.cpp:172
msgid "Turn on"
msgstr "Ligar"
-#: engines/scumm/help.cpp:132 engines/scumm/help.cpp:154
-#: engines/scumm/help.cpp:172
+#: engines/scumm/help.cpp:133 engines/scumm/help.cpp:155
+#: engines/scumm/help.cpp:173
msgid "Turn off"
msgstr "Desligar"
-#: engines/scumm/help.cpp:142 engines/scumm/help.cpp:167
-#: engines/scumm/help.cpp:194
+#: engines/scumm/help.cpp:143 engines/scumm/help.cpp:168
+#: engines/scumm/help.cpp:195
msgid "Walk to"
msgstr "Andar atщ"
-#: engines/scumm/help.cpp:143 engines/scumm/help.cpp:168
-#: engines/scumm/help.cpp:195 engines/scumm/help.cpp:210
-#: engines/scumm/help.cpp:227
+#: 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 "Pegar"
-#: engines/scumm/help.cpp:144 engines/scumm/help.cpp:169
+#: engines/scumm/help.cpp:145 engines/scumm/help.cpp:170
msgid "What is"
msgstr "O que щ"
-#: engines/scumm/help.cpp:146
+#: engines/scumm/help.cpp:147
msgid "Unlock"
msgstr "Destravar"
-#: engines/scumm/help.cpp:149
+#: engines/scumm/help.cpp:150
msgid "Put on"
msgstr "Vestir"
-#: engines/scumm/help.cpp:150
+#: engines/scumm/help.cpp:151
msgid "Take off"
msgstr "Decolar"
-#: engines/scumm/help.cpp:156
+#: engines/scumm/help.cpp:157
msgid "Fix"
msgstr "Consertar"
-#: engines/scumm/help.cpp:158
+#: engines/scumm/help.cpp:159
msgid "Switch"
msgstr "Trocar"
-#: engines/scumm/help.cpp:166 engines/scumm/help.cpp:228
+#: engines/scumm/help.cpp:167 engines/scumm/help.cpp:229
msgid "Look"
msgstr "Olhar"
-#: engines/scumm/help.cpp:173 engines/scumm/help.cpp:223
+#: engines/scumm/help.cpp:174 engines/scumm/help.cpp:224
msgid "Talk"
msgstr "Falar"
-#: engines/scumm/help.cpp:174
+#: engines/scumm/help.cpp:175
msgid "Travel"
msgstr "Viajar"
-#: engines/scumm/help.cpp:175
+#: engines/scumm/help.cpp:176
msgid "To Henry / To Indy"
msgstr "Para Henry / Para Indy"
#. I18N: These are different musical notes
-#: engines/scumm/help.cpp:179
+#: engines/scumm/help.cpp:180
msgid "play C minor on distaff"
msgstr "toca dѓ menor no fio"
-#: engines/scumm/help.cpp:180
+#: engines/scumm/help.cpp:181
msgid "play D on distaff"
msgstr "toca D no fio"
-#: engines/scumm/help.cpp:181
+#: engines/scumm/help.cpp:182
msgid "play E on distaff"
msgstr "toca E no fio"
-#: engines/scumm/help.cpp:182
+#: engines/scumm/help.cpp:183
msgid "play F on distaff"
msgstr "toca F no fio"
-#: engines/scumm/help.cpp:183
+#: engines/scumm/help.cpp:184
msgid "play G on distaff"
msgstr "toca G no fio"
-#: engines/scumm/help.cpp:184
+#: engines/scumm/help.cpp:185
msgid "play A on distaff"
msgstr "toca A no fio"
-#: engines/scumm/help.cpp:185
+#: engines/scumm/help.cpp:186
msgid "play B on distaff"
msgstr "toca B no fio"
-#: engines/scumm/help.cpp:186
+#: engines/scumm/help.cpp:187
msgid "play C major on distaff"
msgstr "toca dѓ maior no fio"
-#: engines/scumm/help.cpp:192 engines/scumm/help.cpp:214
+#: engines/scumm/help.cpp:193 engines/scumm/help.cpp:215
msgid "puSh"
msgstr "Empurrar"
-#: engines/scumm/help.cpp:193 engines/scumm/help.cpp:215
+#: engines/scumm/help.cpp:194 engines/scumm/help.cpp:216
msgid "pull (Yank)"
msgstr "Puxar"
-#: engines/scumm/help.cpp:196 engines/scumm/help.cpp:212
-#: engines/scumm/help.cpp:248
+#: engines/scumm/help.cpp:197 engines/scumm/help.cpp:213
+#: engines/scumm/help.cpp:249
msgid "Talk to"
msgstr "Falar"
-#: engines/scumm/help.cpp:199 engines/scumm/help.cpp:211
+#: engines/scumm/help.cpp:200 engines/scumm/help.cpp:212
msgid "Look at"
msgstr "Olhar para"
-#: engines/scumm/help.cpp:200
+#: engines/scumm/help.cpp:201
msgid "turn oN"
msgstr "Ligar"
-#: engines/scumm/help.cpp:201
+#: engines/scumm/help.cpp:202
msgid "turn oFf"
msgstr "Desligar"
-#: engines/scumm/help.cpp:217
+#: engines/scumm/help.cpp:218
msgid "KeyUp"
msgstr "TeclaCima"
-#: engines/scumm/help.cpp:217
+#: engines/scumm/help.cpp:218
msgid "Highlight prev dialogue"
msgstr "Destacar diсlogo anterior"
-#: engines/scumm/help.cpp:218
+#: engines/scumm/help.cpp:219
msgid "KeyDown"
msgstr "TeclaBaixo"
-#: engines/scumm/help.cpp:218
+#: engines/scumm/help.cpp:219
msgid "Highlight next dialogue"
msgstr "Destacar prѓximo diсlogo"
-#: engines/scumm/help.cpp:222
+#: engines/scumm/help.cpp:223
msgid "Walk"
msgstr "Andar"
-#: engines/scumm/help.cpp:225 engines/scumm/help.cpp:234
-#: engines/scumm/help.cpp:241 engines/scumm/help.cpp:249
+#: engines/scumm/help.cpp:226 engines/scumm/help.cpp:235
+#: engines/scumm/help.cpp:242 engines/scumm/help.cpp:250
msgid "Inventory"
msgstr "Inventсrio"
-#: engines/scumm/help.cpp:226
+#: engines/scumm/help.cpp:227
msgid "Object"
msgstr "Objeto"
-#: engines/scumm/help.cpp:229
+#: engines/scumm/help.cpp:230
msgid "Black and White / Color"
msgstr "Preto e Branco / Cor"
-#: engines/scumm/help.cpp:232
+#: engines/scumm/help.cpp:233
msgid "Eyes"
msgstr "Olhos"
-#: engines/scumm/help.cpp:233
+#: engines/scumm/help.cpp:234
msgid "Tongue"
msgstr "Lэngua"
-#: engines/scumm/help.cpp:235
+#: engines/scumm/help.cpp:236
msgid "Punch"
msgstr "Soco"
-#: engines/scumm/help.cpp:236
+#: engines/scumm/help.cpp:237
msgid "Kick"
msgstr "Chute"
-#: engines/scumm/help.cpp:239 engines/scumm/help.cpp:247
+#: engines/scumm/help.cpp:240 engines/scumm/help.cpp:248
msgid "Examine"
msgstr "Examinar"
-#: engines/scumm/help.cpp:240
+#: engines/scumm/help.cpp:241
msgid "Regular cursor"
msgstr "Cursor normal"
#. I18N: Comm is a communication device
-#: engines/scumm/help.cpp:243
+#: engines/scumm/help.cpp:244
msgid "Comm"
msgstr "Comunicador"
-#: engines/scumm/help.cpp:246
+#: engines/scumm/help.cpp:247
msgid "Save / Load / Options"
msgstr "Salvar / Carregar / Opчѕes"
-#: engines/scumm/help.cpp:255
+#: engines/scumm/help.cpp:256
msgid "Other game controls:"
msgstr "Outros controles do jogo:"
-#: engines/scumm/help.cpp:257 engines/scumm/help.cpp:267
+#: engines/scumm/help.cpp:258 engines/scumm/help.cpp:268
msgid "Inventory:"
msgstr "Inventсrio:"
-#: engines/scumm/help.cpp:258 engines/scumm/help.cpp:274
+#: engines/scumm/help.cpp:259 engines/scumm/help.cpp:275
msgid "Scroll list up"
msgstr "Subir na lista"
-#: engines/scumm/help.cpp:259 engines/scumm/help.cpp:275
+#: engines/scumm/help.cpp:260 engines/scumm/help.cpp:276
msgid "Scroll list down"
msgstr "Descer na lista"
-#: engines/scumm/help.cpp:260 engines/scumm/help.cpp:268
+#: engines/scumm/help.cpp:261 engines/scumm/help.cpp:269
msgid "Upper left item"
msgstr "Item da esquerda superior"
-#: engines/scumm/help.cpp:261 engines/scumm/help.cpp:270
+#: engines/scumm/help.cpp:262 engines/scumm/help.cpp:271
msgid "Lower left item"
msgstr "Item da esquerda inferior"
-#: engines/scumm/help.cpp:262 engines/scumm/help.cpp:271
+#: engines/scumm/help.cpp:263 engines/scumm/help.cpp:272
msgid "Upper right item"
msgstr "Item da direita superior"
-#: engines/scumm/help.cpp:263 engines/scumm/help.cpp:273
+#: engines/scumm/help.cpp:264 engines/scumm/help.cpp:274
msgid "Lower right item"
msgstr "Item da direita inferior"
-#: engines/scumm/help.cpp:269
+#: engines/scumm/help.cpp:270
msgid "Middle left item"
msgstr "Item do meio na esquerda"
-#: engines/scumm/help.cpp:272
+#: engines/scumm/help.cpp:273
msgid "Middle right item"
msgstr "Item do meio na direita"
-#: engines/scumm/help.cpp:279 engines/scumm/help.cpp:284
+#: engines/scumm/help.cpp:280 engines/scumm/help.cpp:285
msgid "Switching characters:"
msgstr "Trocando personagens:"
-#: engines/scumm/help.cpp:281
+#: engines/scumm/help.cpp:282
msgid "Second kid"
msgstr "Segunda crianчa"
-#: engines/scumm/help.cpp:282
+#: engines/scumm/help.cpp:283
msgid "Third kid"
msgstr "Terceira crianчa"
-#: engines/scumm/help.cpp:294
+#: engines/scumm/help.cpp:292
+msgid "Toggle Inventory/IQ Points display"
+msgstr ""
+
+#: engines/scumm/help.cpp:293
+msgid "Toggle Keyboard/Mouse Fighting (*)"
+msgstr ""
+
+#: engines/scumm/help.cpp:295
+msgid "* Keyboard Fighting is always on,"
+msgstr ""
+
+#: engines/scumm/help.cpp:296
+msgid " so despite the in-game message this"
+msgstr ""
+
+#: engines/scumm/help.cpp:297
+msgid " actually toggles Mouse Fighting Off/On"
+msgstr ""
+
+#: engines/scumm/help.cpp:304
msgid "Fighting controls (numpad):"
msgstr "Controle de luta (teclado numщrico):"
-#: engines/scumm/help.cpp:295 engines/scumm/help.cpp:296
-#: engines/scumm/help.cpp:297
+#: engines/scumm/help.cpp:305 engines/scumm/help.cpp:306
+#: engines/scumm/help.cpp:307
msgid "Step back"
msgstr "Passo para trсs"
-#: engines/scumm/help.cpp:298
+#: engines/scumm/help.cpp:308
msgid "Block high"
msgstr "Defender em cima"
-#: engines/scumm/help.cpp:299
+#: engines/scumm/help.cpp:309
msgid "Block middle"
msgstr "Defender no meio"
-#: engines/scumm/help.cpp:300
+#: engines/scumm/help.cpp:310
msgid "Block low"
msgstr "Defender embaixo"
-#: engines/scumm/help.cpp:301
+#: engines/scumm/help.cpp:311
msgid "Punch high"
msgstr "Soco em cima"
-#: engines/scumm/help.cpp:302
+#: engines/scumm/help.cpp:312
msgid "Punch middle"
msgstr "Soco no meio"
-#: engines/scumm/help.cpp:303
+#: engines/scumm/help.cpp:313
msgid "Punch low"
msgstr "Soco embaixo"
-#: engines/scumm/help.cpp:306
+#: engines/scumm/help.cpp:315
+msgid "Sucker punch"
+msgstr ""
+
+#: engines/scumm/help.cpp:318
msgid "These are for Indy on left."
msgstr "Estes sуo para o Indy na esquerda."
-#: engines/scumm/help.cpp:307
+#: engines/scumm/help.cpp:319
msgid "When Indy is on the right,"
msgstr "Quando Indy estiver na direita,"
-#: engines/scumm/help.cpp:308
+#: engines/scumm/help.cpp:320
msgid "7, 4, and 1 are switched with"
msgstr "7, 4 e 1 sуo trocados por"
-#: engines/scumm/help.cpp:309
+#: engines/scumm/help.cpp:321
msgid "9, 6, and 3, respectively."
msgstr "9, 6 e 3, respectivamente."
-#: engines/scumm/help.cpp:316
+#: engines/scumm/help.cpp:328
msgid "Biplane controls (numpad):"
msgstr "Controles do aviуo (teclado numщrico)"
-#: engines/scumm/help.cpp:317
+#: engines/scumm/help.cpp:329
msgid "Fly to upper left"
msgstr "Voar para esquerda superior"
-#: engines/scumm/help.cpp:318
+#: engines/scumm/help.cpp:330
msgid "Fly to left"
msgstr "Voar para esquerda"
-#: engines/scumm/help.cpp:319
+#: engines/scumm/help.cpp:331
msgid "Fly to lower left"
msgstr "Voar para esquerda inferior"
-#: engines/scumm/help.cpp:320
+#: engines/scumm/help.cpp:332
msgid "Fly upwards"
msgstr "Voar para cima"
-#: engines/scumm/help.cpp:321
+#: engines/scumm/help.cpp:333
msgid "Fly straight"
msgstr "Voar reto"
-#: engines/scumm/help.cpp:322
+#: engines/scumm/help.cpp:334
msgid "Fly down"
msgstr "Voar para baixo"
-#: engines/scumm/help.cpp:323
+#: engines/scumm/help.cpp:335
msgid "Fly to upper right"
msgstr "Voar para direita superior"
-#: engines/scumm/help.cpp:324
+#: engines/scumm/help.cpp:336
msgid "Fly to right"
msgstr "Voar para direita"
-#: engines/scumm/help.cpp:325
+#: engines/scumm/help.cpp:337
msgid "Fly to lower right"
msgstr "Voar para direita inferior"
-#: engines/scumm/scumm.cpp:1823
+#: engines/scumm/scumm.cpp:1832
#, c-format
msgid ""
"Native MIDI support requires the Roland Upgrade from LucasArts,\n"
@@ -3233,11 +3319,12 @@ msgstr ""
"LucasArts,\n"
"mas %s estс faltando. Utilizando AdLib ao invщs."
-#: engines/scumm/scumm.cpp:2594
+#: engines/scumm/scumm.cpp:2644
+#, fuzzy
msgid ""
-"Usually, Maniac Mansion would start now. But ScummVM doesn't do that yet. To "
-"play it, go to 'Add Game' in the ScummVM start menu and select the 'Maniac' "
-"directory inside the Tentacle game directory."
+"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 ""
"\"Na versуo original, o jogo Maniac Mansion rodaria agora mesmo. Porem a "
"atual versуo do ScummVM nуo suporta essa aчуo. Para jogar Maniac Mansion, "
@@ -3378,6 +3465,47 @@ msgstr ""
msgid "Show the current number of frames per second in the upper left corner"
msgstr ""
+#: engines/zvision/detection.cpp:256
+msgid "Double FPS"
+msgstr ""
+
+#: engines/zvision/detection.cpp:257
+msgid "Increase game FPS from 30 to 60"
+msgstr ""
+
+#: engines/zvision/detection.cpp:266
+#, fuzzy
+msgid "Enable Venus"
+msgstr "Ligar modo Roland GS"
+
+#: engines/zvision/detection.cpp:267
+msgid "Enable the Venus help system"
+msgstr ""
+
+#: engines/zvision/detection.cpp:276
+msgid "Disable animation while turning"
+msgstr ""
+
+#: engines/zvision/detection.cpp:277
+msgid "Disable animation while turning in panoramic mode"
+msgstr ""
+
+#: engines/zvision/detection.cpp:286
+msgid "Use the hires MPEG movies"
+msgstr ""
+
+#: engines/zvision/detection.cpp:287
+msgid ""
+"Use the hires MPEG movies of the DVD version, instead of the lowres AVI ones"
+msgstr ""
+
+#~ msgid "EGA undithering"
+#~ msgstr "EGA sem dithering"
+
+#, fuzzy
+#~ msgid "Enable undithering in EGA games"
+#~ msgstr "Habilita EGA sem dithering em jogos com suporte"
+
#, fuzzy
#~ msgid "MPEG-2 cutscenes found but ScummVM has been built without MPEG-2"
#~ msgstr ""
@@ -3388,9 +3516,6 @@ msgstr ""
#~ msgid "Mass Add..."
#~ msgstr "Multi-Adiчуo..."
-#~ msgid "Mass Add..."
-#~ msgstr "Multi-Adiчуo..."
-
#~ msgid ""
#~ "Turns off General MIDI mapping for games with Roland MT-32 soundtrack"
#~ msgstr ""
diff --git a/po/ru_RU.po b/po/ru_RU.po
index adc5fcdc1d..066333bbb5 100644
--- a/po/ru_RU.po
+++ b/po/ru_RU.po
@@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: ScummVM 1.3.0svn\n"
"Report-Msgid-Bugs-To: scummvm-devel@lists.sf.net\n"
-"POT-Creation-Date: 2014-10-04 00:58+0100\n"
+"POT-Creation-Date: 2015-06-30 20:57+0100\n"
"PO-Revision-Date: 2014-07-02 17:20+0300\n"
"Last-Translator: Eugene Sandulenko <sev@scummvm.org>\n"
"Language-Team: Russian\n"
@@ -55,10 +55,11 @@ msgstr "Вверх"
#: gui/browser.cpp:75 gui/chooser.cpp:46 gui/KeysDialog.cpp:43
#: gui/launcher.cpp:351 gui/massadd.cpp:95 gui/options.cpp:1239
+#: gui/recorderdialog.cpp:70 gui/recorderdialog.cpp:156
#: gui/saveload-dialog.cpp:216 gui/saveload-dialog.cpp:276
-#: gui/saveload-dialog.cpp:547 gui/saveload-dialog.cpp:922
+#: gui/saveload-dialog.cpp:547 gui/saveload-dialog.cpp:931
#: gui/themebrowser.cpp:55 gui/fluidsynth-dialog.cpp:152
-#: engines/engine.cpp:452 backends/platform/wii/options.cpp:48
+#: engines/engine.cpp:483 backends/platform/wii/options.cpp:48
#: backends/events/default/default-events.cpp:196
#: backends/events/default/default-events.cpp:218
#: engines/drascula/saveload.cpp:49 engines/parallaction/saveload.cpp:274
@@ -71,9 +72,9 @@ msgid "Choose"
msgstr "Выбрать"
#: gui/gui-manager.cpp:117 backends/keymapper/remap-dialog.cpp:53
-#: 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
+#: 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 "Закрыть"
@@ -89,7 +90,7 @@ msgstr "Показать клавиатуру"
msgid "Remap keys"
msgstr "Переназначить клавиши"
-#: gui/gui-manager.cpp:131 base/main.cpp:326 engines/scumm/help.cpp:86
+#: gui/gui-manager.cpp:131 base/main.cpp:326 engines/scumm/help.cpp:87
msgid "Toggle fullscreen"
msgstr "Переключение на весь экран"
@@ -103,13 +104,13 @@ msgstr "Назначить"
#: gui/KeysDialog.cpp:42 gui/launcher.cpp:352 gui/launcher.cpp:1048
#: gui/launcher.cpp:1052 gui/massadd.cpp:92 gui/options.cpp:1240
-#: gui/saveload-dialog.cpp:923 gui/fluidsynth-dialog.cpp:153
-#: engines/engine.cpp:371 engines/engine.cpp:382
+#: 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:399 engines/parallaction/saveload.cpp:274
-#: engines/scumm/dialogs.cpp:193 engines/scumm/scumm.cpp:1825
+#: 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
@@ -478,7 +479,7 @@ msgstr ""
#: gui/launcher.cpp:793 gui/launcher.cpp:941 gui/launcher.cpp:1000
#: gui/fluidsynth-dialog.cpp:217
-#: backends/events/symbiansdl/symbiansdl-events.cpp:184
+#: 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
@@ -488,7 +489,7 @@ msgstr "Да"
#: gui/launcher.cpp:793 gui/launcher.cpp:941 gui/launcher.cpp:1000
#: gui/fluidsynth-dialog.cpp:217
-#: backends/events/symbiansdl/symbiansdl-events.cpp:184
+#: 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
@@ -524,6 +525,14 @@ msgstr "Эта игра не поддерживает загрузку сохранений через главное меню."
msgid "ScummVM could not find any engine capable of running the selected game!"
msgstr "ScummVM не смог найти движок для запуска выбранной игры!"
+#: gui/launcher.cpp:1159
+msgid "Mass Add..."
+msgstr "Много игр..."
+
+#: gui/launcher.cpp:1161
+msgid "Record..."
+msgstr ""
+
#: gui/massadd.cpp:79 gui/massadd.cpp:82
msgid "... progress ..."
msgstr "... ищу ..."
@@ -622,7 +631,7 @@ msgid "Special dithering modes supported by some games"
msgstr "Специальные режимы рендеринга, поддерживаемые некоторыми играми"
#: gui/options.cpp:760
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2249
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2298
msgid "Fullscreen mode"
msgstr "Полноэкранный режим"
@@ -943,6 +952,43 @@ msgstr ""
"Тема, выбранная вами, не поддерживает текущий язык. Если вы хотите "
"использовать эту тему, вам необходимо сначала переключиться на другой язык."
+#: gui/recorderdialog.cpp:64
+msgid "Recorder or Playback Gameplay"
+msgstr ""
+
+#: gui/recorderdialog.cpp:69 gui/recorderdialog.cpp:156
+#: gui/saveload-dialog.cpp:220 gui/saveload-dialog.cpp:276
+msgid "Delete"
+msgstr "Удалить"
+
+#: gui/recorderdialog.cpp:71
+msgid "Record"
+msgstr ""
+
+#: gui/recorderdialog.cpp:72
+#, fuzzy
+msgid "Playback"
+msgstr "Играть"
+
+#: gui/recorderdialog.cpp:74
+msgid "Edit"
+msgstr ""
+
+#: gui/recorderdialog.cpp:86 gui/recorderdialog.cpp:243
+#: gui/recorderdialog.cpp:253
+msgid "Author: "
+msgstr ""
+
+#: gui/recorderdialog.cpp:87 gui/recorderdialog.cpp:244
+#: gui/recorderdialog.cpp:254
+msgid "Notes: "
+msgstr ""
+
+#: gui/recorderdialog.cpp:155
+#, fuzzy
+msgid "Do you really want to delete this record?"
+msgstr "Вы действительно хотите удалить это сохранение?"
+
#: gui/saveload-dialog.cpp:167
msgid "List view"
msgstr "Вид списка"
@@ -963,23 +1009,19 @@ msgstr "Время не записано"
msgid "No playtime saved"
msgstr "Время игры не записано"
-#: gui/saveload-dialog.cpp:220 gui/saveload-dialog.cpp:276
-msgid "Delete"
-msgstr "Удалить"
-
#: gui/saveload-dialog.cpp:275
msgid "Do you really want to delete this saved game?"
msgstr "Вы действительно хотите удалить это сохранение?"
-#: gui/saveload-dialog.cpp:385 gui/saveload-dialog.cpp:875
+#: gui/saveload-dialog.cpp:385 gui/saveload-dialog.cpp:884
msgid "Date: "
msgstr "Дата: "
-#: gui/saveload-dialog.cpp:389 gui/saveload-dialog.cpp:881
+#: gui/saveload-dialog.cpp:389 gui/saveload-dialog.cpp:890
msgid "Time: "
msgstr "Время: "
-#: gui/saveload-dialog.cpp:395 gui/saveload-dialog.cpp:889
+#: gui/saveload-dialog.cpp:395 gui/saveload-dialog.cpp:898
msgid "Playtime: "
msgstr "Время игры: "
@@ -995,19 +1037,19 @@ msgstr "Следующий"
msgid "Prev"
msgstr "Предыдущий"
-#: gui/saveload-dialog.cpp:739
+#: gui/saveload-dialog.cpp:748
msgid "New Save"
msgstr "Новое сохранение"
-#: gui/saveload-dialog.cpp:739
+#: gui/saveload-dialog.cpp:748
msgid "Create a new save game"
msgstr "Создать новую запись игры"
-#: gui/saveload-dialog.cpp:868
+#: gui/saveload-dialog.cpp:877
msgid "Name: "
msgstr "Название: "
-#: gui/saveload-dialog.cpp:940
+#: gui/saveload-dialog.cpp:949
#, c-format
msgid "Enter a description for slot %d:"
msgstr "Введите описание слота %d:"
@@ -1160,7 +1202,7 @@ msgstr "Пропустить строку"
msgid "Error running game:"
msgstr "Ошибка запуска игры:"
-#: base/main.cpp:536
+#: base/main.cpp:554
msgid "Could not find any engine capable of running the selected game"
msgstr "Не могу найти движок для запуска выбранной игры"
@@ -1278,7 +1320,7 @@ 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:758
+#: engines/pegasus/pegasus.cpp:377 engines/sci/engine/kfile.cpp:759
#: engines/toltecs/menu.cpp:281 engines/tsage/scenes.cpp:598
msgid "Save game:"
msgstr "Сохранить игру:"
@@ -1291,7 +1333,7 @@ msgstr "Сохранить игру:"
#: 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:758 engines/scumm/dialogs.cpp:188
+#: engines/sci/engine/kfile.cpp:759 engines/scumm/dialogs.cpp:188
#: engines/toltecs/menu.cpp:281 engines/tsage/scenes.cpp:598
msgid "Save"
msgstr "Сохранить"
@@ -1330,23 +1372,23 @@ msgstr "О~т~мена"
msgid "~K~eys"
msgstr "~К~лавиши"
-#: engines/engine.cpp:245
+#: engines/engine.cpp:276
msgid "Could not initialize color format."
msgstr "Не могу инициализировать формат цвета."
-#: engines/engine.cpp:253
+#: engines/engine.cpp:284
msgid "Could not switch to video mode: '"
msgstr "Не удалось переключить видеорежим: '"
-#: engines/engine.cpp:262
+#: engines/engine.cpp:293
msgid "Could not apply aspect ratio setting."
msgstr "Не удалось использовать коррекцию соотношения сторон."
-#: engines/engine.cpp:267
+#: engines/engine.cpp:298
msgid "Could not apply fullscreen setting."
msgstr "Не могу применить полноэкранный режим."
-#: engines/engine.cpp:367
+#: engines/engine.cpp:398
msgid ""
"You appear to be playing this game directly\n"
"from the CD. This is known to cause problems,\n"
@@ -1360,7 +1402,7 @@ msgstr ""
"на жёсткий диск. Подробности можно найти в\n"
"файле README."
-#: engines/engine.cpp:378
+#: engines/engine.cpp:409
msgid ""
"This game has audio tracks in its disk. These\n"
"tracks need to be ripped from the disk using\n"
@@ -1375,7 +1417,7 @@ msgstr ""
"появится музыка. Подробности можно найти в\n"
"файле README."
-#: engines/engine.cpp:436
+#: engines/engine.cpp:467
#, c-format
msgid ""
"Gamestate load failed (%s)! Please consult the README for basic information, "
@@ -1385,7 +1427,7 @@ msgstr ""
"README за базовой информацией, а также инструкциями о том, как получить "
"дальнейшую помощь."
-#: engines/engine.cpp:449
+#: engines/engine.cpp:480
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 "
@@ -1395,7 +1437,7 @@ msgstr ""
"поддерживается ScummVM полностью. Она, скорее всего, не будет работать "
"стабильно, и сохранения игр могут не работать в будущих версиях ScummVM."
-#: engines/engine.cpp:452
+#: engines/engine.cpp:483
msgid "Start anyway"
msgstr "Всё равно запустить"
@@ -1605,11 +1647,11 @@ msgstr "Режим тачпада включён."
msgid "Touchpad mode disabled."
msgstr "Режим тачпада выключен."
-#: backends/platform/maemo/maemo.cpp:209
+#: backends/platform/maemo/maemo.cpp:208
msgid "Click Mode"
msgstr "Режим щелчка"
-#: backends/platform/maemo/maemo.cpp:215
+#: backends/platform/maemo/maemo.cpp:214
#: backends/platform/symbian/src/SymbianActions.cpp:42
#: backends/platform/wince/CEActionsPocket.cpp:60
#: backends/platform/wince/CEActionsSmartphone.cpp:43
@@ -1617,11 +1659,11 @@ msgstr "Режим щелчка"
msgid "Left Click"
msgstr "Левый щелчок"
-#: backends/platform/maemo/maemo.cpp:218
+#: backends/platform/maemo/maemo.cpp:217
msgid "Middle Click"
msgstr "Средний щелчок"
-#: backends/platform/maemo/maemo.cpp:221
+#: 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
@@ -1658,19 +1700,19 @@ msgctxt "lowres"
msgid "Normal (no scaling)"
msgstr "Без увеличения"
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2148
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2197
msgid "Enabled aspect ratio correction"
msgstr "Коррекция соотношения сторон включена"
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2154
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2203
msgid "Disabled aspect ratio correction"
msgstr "Коррекция соотношения сторон выключена"
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2209
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2258
msgid "Active graphics filter:"
msgstr "Активный графический фильтр:"
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2251
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2300
msgid "Windowed mode"
msgstr "Оконный режим"
@@ -1729,8 +1771,8 @@ msgstr "Быстрый режим"
#: 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:82
-#: engines/scumm/help.cpp:84
+#: engines/scumm/dialogs.cpp:192 engines/scumm/help.cpp:83
+#: engines/scumm/help.cpp:85
msgid "Quit"
msgstr "Выход"
@@ -1750,7 +1792,7 @@ msgstr "Виртуальная клавиатура"
msgid "Key mapper"
msgstr "Назначение клавиш"
-#: backends/events/symbiansdl/symbiansdl-events.cpp:184
+#: backends/events/symbiansdl/symbiansdl-events.cpp:186
msgid "Do you want to quit ?"
msgstr "Вы действительно хотите выйти?"
@@ -2083,35 +2125,56 @@ msgstr "Щелчки включены"
msgid "Clicking Disabled"
msgstr "Щелчки выключены"
-#: engines/agi/detection.cpp:142 engines/drascula/detection.cpp:302
+#: 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.cpp:103
+#: engines/zvision/detection.cpp:246
msgid "Use original save/load screens"
msgstr "Использовать оригинальные экраны записи/чтения игры"
-#: engines/agi/detection.cpp:143 engines/drascula/detection.cpp:303
+#: 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/zvision/detection.cpp:104
+#: engines/zvision/detection.cpp:247
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 версии игры)"
+
+#: engines/agi/detection.cpp:158
+msgid ""
+"Use an alternative palette, common for all Amiga games. This was the old "
+"behavior"
+msgstr ""
+
+#: engines/agi/detection.cpp:167
+#, fuzzy
+msgid "Mouse support"
+msgstr "Поддержка пропусков"
+
+#: 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:857 engines/toltecs/menu.cpp:256
+#: engines/sci/engine/kfile.cpp:858 engines/toltecs/menu.cpp:256
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:857 engines/toltecs/menu.cpp:256
+#: engines/sci/engine/kfile.cpp:858 engines/toltecs/menu.cpp:256
msgid "Restore"
msgstr "Восстановить"
-#: engines/agos/saveload.cpp:160 engines/scumm/scumm.cpp:2368
+#: engines/agos/saveload.cpp:160 engines/scumm/scumm.cpp:2377
#, c-format
msgid ""
"Failed to load game state from file:\n"
@@ -2122,7 +2185,7 @@ msgstr ""
"\n"
"%s"
-#: engines/agos/saveload.cpp:195 engines/scumm/scumm.cpp:2361
+#: engines/agos/saveload.cpp:195 engines/scumm/scumm.cpp:2370
#, c-format
msgid ""
"Failed to save game state to file:\n"
@@ -2133,7 +2196,7 @@ msgstr ""
"\n"
"%s"
-#: engines/agos/saveload.cpp:203 engines/scumm/scumm.cpp:2379
+#: engines/agos/saveload.cpp:203 engines/scumm/scumm.cpp:2388
#, c-format
msgid ""
"Successfully saved game state in file:\n"
@@ -2149,12 +2212,12 @@ msgstr ""
msgid "Cutscene file '%s' not found!"
msgstr "Файл заставки '%s' не найден!"
-#: engines/cge/detection.cpp:105 engines/cge2/detection.cpp:81
+#: engines/cge/detection.cpp:105 engines/cge2/detection.cpp:101
#, fuzzy
msgid "Color Blind Mode"
msgstr "Режим щелчка"
-#: engines/cge/detection.cpp:106 engines/cge2/detection.cpp:82
+#: engines/cge/detection.cpp:106 engines/cge2/detection.cpp:102
msgid "Enable Color Blind Mode by default"
msgstr ""
@@ -2206,7 +2269,7 @@ msgstr "Режим ускоренного видео"
msgid "Play movies at an increased speed"
msgstr "Воспроизводит видеоролики с увеличенной скоростью"
-#: engines/groovie/script.cpp:399
+#: engines/groovie/script.cpp:408
msgid "Failed to save game"
msgstr "Не удалось сохранить игру"
@@ -2504,12 +2567,12 @@ msgid "Use an alternative game intro (CD version only)"
msgstr "Использовать альтернативное вступление (только для CD версии игры)"
#: engines/sci/detection.cpp:374
-msgid "EGA undithering"
-msgstr "EGA без растра"
+msgid "Skip EGA dithering pass (full color backgrounds)"
+msgstr ""
#: engines/sci/detection.cpp:375
-msgid "Enable undithering in EGA games"
-msgstr "Включает режим без растрирования в EGA играх"
+msgid "Skip dithering pass in EGA games, graphics are shown with full colors"
+msgstr ""
#: engines/sci/detection.cpp:384
msgid "Prefer digital sound effects"
@@ -2586,12 +2649,14 @@ msgstr "Игра остановлена. Нажмите пробел, чтобы продолжить."
#. "Moechten Sie wirklich neu starten? (J/N)J"
#. Will react to J as 'Yes'
#: engines/scumm/dialogs.cpp:183
-msgid "Are you sure you want to restart? (Y/N)"
+#, fuzzy
+msgid "Are you sure you want to restart? (Y/N)Y"
msgstr "Вы уверены, что хотите начать снова? (Y/N)"
#. I18N: you may specify 'Yes' symbol at the end of the line. See previous comment
#: engines/scumm/dialogs.cpp:185
-msgid "Are you sure you want to quit? (Y/N)"
+#, fuzzy
+msgid "Are you sure you want to quit? (Y/N)Y"
msgstr "Вы уверены, что хотите выйти? (Y/N)"
#: engines/scumm/dialogs.cpp:190
@@ -2679,516 +2744,541 @@ msgstr "Практикант"
msgid "Expert"
msgstr "Эксперт"
-#: engines/scumm/help.cpp:73
+#: engines/scumm/help.cpp:74
msgid "Common keyboard commands:"
msgstr "Общие клавиатурные команды:"
-#: engines/scumm/help.cpp:74
+#: engines/scumm/help.cpp:75
msgid "Save / Load dialog"
msgstr "Диалог записи / чтения"
-#: engines/scumm/help.cpp:76
+#: engines/scumm/help.cpp:77
msgid "Skip line of text"
msgstr "Пропустить строку"
-#: engines/scumm/help.cpp:77
+#: engines/scumm/help.cpp:78
msgid "Esc"
msgstr "Esc"
-#: engines/scumm/help.cpp:77
+#: engines/scumm/help.cpp:78
msgid "Skip cutscene"
msgstr "Пропустить заставку"
-#: engines/scumm/help.cpp:78
+#: engines/scumm/help.cpp:79
msgid "Space"
msgstr "Пробел"
-#: engines/scumm/help.cpp:78
+#: engines/scumm/help.cpp:79
msgid "Pause game"
msgstr "Пауза игры"
-#: engines/scumm/help.cpp:79 engines/scumm/help.cpp:84
-#: engines/scumm/help.cpp:95 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: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:79
+#: engines/scumm/help.cpp:80
msgid "Load game state 1-10"
msgstr "Загрузить игру 1-10"
-#: engines/scumm/help.cpp:80 engines/scumm/help.cpp:84
-#: engines/scumm/help.cpp:86 engines/scumm/help.cpp:100
-#: engines/scumm/help.cpp:101 engines/scumm/help.cpp:102
+#: 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:80
+#: engines/scumm/help.cpp:81
msgid "Save game state 1-10"
msgstr "Сохранить игру 1-10"
-#: engines/scumm/help.cpp:86 engines/scumm/help.cpp:89
+#: engines/scumm/help.cpp:87 engines/scumm/help.cpp:90
msgid "Enter"
msgstr "Ввод"
-#: engines/scumm/help.cpp:87
+#: engines/scumm/help.cpp:88
msgid "Music volume up / down"
msgstr "Громкость музыки увеличить / уменьшить"
-#: engines/scumm/help.cpp:88
+#: engines/scumm/help.cpp:89
msgid "Text speed slower / faster"
msgstr "Скорость текста быстрее / медленнее"
-#: engines/scumm/help.cpp:89
+#: engines/scumm/help.cpp:90
msgid "Simulate left mouse button"
msgstr "Эмуляция нажатия левой клавиши мыши"
-#: engines/scumm/help.cpp:90
+#: engines/scumm/help.cpp:91
msgid "Tab"
msgstr "Tab"
-#: engines/scumm/help.cpp:90
+#: engines/scumm/help.cpp:91
msgid "Simulate right mouse button"
msgstr "Эмуляция правой клавиши мыши"
-#: engines/scumm/help.cpp:93
+#: engines/scumm/help.cpp:94
msgid "Special keyboard commands:"
msgstr "Специальные клавиатурные команды:"
-#: engines/scumm/help.cpp:94
+#: engines/scumm/help.cpp:95
msgid "Show / Hide console"
msgstr "Показать / Убрать консоль"
-#: engines/scumm/help.cpp:95
+#: engines/scumm/help.cpp:96
msgid "Start the debugger"
msgstr "Запуск отладчика"
-#: engines/scumm/help.cpp:96
+#: engines/scumm/help.cpp:97
msgid "Show memory consumption"
msgstr "Показать потребление памяти"
-#: engines/scumm/help.cpp:97
+#: engines/scumm/help.cpp:98
msgid "Run in fast mode (*)"
msgstr "Запустить быстрый режим (*)"
-#: engines/scumm/help.cpp:98
+#: engines/scumm/help.cpp:99
msgid "Run in really fast mode (*)"
msgstr "Запустить очень быстрый режим (*)"
-#: engines/scumm/help.cpp:99
+#: engines/scumm/help.cpp:100
msgid "Toggle mouse capture"
msgstr "Переключение перехвата мыши"
-#: engines/scumm/help.cpp:100
+#: engines/scumm/help.cpp:101
msgid "Switch between graphics filters"
msgstr "Переключение между графическими фильтрами"
-#: engines/scumm/help.cpp:101
+#: engines/scumm/help.cpp:102
msgid "Increase / Decrease scale factor"
msgstr "Увеличить/уменьшить масштаб"
-#: engines/scumm/help.cpp:102
+#: engines/scumm/help.cpp:103
msgid "Toggle aspect-ratio correction"
msgstr "Переключение коррекции соотношения сторон"
-#: engines/scumm/help.cpp:107
+#: engines/scumm/help.cpp:108
msgid "* Note that using ctrl-f and"
msgstr "* Использование ctrl-f и"
-#: engines/scumm/help.cpp:108
+#: engines/scumm/help.cpp:109
msgid " ctrl-g are not recommended"
msgstr " ctrl-g не рекомендуется,"
-#: engines/scumm/help.cpp:109
+#: engines/scumm/help.cpp:110
msgid " since they may cause crashes"
msgstr " так как они могут привести к"
-#: engines/scumm/help.cpp:110
+#: engines/scumm/help.cpp:111
msgid " or incorrect game behavior."
msgstr " неверной работе игры."
-#: engines/scumm/help.cpp:114
+#: engines/scumm/help.cpp:115
msgid "Spinning drafts on the keyboard:"
msgstr "Изменяемые черновики на клавиатуре:"
-#: engines/scumm/help.cpp:116
+#: engines/scumm/help.cpp:117
msgid "Main game controls:"
msgstr "Основное управление игрой:"
-#: engines/scumm/help.cpp:121 engines/scumm/help.cpp:136
-#: engines/scumm/help.cpp:161
+#: engines/scumm/help.cpp:122 engines/scumm/help.cpp:137
+#: engines/scumm/help.cpp:162
msgid "Push"
msgstr "Толкать"
-#: engines/scumm/help.cpp:122 engines/scumm/help.cpp:137
-#: engines/scumm/help.cpp:162
+#: engines/scumm/help.cpp:123 engines/scumm/help.cpp:138
+#: engines/scumm/help.cpp:163
msgid "Pull"
msgstr "Тянуть"
-#: engines/scumm/help.cpp:123 engines/scumm/help.cpp:138
-#: engines/scumm/help.cpp:163 engines/scumm/help.cpp:197
-#: engines/scumm/help.cpp:207
+#: 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 "Дать"
-#: engines/scumm/help.cpp:124 engines/scumm/help.cpp:139
-#: engines/scumm/help.cpp:164 engines/scumm/help.cpp:190
-#: engines/scumm/help.cpp:208
+#: 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 "Открыть"
-#: engines/scumm/help.cpp:126
+#: engines/scumm/help.cpp:127
msgid "Go to"
msgstr "Идти"
-#: engines/scumm/help.cpp:127
+#: engines/scumm/help.cpp:128
msgid "Get"
msgstr "Взять"
-#: engines/scumm/help.cpp:128 engines/scumm/help.cpp:152
-#: engines/scumm/help.cpp:170 engines/scumm/help.cpp:198
-#: engines/scumm/help.cpp:213 engines/scumm/help.cpp:224
-#: engines/scumm/help.cpp:250
+#: 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 "Использовать"
-#: engines/scumm/help.cpp:129 engines/scumm/help.cpp:141
+#: engines/scumm/help.cpp:130 engines/scumm/help.cpp:142
msgid "Read"
msgstr "Читать"
-#: engines/scumm/help.cpp:130 engines/scumm/help.cpp:147
+#: engines/scumm/help.cpp:131 engines/scumm/help.cpp:148
msgid "New kid"
msgstr "Новый перс"
-#: engines/scumm/help.cpp:131 engines/scumm/help.cpp:153
-#: engines/scumm/help.cpp:171
+#: engines/scumm/help.cpp:132 engines/scumm/help.cpp:154
+#: engines/scumm/help.cpp:172
msgid "Turn on"
msgstr "Включить"
-#: engines/scumm/help.cpp:132 engines/scumm/help.cpp:154
-#: engines/scumm/help.cpp:172
+#: engines/scumm/help.cpp:133 engines/scumm/help.cpp:155
+#: engines/scumm/help.cpp:173
msgid "Turn off"
msgstr "Выключить"
-#: engines/scumm/help.cpp:142 engines/scumm/help.cpp:167
-#: engines/scumm/help.cpp:194
+#: engines/scumm/help.cpp:143 engines/scumm/help.cpp:168
+#: engines/scumm/help.cpp:195
msgid "Walk to"
msgstr "Идти к"
-#: engines/scumm/help.cpp:143 engines/scumm/help.cpp:168
-#: engines/scumm/help.cpp:195 engines/scumm/help.cpp:210
-#: engines/scumm/help.cpp:227
+#: 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 "Поднять"
-#: engines/scumm/help.cpp:144 engines/scumm/help.cpp:169
+#: engines/scumm/help.cpp:145 engines/scumm/help.cpp:170
msgid "What is"
msgstr "Что такое"
-#: engines/scumm/help.cpp:146
+#: engines/scumm/help.cpp:147
msgid "Unlock"
msgstr "Открыть"
-#: engines/scumm/help.cpp:149
+#: engines/scumm/help.cpp:150
msgid "Put on"
msgstr "Положить"
-#: engines/scumm/help.cpp:150
+#: engines/scumm/help.cpp:151
msgid "Take off"
msgstr "Поднять"
-#: engines/scumm/help.cpp:156
+#: engines/scumm/help.cpp:157
msgid "Fix"
msgstr "Исправить"
-#: engines/scumm/help.cpp:158
+#: engines/scumm/help.cpp:159
msgid "Switch"
msgstr "Переключить"
-#: engines/scumm/help.cpp:166 engines/scumm/help.cpp:228
+#: engines/scumm/help.cpp:167 engines/scumm/help.cpp:229
msgid "Look"
msgstr "Смотреть"
-#: engines/scumm/help.cpp:173 engines/scumm/help.cpp:223
+#: engines/scumm/help.cpp:174 engines/scumm/help.cpp:224
msgid "Talk"
msgstr "Говорить"
-#: engines/scumm/help.cpp:174
+#: engines/scumm/help.cpp:175
msgid "Travel"
msgstr "Путешествовать"
-#: engines/scumm/help.cpp:175
+#: engines/scumm/help.cpp:176
msgid "To Henry / To Indy"
msgstr "Генри/Инди"
#. I18N: These are different musical notes
-#: engines/scumm/help.cpp:179
+#: engines/scumm/help.cpp:180
msgid "play C minor on distaff"
msgstr "играть до минор на прялке"
-#: engines/scumm/help.cpp:180
+#: engines/scumm/help.cpp:181
msgid "play D on distaff"
msgstr "играть ре на прялке"
-#: engines/scumm/help.cpp:181
+#: engines/scumm/help.cpp:182
msgid "play E on distaff"
msgstr "играть ми на прялке"
-#: engines/scumm/help.cpp:182
+#: engines/scumm/help.cpp:183
msgid "play F on distaff"
msgstr "играть фа на прялке"
-#: engines/scumm/help.cpp:183
+#: engines/scumm/help.cpp:184
msgid "play G on distaff"
msgstr "играть соль на прялке"
-#: engines/scumm/help.cpp:184
+#: engines/scumm/help.cpp:185
msgid "play A on distaff"
msgstr "играть ля на прялке"
-#: engines/scumm/help.cpp:185
+#: engines/scumm/help.cpp:186
msgid "play B on distaff"
msgstr "играть си на прялке"
-#: engines/scumm/help.cpp:186
+#: engines/scumm/help.cpp:187
msgid "play C major on distaff"
msgstr "играть до мажор на прялке"
-#: engines/scumm/help.cpp:192 engines/scumm/help.cpp:214
+#: engines/scumm/help.cpp:193 engines/scumm/help.cpp:215
msgid "puSh"
msgstr "толкать"
-#: engines/scumm/help.cpp:193 engines/scumm/help.cpp:215
+#: engines/scumm/help.cpp:194 engines/scumm/help.cpp:216
msgid "pull (Yank)"
msgstr "тянуть (цеплять)"
-#: engines/scumm/help.cpp:196 engines/scumm/help.cpp:212
-#: engines/scumm/help.cpp:248
+#: engines/scumm/help.cpp:197 engines/scumm/help.cpp:213
+#: engines/scumm/help.cpp:249
msgid "Talk to"
msgstr "Говорить с"
-#: engines/scumm/help.cpp:199 engines/scumm/help.cpp:211
+#: engines/scumm/help.cpp:200 engines/scumm/help.cpp:212
msgid "Look at"
msgstr "Смотреть на"
-#: engines/scumm/help.cpp:200
+#: engines/scumm/help.cpp:201
msgid "turn oN"
msgstr "включить"
-#: engines/scumm/help.cpp:201
+#: engines/scumm/help.cpp:202
msgid "turn oFf"
msgstr "выключить"
-#: engines/scumm/help.cpp:217
+#: engines/scumm/help.cpp:218
msgid "KeyUp"
msgstr "Вверх"
-#: engines/scumm/help.cpp:217
+#: engines/scumm/help.cpp:218
msgid "Highlight prev dialogue"
msgstr "Подсветить предыдущий диалог"
-#: engines/scumm/help.cpp:218
+#: engines/scumm/help.cpp:219
msgid "KeyDown"
msgstr "Вниз"
-#: engines/scumm/help.cpp:218
+#: engines/scumm/help.cpp:219
msgid "Highlight next dialogue"
msgstr "Подсветить следующий диалог"
-#: engines/scumm/help.cpp:222
+#: engines/scumm/help.cpp:223
msgid "Walk"
msgstr "Идти"
-#: engines/scumm/help.cpp:225 engines/scumm/help.cpp:234
-#: engines/scumm/help.cpp:241 engines/scumm/help.cpp:249
+#: engines/scumm/help.cpp:226 engines/scumm/help.cpp:235
+#: engines/scumm/help.cpp:242 engines/scumm/help.cpp:250
msgid "Inventory"
msgstr "Инвентарь"
-#: engines/scumm/help.cpp:226
+#: engines/scumm/help.cpp:227
msgid "Object"
msgstr "Объект"
-#: engines/scumm/help.cpp:229
+#: engines/scumm/help.cpp:230
msgid "Black and White / Color"
msgstr "Черно-белый / Цветной"
-#: engines/scumm/help.cpp:232
+#: engines/scumm/help.cpp:233
msgid "Eyes"
msgstr "Глаза"
-#: engines/scumm/help.cpp:233
+#: engines/scumm/help.cpp:234
msgid "Tongue"
msgstr "Язык"
-#: engines/scumm/help.cpp:235
+#: engines/scumm/help.cpp:236
msgid "Punch"
msgstr "Удар"
-#: engines/scumm/help.cpp:236
+#: engines/scumm/help.cpp:237
msgid "Kick"
msgstr "Ногой"
-#: engines/scumm/help.cpp:239 engines/scumm/help.cpp:247
+#: engines/scumm/help.cpp:240 engines/scumm/help.cpp:248
msgid "Examine"
msgstr "Проверить"
-#: engines/scumm/help.cpp:240
+#: engines/scumm/help.cpp:241
msgid "Regular cursor"
msgstr "Обычный курсор"
#. I18N: Comm is a communication device
-#: engines/scumm/help.cpp:243
+#: engines/scumm/help.cpp:244
msgid "Comm"
msgstr "Комм"
-#: engines/scumm/help.cpp:246
+#: engines/scumm/help.cpp:247
msgid "Save / Load / Options"
msgstr "Загрузить / Сохранить / Настройки"
-#: engines/scumm/help.cpp:255
+#: engines/scumm/help.cpp:256
msgid "Other game controls:"
msgstr "Остальное управление игрой:"
-#: engines/scumm/help.cpp:257 engines/scumm/help.cpp:267
+#: engines/scumm/help.cpp:258 engines/scumm/help.cpp:268
msgid "Inventory:"
msgstr "Инвентарь:"
-#: engines/scumm/help.cpp:258 engines/scumm/help.cpp:274
+#: engines/scumm/help.cpp:259 engines/scumm/help.cpp:275
msgid "Scroll list up"
msgstr "Прокрутить список вверх"
-#: engines/scumm/help.cpp:259 engines/scumm/help.cpp:275
+#: engines/scumm/help.cpp:260 engines/scumm/help.cpp:276
msgid "Scroll list down"
msgstr "Прокрутить список вниз"
-#: engines/scumm/help.cpp:260 engines/scumm/help.cpp:268
+#: engines/scumm/help.cpp:261 engines/scumm/help.cpp:269
msgid "Upper left item"
msgstr "Верхний левый предмет"
-#: engines/scumm/help.cpp:261 engines/scumm/help.cpp:270
+#: engines/scumm/help.cpp:262 engines/scumm/help.cpp:271
msgid "Lower left item"
msgstr "Нижний левый предмет"
-#: engines/scumm/help.cpp:262 engines/scumm/help.cpp:271
+#: engines/scumm/help.cpp:263 engines/scumm/help.cpp:272
msgid "Upper right item"
msgstr "Верхний правый предмет"
-#: engines/scumm/help.cpp:263 engines/scumm/help.cpp:273
+#: engines/scumm/help.cpp:264 engines/scumm/help.cpp:274
msgid "Lower right item"
msgstr "Нижний правый предмет"
-#: engines/scumm/help.cpp:269
+#: engines/scumm/help.cpp:270
msgid "Middle left item"
msgstr "Средний левый предмет"
-#: engines/scumm/help.cpp:272
+#: engines/scumm/help.cpp:273
msgid "Middle right item"
msgstr "Средний правый предмет"
-#: engines/scumm/help.cpp:279 engines/scumm/help.cpp:284
+#: engines/scumm/help.cpp:280 engines/scumm/help.cpp:285
msgid "Switching characters:"
msgstr "Смена героя:"
-#: engines/scumm/help.cpp:281
+#: engines/scumm/help.cpp:282
msgid "Second kid"
msgstr "Второй герой"
-#: engines/scumm/help.cpp:282
+#: engines/scumm/help.cpp:283
msgid "Third kid"
msgstr "Третий герой"
-#: engines/scumm/help.cpp:294
+#: engines/scumm/help.cpp:292
+#, fuzzy
+msgid "Toggle Inventory/IQ Points display"
+msgstr "Включить показ данных в центре экрана"
+
+#: engines/scumm/help.cpp:293
+msgid "Toggle Keyboard/Mouse Fighting (*)"
+msgstr ""
+
+#: engines/scumm/help.cpp:295
+msgid "* Keyboard Fighting is always on,"
+msgstr ""
+
+#: engines/scumm/help.cpp:296
+msgid " so despite the in-game message this"
+msgstr ""
+
+#: engines/scumm/help.cpp:297
+msgid " actually toggles Mouse Fighting Off/On"
+msgstr ""
+
+#: engines/scumm/help.cpp:304
msgid "Fighting controls (numpad):"
msgstr "Управление боем (цифровые клавиши)"
-#: engines/scumm/help.cpp:295 engines/scumm/help.cpp:296
-#: engines/scumm/help.cpp:297
+#: engines/scumm/help.cpp:305 engines/scumm/help.cpp:306
+#: engines/scumm/help.cpp:307
msgid "Step back"
msgstr "Шаг назад"
-#: engines/scumm/help.cpp:298
+#: engines/scumm/help.cpp:308
msgid "Block high"
msgstr "Защита сверху"
-#: engines/scumm/help.cpp:299
+#: engines/scumm/help.cpp:309
msgid "Block middle"
msgstr "Защита посередине"
-#: engines/scumm/help.cpp:300
+#: engines/scumm/help.cpp:310
msgid "Block low"
msgstr "Защита снизу"
-#: engines/scumm/help.cpp:301
+#: engines/scumm/help.cpp:311
msgid "Punch high"
msgstr "Удар сверху"
-#: engines/scumm/help.cpp:302
+#: engines/scumm/help.cpp:312
msgid "Punch middle"
msgstr "Удар посередине"
-#: engines/scumm/help.cpp:303
+#: engines/scumm/help.cpp:313
msgid "Punch low"
msgstr "Удар снизу"
-#: engines/scumm/help.cpp:306
+#: engines/scumm/help.cpp:315
+msgid "Sucker punch"
+msgstr ""
+
+#: engines/scumm/help.cpp:318
msgid "These are for Indy on left."
msgstr "Это когда Инди слева."
-#: engines/scumm/help.cpp:307
+#: engines/scumm/help.cpp:319
msgid "When Indy is on the right,"
msgstr "Когда Инди справа,"
-#: engines/scumm/help.cpp:308
+#: engines/scumm/help.cpp:320
msgid "7, 4, and 1 are switched with"
msgstr "7, 4 и 1 меняются с"
-#: engines/scumm/help.cpp:309
+#: engines/scumm/help.cpp:321
msgid "9, 6, and 3, respectively."
msgstr "9, 6 и 3 соответственно."
-#: engines/scumm/help.cpp:316
+#: engines/scumm/help.cpp:328
msgid "Biplane controls (numpad):"
msgstr "Управление самолётом (цифровые клавиши)"
-#: engines/scumm/help.cpp:317
+#: engines/scumm/help.cpp:329
msgid "Fly to upper left"
msgstr "Лететь влево-вверх"
-#: engines/scumm/help.cpp:318
+#: engines/scumm/help.cpp:330
msgid "Fly to left"
msgstr "Лететь влево"
-#: engines/scumm/help.cpp:319
+#: engines/scumm/help.cpp:331
msgid "Fly to lower left"
msgstr "Лететь влево-вниз"
-#: engines/scumm/help.cpp:320
+#: engines/scumm/help.cpp:332
msgid "Fly upwards"
msgstr "Лететь вверх"
-#: engines/scumm/help.cpp:321
+#: engines/scumm/help.cpp:333
msgid "Fly straight"
msgstr "Лететь прямо"
-#: engines/scumm/help.cpp:322
+#: engines/scumm/help.cpp:334
msgid "Fly down"
msgstr "Лететь вниз"
-#: engines/scumm/help.cpp:323
+#: engines/scumm/help.cpp:335
msgid "Fly to upper right"
msgstr "Лететь вправо-вверх"
-#: engines/scumm/help.cpp:324
+#: engines/scumm/help.cpp:336
msgid "Fly to right"
msgstr "Лететь вправо"
-#: engines/scumm/help.cpp:325
+#: engines/scumm/help.cpp:337
msgid "Fly to lower right"
msgstr "Лететь вправо-вниз"
-#: engines/scumm/scumm.cpp:1823
+#: engines/scumm/scumm.cpp:1832
#, c-format
msgid ""
"Native MIDI support requires the Roland Upgrade from LucasArts,\n"
@@ -3197,11 +3287,12 @@ msgstr ""
"Режим \"родного\" MIDI требует обновление Roland Upgrade от\n"
"LucasArts, но не хватает %s. Переключаюсь на AdLib."
-#: engines/scumm/scumm.cpp:2594
+#: engines/scumm/scumm.cpp:2644
+#, fuzzy
msgid ""
-"Usually, Maniac Mansion would start now. But ScummVM doesn't do that yet. To "
-"play it, go to 'Add Game' in the ScummVM start menu and select the 'Maniac' "
-"directory inside the Tentacle game directory."
+"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, а затем "
@@ -3339,6 +3430,48 @@ msgstr ""
msgid "Show the current number of frames per second in the upper left corner"
msgstr ""
+#: engines/zvision/detection.cpp:256
+msgid "Double FPS"
+msgstr ""
+
+#: engines/zvision/detection.cpp:257
+msgid "Increase game FPS from 30 to 60"
+msgstr ""
+
+#: engines/zvision/detection.cpp:266
+#, fuzzy
+msgid "Enable Venus"
+msgstr "Включить режим гелия"
+
+#: engines/zvision/detection.cpp:267
+msgid "Enable the Venus help system"
+msgstr ""
+
+#: engines/zvision/detection.cpp:276
+msgid "Disable animation while turning"
+msgstr ""
+
+#: engines/zvision/detection.cpp:277
+msgid "Disable animation while turning in panoramic mode"
+msgstr ""
+
+#: engines/zvision/detection.cpp:286
+msgid "Use the hires MPEG movies"
+msgstr ""
+
+#: engines/zvision/detection.cpp:287
+#, fuzzy
+msgid ""
+"Use the hires MPEG movies of the DVD version, instead of the lowres AVI ones"
+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 был собран без поддержки "
@@ -3348,9 +3481,6 @@ msgstr ""
#~ msgid "Mass Add..."
#~ msgstr "Много игр..."
-#~ msgid "Mass Add..."
-#~ msgstr "Много игр..."
-
#~ msgid ""
#~ "Turns off General MIDI mapping for games with Roland MT-32 soundtrack"
#~ msgstr ""
diff --git a/po/scummvm.pot b/po/scummvm.pot
index 3c780ac0bd..49689e914b 100644
--- a/po/scummvm.pot
+++ b/po/scummvm.pot
@@ -1,5 +1,5 @@
# LANGUAGE translation for ScummVM.
-# Copyright (C) YEAR The ScummVM Team
+# Copyright (C) YEAR ScummVM Team
# This file is distributed under the same license as the ScummVM package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
@@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: ScummVM 1.8.0git\n"
"Report-Msgid-Bugs-To: scummvm-devel@lists.sf.net\n"
-"POT-Creation-Date: 2014-10-04 00:58+0100\n"
+"POT-Creation-Date: 2015-06-30 20:57+0100\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
@@ -53,10 +53,11 @@ msgstr ""
#: gui/browser.cpp:75 gui/chooser.cpp:46 gui/KeysDialog.cpp:43
#: gui/launcher.cpp:351 gui/massadd.cpp:95 gui/options.cpp:1239
+#: gui/recorderdialog.cpp:70 gui/recorderdialog.cpp:156
#: gui/saveload-dialog.cpp:216 gui/saveload-dialog.cpp:276
-#: gui/saveload-dialog.cpp:547 gui/saveload-dialog.cpp:922
+#: gui/saveload-dialog.cpp:547 gui/saveload-dialog.cpp:931
#: gui/themebrowser.cpp:55 gui/fluidsynth-dialog.cpp:152
-#: engines/engine.cpp:452 backends/platform/wii/options.cpp:48
+#: engines/engine.cpp:483 backends/platform/wii/options.cpp:48
#: backends/events/default/default-events.cpp:196
#: backends/events/default/default-events.cpp:218
#: engines/drascula/saveload.cpp:49 engines/parallaction/saveload.cpp:274
@@ -69,9 +70,9 @@ msgid "Choose"
msgstr ""
#: gui/gui-manager.cpp:117 backends/keymapper/remap-dialog.cpp:53
-#: 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
+#: 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 ""
@@ -87,7 +88,7 @@ msgstr ""
msgid "Remap keys"
msgstr ""
-#: gui/gui-manager.cpp:131 base/main.cpp:326 engines/scumm/help.cpp:86
+#: gui/gui-manager.cpp:131 base/main.cpp:326 engines/scumm/help.cpp:87
msgid "Toggle fullscreen"
msgstr ""
@@ -101,13 +102,13 @@ msgstr ""
#: gui/KeysDialog.cpp:42 gui/launcher.cpp:352 gui/launcher.cpp:1048
#: gui/launcher.cpp:1052 gui/massadd.cpp:92 gui/options.cpp:1240
-#: gui/saveload-dialog.cpp:923 gui/fluidsynth-dialog.cpp:153
-#: engines/engine.cpp:371 engines/engine.cpp:382
+#: 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:399 engines/parallaction/saveload.cpp:274
-#: engines/scumm/dialogs.cpp:193 engines/scumm/scumm.cpp:1825
+#: 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
@@ -471,7 +472,7 @@ msgstr ""
#: gui/launcher.cpp:793 gui/launcher.cpp:941 gui/launcher.cpp:1000
#: gui/fluidsynth-dialog.cpp:217
-#: backends/events/symbiansdl/symbiansdl-events.cpp:184
+#: 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
@@ -481,7 +482,7 @@ msgstr ""
#: gui/launcher.cpp:793 gui/launcher.cpp:941 gui/launcher.cpp:1000
#: gui/fluidsynth-dialog.cpp:217
-#: backends/events/symbiansdl/symbiansdl-events.cpp:184
+#: 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
@@ -517,6 +518,14 @@ msgstr ""
msgid "ScummVM could not find any engine capable of running the selected game!"
msgstr ""
+#: gui/launcher.cpp:1159
+msgid "Mass Add..."
+msgstr ""
+
+#: gui/launcher.cpp:1161
+msgid "Record..."
+msgstr ""
+
#: gui/massadd.cpp:79 gui/massadd.cpp:82
msgid "... progress ..."
msgstr ""
@@ -615,7 +624,7 @@ msgid "Special dithering modes supported by some games"
msgstr ""
#: gui/options.cpp:760
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2249
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2298
msgid "Fullscreen mode"
msgstr ""
@@ -921,6 +930,41 @@ msgid ""
"to use this theme you need to switch to another language first."
msgstr ""
+#: gui/recorderdialog.cpp:64
+msgid "Recorder or Playback Gameplay"
+msgstr ""
+
+#: gui/recorderdialog.cpp:69 gui/recorderdialog.cpp:156
+#: gui/saveload-dialog.cpp:220 gui/saveload-dialog.cpp:276
+msgid "Delete"
+msgstr ""
+
+#: gui/recorderdialog.cpp:71
+msgid "Record"
+msgstr ""
+
+#: gui/recorderdialog.cpp:72
+msgid "Playback"
+msgstr ""
+
+#: gui/recorderdialog.cpp:74
+msgid "Edit"
+msgstr ""
+
+#: gui/recorderdialog.cpp:86 gui/recorderdialog.cpp:243
+#: gui/recorderdialog.cpp:253
+msgid "Author: "
+msgstr ""
+
+#: gui/recorderdialog.cpp:87 gui/recorderdialog.cpp:244
+#: gui/recorderdialog.cpp:254
+msgid "Notes: "
+msgstr ""
+
+#: gui/recorderdialog.cpp:155
+msgid "Do you really want to delete this record?"
+msgstr ""
+
#: gui/saveload-dialog.cpp:167
msgid "List view"
msgstr ""
@@ -941,23 +985,19 @@ msgstr ""
msgid "No playtime saved"
msgstr ""
-#: gui/saveload-dialog.cpp:220 gui/saveload-dialog.cpp:276
-msgid "Delete"
-msgstr ""
-
#: gui/saveload-dialog.cpp:275
msgid "Do you really want to delete this saved game?"
msgstr ""
-#: gui/saveload-dialog.cpp:385 gui/saveload-dialog.cpp:875
+#: gui/saveload-dialog.cpp:385 gui/saveload-dialog.cpp:884
msgid "Date: "
msgstr ""
-#: gui/saveload-dialog.cpp:389 gui/saveload-dialog.cpp:881
+#: gui/saveload-dialog.cpp:389 gui/saveload-dialog.cpp:890
msgid "Time: "
msgstr ""
-#: gui/saveload-dialog.cpp:395 gui/saveload-dialog.cpp:889
+#: gui/saveload-dialog.cpp:395 gui/saveload-dialog.cpp:898
msgid "Playtime: "
msgstr ""
@@ -973,19 +1013,19 @@ msgstr ""
msgid "Prev"
msgstr ""
-#: gui/saveload-dialog.cpp:739
+#: gui/saveload-dialog.cpp:748
msgid "New Save"
msgstr ""
-#: gui/saveload-dialog.cpp:739
+#: gui/saveload-dialog.cpp:748
msgid "Create a new save game"
msgstr ""
-#: gui/saveload-dialog.cpp:868
+#: gui/saveload-dialog.cpp:877
msgid "Name: "
msgstr ""
-#: gui/saveload-dialog.cpp:940
+#: gui/saveload-dialog.cpp:949
#, c-format
msgid "Enter a description for slot %d:"
msgstr ""
@@ -1136,7 +1176,7 @@ msgstr ""
msgid "Error running game:"
msgstr ""
-#: base/main.cpp:536
+#: base/main.cpp:554
msgid "Could not find any engine capable of running the selected game"
msgstr ""
@@ -1253,7 +1293,7 @@ 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:758
+#: engines/pegasus/pegasus.cpp:377 engines/sci/engine/kfile.cpp:759
#: engines/toltecs/menu.cpp:281 engines/tsage/scenes.cpp:598
msgid "Save game:"
msgstr ""
@@ -1266,7 +1306,7 @@ msgstr ""
#: 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:758 engines/scumm/dialogs.cpp:188
+#: engines/sci/engine/kfile.cpp:759 engines/scumm/dialogs.cpp:188
#: engines/toltecs/menu.cpp:281 engines/tsage/scenes.cpp:598
msgid "Save"
msgstr ""
@@ -1299,23 +1339,23 @@ msgstr ""
msgid "~K~eys"
msgstr ""
-#: engines/engine.cpp:245
+#: engines/engine.cpp:276
msgid "Could not initialize color format."
msgstr ""
-#: engines/engine.cpp:253
+#: engines/engine.cpp:284
msgid "Could not switch to video mode: '"
msgstr ""
-#: engines/engine.cpp:262
+#: engines/engine.cpp:293
msgid "Could not apply aspect ratio setting."
msgstr ""
-#: engines/engine.cpp:267
+#: engines/engine.cpp:298
msgid "Could not apply fullscreen setting."
msgstr ""
-#: engines/engine.cpp:367
+#: engines/engine.cpp:398
msgid ""
"You appear to be playing this game directly\n"
"from the CD. This is known to cause problems,\n"
@@ -1324,7 +1364,7 @@ msgid ""
"See the README file for details."
msgstr ""
-#: engines/engine.cpp:378
+#: engines/engine.cpp:409
msgid ""
"This game has audio tracks in its disk. These\n"
"tracks need to be ripped from the disk using\n"
@@ -1333,21 +1373,21 @@ msgid ""
"See the README file for details."
msgstr ""
-#: engines/engine.cpp:436
+#: engines/engine.cpp:467
#, 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:449
+#: engines/engine.cpp:480
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:452
+#: engines/engine.cpp:483
msgid "Start anyway"
msgstr ""
@@ -1549,11 +1589,11 @@ msgstr ""
msgid "Touchpad mode disabled."
msgstr ""
-#: backends/platform/maemo/maemo.cpp:209
+#: backends/platform/maemo/maemo.cpp:208
msgid "Click Mode"
msgstr ""
-#: backends/platform/maemo/maemo.cpp:215
+#: backends/platform/maemo/maemo.cpp:214
#: backends/platform/symbian/src/SymbianActions.cpp:42
#: backends/platform/wince/CEActionsPocket.cpp:60
#: backends/platform/wince/CEActionsSmartphone.cpp:43
@@ -1561,11 +1601,11 @@ msgstr ""
msgid "Left Click"
msgstr ""
-#: backends/platform/maemo/maemo.cpp:218
+#: backends/platform/maemo/maemo.cpp:217
msgid "Middle Click"
msgstr ""
-#: backends/platform/maemo/maemo.cpp:221
+#: 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
@@ -1602,19 +1642,19 @@ msgctxt "lowres"
msgid "Normal (no scaling)"
msgstr ""
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2148
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2197
msgid "Enabled aspect ratio correction"
msgstr ""
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2154
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2203
msgid "Disabled aspect ratio correction"
msgstr ""
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2209
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2258
msgid "Active graphics filter:"
msgstr ""
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2251
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2300
msgid "Windowed mode"
msgstr ""
@@ -1673,8 +1713,8 @@ msgstr ""
#: 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:82
-#: engines/scumm/help.cpp:84
+#: engines/scumm/dialogs.cpp:192 engines/scumm/help.cpp:83
+#: engines/scumm/help.cpp:85
msgid "Quit"
msgstr ""
@@ -1694,7 +1734,7 @@ msgstr ""
msgid "Key mapper"
msgstr ""
-#: backends/events/symbiansdl/symbiansdl-events.cpp:184
+#: backends/events/symbiansdl/symbiansdl-events.cpp:186
msgid "Do you want to quit ?"
msgstr ""
@@ -2025,33 +2065,52 @@ msgstr ""
msgid "Clicking Disabled"
msgstr ""
-#: engines/agi/detection.cpp:142 engines/drascula/detection.cpp:302
+#: 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.cpp:103
+#: engines/zvision/detection.cpp:246
msgid "Use original save/load screens"
msgstr ""
-#: engines/agi/detection.cpp:143 engines/drascula/detection.cpp:303
+#: 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/zvision/detection.cpp:104
+#: engines/zvision/detection.cpp:247
msgid "Use the original save/load screens, instead of the ScummVM ones"
msgstr ""
+#: engines/agi/detection.cpp:157
+msgid "Use an alternative palette"
+msgstr ""
+
+#: engines/agi/detection.cpp:158
+msgid ""
+"Use an alternative palette, common for all Amiga games. This was the old "
+"behavior"
+msgstr ""
+
+#: engines/agi/detection.cpp:167
+msgid "Mouse support"
+msgstr ""
+
+#: 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:857 engines/toltecs/menu.cpp:256
+#: engines/sci/engine/kfile.cpp:858 engines/toltecs/menu.cpp:256
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:857 engines/toltecs/menu.cpp:256
+#: engines/sci/engine/kfile.cpp:858 engines/toltecs/menu.cpp:256
msgid "Restore"
msgstr ""
-#: engines/agos/saveload.cpp:160 engines/scumm/scumm.cpp:2368
+#: engines/agos/saveload.cpp:160 engines/scumm/scumm.cpp:2377
#, c-format
msgid ""
"Failed to load game state from file:\n"
@@ -2059,7 +2118,7 @@ msgid ""
"%s"
msgstr ""
-#: engines/agos/saveload.cpp:195 engines/scumm/scumm.cpp:2361
+#: engines/agos/saveload.cpp:195 engines/scumm/scumm.cpp:2370
#, c-format
msgid ""
"Failed to save game state to file:\n"
@@ -2067,7 +2126,7 @@ msgid ""
"%s"
msgstr ""
-#: engines/agos/saveload.cpp:203 engines/scumm/scumm.cpp:2379
+#: engines/agos/saveload.cpp:203 engines/scumm/scumm.cpp:2388
#, c-format
msgid ""
"Successfully saved game state in file:\n"
@@ -2080,11 +2139,11 @@ msgstr ""
msgid "Cutscene file '%s' not found!"
msgstr ""
-#: engines/cge/detection.cpp:105 engines/cge2/detection.cpp:81
+#: engines/cge/detection.cpp:105 engines/cge2/detection.cpp:101
msgid "Color Blind Mode"
msgstr ""
-#: engines/cge/detection.cpp:106 engines/cge2/detection.cpp:82
+#: engines/cge/detection.cpp:106 engines/cge2/detection.cpp:102
msgid "Enable Color Blind Mode by default"
msgstr ""
@@ -2129,7 +2188,7 @@ msgstr ""
msgid "Play movies at an increased speed"
msgstr ""
-#: engines/groovie/script.cpp:399
+#: engines/groovie/script.cpp:408
msgid "Failed to save game"
msgstr ""
@@ -2409,11 +2468,11 @@ msgid "Use an alternative game intro (CD version only)"
msgstr ""
#: engines/sci/detection.cpp:374
-msgid "EGA undithering"
+msgid "Skip EGA dithering pass (full color backgrounds)"
msgstr ""
#: engines/sci/detection.cpp:375
-msgid "Enable undithering in EGA games"
+msgid "Skip dithering pass in EGA games, graphics are shown with full colors"
msgstr ""
#: engines/sci/detection.cpp:384
@@ -2483,12 +2542,12 @@ msgstr ""
#. "Moechten Sie wirklich neu starten? (J/N)J"
#. Will react to J as 'Yes'
#: engines/scumm/dialogs.cpp:183
-msgid "Are you sure you want to restart? (Y/N)"
+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
-msgid "Are you sure you want to quit? (Y/N)"
+msgid "Are you sure you want to quit? (Y/N)Y"
msgstr ""
#: engines/scumm/dialogs.cpp:190
@@ -2576,527 +2635,551 @@ msgstr ""
msgid "Expert"
msgstr ""
-#: engines/scumm/help.cpp:73
+#: engines/scumm/help.cpp:74
msgid "Common keyboard commands:"
msgstr ""
-#: engines/scumm/help.cpp:74
+#: engines/scumm/help.cpp:75
msgid "Save / Load dialog"
msgstr ""
-#: engines/scumm/help.cpp:76
+#: engines/scumm/help.cpp:77
msgid "Skip line of text"
msgstr ""
-#: engines/scumm/help.cpp:77
+#: engines/scumm/help.cpp:78
msgid "Esc"
msgstr ""
-#: engines/scumm/help.cpp:77
+#: engines/scumm/help.cpp:78
msgid "Skip cutscene"
msgstr ""
-#: engines/scumm/help.cpp:78
+#: engines/scumm/help.cpp:79
msgid "Space"
msgstr ""
-#: engines/scumm/help.cpp:78
+#: engines/scumm/help.cpp:79
msgid "Pause game"
msgstr ""
-#: engines/scumm/help.cpp:79 engines/scumm/help.cpp:84
-#: engines/scumm/help.cpp:95 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: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 ""
-#: engines/scumm/help.cpp:79
+#: engines/scumm/help.cpp:80
msgid "Load game state 1-10"
msgstr ""
-#: engines/scumm/help.cpp:80 engines/scumm/help.cpp:84
-#: engines/scumm/help.cpp:86 engines/scumm/help.cpp:100
-#: engines/scumm/help.cpp:101 engines/scumm/help.cpp:102
+#: 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 ""
-#: engines/scumm/help.cpp:80
+#: engines/scumm/help.cpp:81
msgid "Save game state 1-10"
msgstr ""
-#: engines/scumm/help.cpp:86 engines/scumm/help.cpp:89
+#: engines/scumm/help.cpp:87 engines/scumm/help.cpp:90
msgid "Enter"
msgstr ""
-#: engines/scumm/help.cpp:87
+#: engines/scumm/help.cpp:88
msgid "Music volume up / down"
msgstr ""
-#: engines/scumm/help.cpp:88
+#: engines/scumm/help.cpp:89
msgid "Text speed slower / faster"
msgstr ""
-#: engines/scumm/help.cpp:89
+#: engines/scumm/help.cpp:90
msgid "Simulate left mouse button"
msgstr ""
-#: engines/scumm/help.cpp:90
+#: engines/scumm/help.cpp:91
msgid "Tab"
msgstr ""
-#: engines/scumm/help.cpp:90
+#: engines/scumm/help.cpp:91
msgid "Simulate right mouse button"
msgstr ""
-#: engines/scumm/help.cpp:93
+#: engines/scumm/help.cpp:94
msgid "Special keyboard commands:"
msgstr ""
-#: engines/scumm/help.cpp:94
+#: engines/scumm/help.cpp:95
msgid "Show / Hide console"
msgstr ""
-#: engines/scumm/help.cpp:95
+#: engines/scumm/help.cpp:96
msgid "Start the debugger"
msgstr ""
-#: engines/scumm/help.cpp:96
+#: engines/scumm/help.cpp:97
msgid "Show memory consumption"
msgstr ""
-#: engines/scumm/help.cpp:97
+#: engines/scumm/help.cpp:98
msgid "Run in fast mode (*)"
msgstr ""
-#: engines/scumm/help.cpp:98
+#: engines/scumm/help.cpp:99
msgid "Run in really fast mode (*)"
msgstr ""
-#: engines/scumm/help.cpp:99
+#: engines/scumm/help.cpp:100
msgid "Toggle mouse capture"
msgstr ""
-#: engines/scumm/help.cpp:100
+#: engines/scumm/help.cpp:101
msgid "Switch between graphics filters"
msgstr ""
-#: engines/scumm/help.cpp:101
+#: engines/scumm/help.cpp:102
msgid "Increase / Decrease scale factor"
msgstr ""
-#: engines/scumm/help.cpp:102
+#: engines/scumm/help.cpp:103
msgid "Toggle aspect-ratio correction"
msgstr ""
-#: engines/scumm/help.cpp:107
+#: engines/scumm/help.cpp:108
msgid "* Note that using ctrl-f and"
msgstr ""
-#: engines/scumm/help.cpp:108
+#: engines/scumm/help.cpp:109
msgid " ctrl-g are not recommended"
msgstr ""
-#: engines/scumm/help.cpp:109
+#: engines/scumm/help.cpp:110
msgid " since they may cause crashes"
msgstr ""
-#: engines/scumm/help.cpp:110
+#: engines/scumm/help.cpp:111
msgid " or incorrect game behavior."
msgstr ""
-#: engines/scumm/help.cpp:114
+#: engines/scumm/help.cpp:115
msgid "Spinning drafts on the keyboard:"
msgstr ""
-#: engines/scumm/help.cpp:116
+#: engines/scumm/help.cpp:117
msgid "Main game controls:"
msgstr ""
-#: engines/scumm/help.cpp:121 engines/scumm/help.cpp:136
-#: engines/scumm/help.cpp:161
-msgid "Push"
-msgstr ""
-
#: engines/scumm/help.cpp:122 engines/scumm/help.cpp:137
#: engines/scumm/help.cpp:162
-msgid "Pull"
+msgid "Push"
msgstr ""
#: engines/scumm/help.cpp:123 engines/scumm/help.cpp:138
-#: engines/scumm/help.cpp:163 engines/scumm/help.cpp:197
-#: engines/scumm/help.cpp:207
-msgid "Give"
+#: engines/scumm/help.cpp:163
+msgid "Pull"
msgstr ""
#: engines/scumm/help.cpp:124 engines/scumm/help.cpp:139
-#: engines/scumm/help.cpp:164 engines/scumm/help.cpp:190
+#: engines/scumm/help.cpp:164 engines/scumm/help.cpp:198
#: engines/scumm/help.cpp:208
+msgid "Give"
+msgstr ""
+
+#: 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 ""
-#: engines/scumm/help.cpp:126
+#: engines/scumm/help.cpp:127
msgid "Go to"
msgstr ""
-#: engines/scumm/help.cpp:127
+#: engines/scumm/help.cpp:128
msgid "Get"
msgstr ""
-#: engines/scumm/help.cpp:128 engines/scumm/help.cpp:152
-#: engines/scumm/help.cpp:170 engines/scumm/help.cpp:198
-#: engines/scumm/help.cpp:213 engines/scumm/help.cpp:224
-#: engines/scumm/help.cpp:250
+#: 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 ""
-#: engines/scumm/help.cpp:129 engines/scumm/help.cpp:141
+#: engines/scumm/help.cpp:130 engines/scumm/help.cpp:142
msgid "Read"
msgstr ""
-#: engines/scumm/help.cpp:130 engines/scumm/help.cpp:147
+#: engines/scumm/help.cpp:131 engines/scumm/help.cpp:148
msgid "New kid"
msgstr ""
-#: engines/scumm/help.cpp:131 engines/scumm/help.cpp:153
-#: engines/scumm/help.cpp:171
+#: engines/scumm/help.cpp:132 engines/scumm/help.cpp:154
+#: engines/scumm/help.cpp:172
msgid "Turn on"
msgstr ""
-#: engines/scumm/help.cpp:132 engines/scumm/help.cpp:154
-#: engines/scumm/help.cpp:172
+#: engines/scumm/help.cpp:133 engines/scumm/help.cpp:155
+#: engines/scumm/help.cpp:173
msgid "Turn off"
msgstr ""
-#: engines/scumm/help.cpp:142 engines/scumm/help.cpp:167
-#: engines/scumm/help.cpp:194
+#: engines/scumm/help.cpp:143 engines/scumm/help.cpp:168
+#: engines/scumm/help.cpp:195
msgid "Walk to"
msgstr ""
-#: engines/scumm/help.cpp:143 engines/scumm/help.cpp:168
-#: engines/scumm/help.cpp:195 engines/scumm/help.cpp:210
-#: engines/scumm/help.cpp:227
+#: 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 ""
-#: engines/scumm/help.cpp:144 engines/scumm/help.cpp:169
+#: engines/scumm/help.cpp:145 engines/scumm/help.cpp:170
msgid "What is"
msgstr ""
-#: engines/scumm/help.cpp:146
+#: engines/scumm/help.cpp:147
msgid "Unlock"
msgstr ""
-#: engines/scumm/help.cpp:149
+#: engines/scumm/help.cpp:150
msgid "Put on"
msgstr ""
-#: engines/scumm/help.cpp:150
+#: engines/scumm/help.cpp:151
msgid "Take off"
msgstr ""
-#: engines/scumm/help.cpp:156
+#: engines/scumm/help.cpp:157
msgid "Fix"
msgstr ""
-#: engines/scumm/help.cpp:158
+#: engines/scumm/help.cpp:159
msgid "Switch"
msgstr ""
-#: engines/scumm/help.cpp:166 engines/scumm/help.cpp:228
+#: engines/scumm/help.cpp:167 engines/scumm/help.cpp:229
msgid "Look"
msgstr ""
-#: engines/scumm/help.cpp:173 engines/scumm/help.cpp:223
+#: engines/scumm/help.cpp:174 engines/scumm/help.cpp:224
msgid "Talk"
msgstr ""
-#: engines/scumm/help.cpp:174
+#: engines/scumm/help.cpp:175
msgid "Travel"
msgstr ""
-#: engines/scumm/help.cpp:175
+#: engines/scumm/help.cpp:176
msgid "To Henry / To Indy"
msgstr ""
#. I18N: These are different musical notes
-#: engines/scumm/help.cpp:179
+#: engines/scumm/help.cpp:180
msgid "play C minor on distaff"
msgstr ""
-#: engines/scumm/help.cpp:180
+#: engines/scumm/help.cpp:181
msgid "play D on distaff"
msgstr ""
-#: engines/scumm/help.cpp:181
+#: engines/scumm/help.cpp:182
msgid "play E on distaff"
msgstr ""
-#: engines/scumm/help.cpp:182
+#: engines/scumm/help.cpp:183
msgid "play F on distaff"
msgstr ""
-#: engines/scumm/help.cpp:183
+#: engines/scumm/help.cpp:184
msgid "play G on distaff"
msgstr ""
-#: engines/scumm/help.cpp:184
+#: engines/scumm/help.cpp:185
msgid "play A on distaff"
msgstr ""
-#: engines/scumm/help.cpp:185
+#: engines/scumm/help.cpp:186
msgid "play B on distaff"
msgstr ""
-#: engines/scumm/help.cpp:186
+#: engines/scumm/help.cpp:187
msgid "play C major on distaff"
msgstr ""
-#: engines/scumm/help.cpp:192 engines/scumm/help.cpp:214
+#: engines/scumm/help.cpp:193 engines/scumm/help.cpp:215
msgid "puSh"
msgstr ""
-#: engines/scumm/help.cpp:193 engines/scumm/help.cpp:215
+#: engines/scumm/help.cpp:194 engines/scumm/help.cpp:216
msgid "pull (Yank)"
msgstr ""
-#: engines/scumm/help.cpp:196 engines/scumm/help.cpp:212
-#: engines/scumm/help.cpp:248
+#: engines/scumm/help.cpp:197 engines/scumm/help.cpp:213
+#: engines/scumm/help.cpp:249
msgid "Talk to"
msgstr ""
-#: engines/scumm/help.cpp:199 engines/scumm/help.cpp:211
+#: engines/scumm/help.cpp:200 engines/scumm/help.cpp:212
msgid "Look at"
msgstr ""
-#: engines/scumm/help.cpp:200
+#: engines/scumm/help.cpp:201
msgid "turn oN"
msgstr ""
-#: engines/scumm/help.cpp:201
+#: engines/scumm/help.cpp:202
msgid "turn oFf"
msgstr ""
-#: engines/scumm/help.cpp:217
+#: engines/scumm/help.cpp:218
msgid "KeyUp"
msgstr ""
-#: engines/scumm/help.cpp:217
+#: engines/scumm/help.cpp:218
msgid "Highlight prev dialogue"
msgstr ""
-#: engines/scumm/help.cpp:218
+#: engines/scumm/help.cpp:219
msgid "KeyDown"
msgstr ""
-#: engines/scumm/help.cpp:218
+#: engines/scumm/help.cpp:219
msgid "Highlight next dialogue"
msgstr ""
-#: engines/scumm/help.cpp:222
+#: engines/scumm/help.cpp:223
msgid "Walk"
msgstr ""
-#: engines/scumm/help.cpp:225 engines/scumm/help.cpp:234
-#: engines/scumm/help.cpp:241 engines/scumm/help.cpp:249
+#: engines/scumm/help.cpp:226 engines/scumm/help.cpp:235
+#: engines/scumm/help.cpp:242 engines/scumm/help.cpp:250
msgid "Inventory"
msgstr ""
-#: engines/scumm/help.cpp:226
+#: engines/scumm/help.cpp:227
msgid "Object"
msgstr ""
-#: engines/scumm/help.cpp:229
+#: engines/scumm/help.cpp:230
msgid "Black and White / Color"
msgstr ""
-#: engines/scumm/help.cpp:232
+#: engines/scumm/help.cpp:233
msgid "Eyes"
msgstr ""
-#: engines/scumm/help.cpp:233
+#: engines/scumm/help.cpp:234
msgid "Tongue"
msgstr ""
-#: engines/scumm/help.cpp:235
+#: engines/scumm/help.cpp:236
msgid "Punch"
msgstr ""
-#: engines/scumm/help.cpp:236
+#: engines/scumm/help.cpp:237
msgid "Kick"
msgstr ""
-#: engines/scumm/help.cpp:239 engines/scumm/help.cpp:247
+#: engines/scumm/help.cpp:240 engines/scumm/help.cpp:248
msgid "Examine"
msgstr ""
-#: engines/scumm/help.cpp:240
+#: engines/scumm/help.cpp:241
msgid "Regular cursor"
msgstr ""
#. I18N: Comm is a communication device
-#: engines/scumm/help.cpp:243
+#: engines/scumm/help.cpp:244
msgid "Comm"
msgstr ""
-#: engines/scumm/help.cpp:246
+#: engines/scumm/help.cpp:247
msgid "Save / Load / Options"
msgstr ""
-#: engines/scumm/help.cpp:255
+#: engines/scumm/help.cpp:256
msgid "Other game controls:"
msgstr ""
-#: engines/scumm/help.cpp:257 engines/scumm/help.cpp:267
+#: engines/scumm/help.cpp:258 engines/scumm/help.cpp:268
msgid "Inventory:"
msgstr ""
-#: engines/scumm/help.cpp:258 engines/scumm/help.cpp:274
+#: engines/scumm/help.cpp:259 engines/scumm/help.cpp:275
msgid "Scroll list up"
msgstr ""
-#: engines/scumm/help.cpp:259 engines/scumm/help.cpp:275
+#: engines/scumm/help.cpp:260 engines/scumm/help.cpp:276
msgid "Scroll list down"
msgstr ""
-#: engines/scumm/help.cpp:260 engines/scumm/help.cpp:268
+#: engines/scumm/help.cpp:261 engines/scumm/help.cpp:269
msgid "Upper left item"
msgstr ""
-#: engines/scumm/help.cpp:261 engines/scumm/help.cpp:270
+#: engines/scumm/help.cpp:262 engines/scumm/help.cpp:271
msgid "Lower left item"
msgstr ""
-#: engines/scumm/help.cpp:262 engines/scumm/help.cpp:271
+#: engines/scumm/help.cpp:263 engines/scumm/help.cpp:272
msgid "Upper right item"
msgstr ""
-#: engines/scumm/help.cpp:263 engines/scumm/help.cpp:273
+#: engines/scumm/help.cpp:264 engines/scumm/help.cpp:274
msgid "Lower right item"
msgstr ""
-#: engines/scumm/help.cpp:269
+#: engines/scumm/help.cpp:270
msgid "Middle left item"
msgstr ""
-#: engines/scumm/help.cpp:272
+#: engines/scumm/help.cpp:273
msgid "Middle right item"
msgstr ""
-#: engines/scumm/help.cpp:279 engines/scumm/help.cpp:284
+#: engines/scumm/help.cpp:280 engines/scumm/help.cpp:285
msgid "Switching characters:"
msgstr ""
-#: engines/scumm/help.cpp:281
+#: engines/scumm/help.cpp:282
msgid "Second kid"
msgstr ""
-#: engines/scumm/help.cpp:282
+#: engines/scumm/help.cpp:283
msgid "Third kid"
msgstr ""
-#: engines/scumm/help.cpp:294
-msgid "Fighting controls (numpad):"
+#: engines/scumm/help.cpp:292
+msgid "Toggle Inventory/IQ Points display"
+msgstr ""
+
+#: engines/scumm/help.cpp:293
+msgid "Toggle Keyboard/Mouse Fighting (*)"
+msgstr ""
+
+#: engines/scumm/help.cpp:295
+msgid "* Keyboard Fighting is always on,"
+msgstr ""
+
+#: engines/scumm/help.cpp:296
+msgid " so despite the in-game message this"
msgstr ""
-#: engines/scumm/help.cpp:295 engines/scumm/help.cpp:296
#: engines/scumm/help.cpp:297
+msgid " actually toggles Mouse Fighting Off/On"
+msgstr ""
+
+#: engines/scumm/help.cpp:304
+msgid "Fighting controls (numpad):"
+msgstr ""
+
+#: engines/scumm/help.cpp:305 engines/scumm/help.cpp:306
+#: engines/scumm/help.cpp:307
msgid "Step back"
msgstr ""
-#: engines/scumm/help.cpp:298
+#: engines/scumm/help.cpp:308
msgid "Block high"
msgstr ""
-#: engines/scumm/help.cpp:299
+#: engines/scumm/help.cpp:309
msgid "Block middle"
msgstr ""
-#: engines/scumm/help.cpp:300
+#: engines/scumm/help.cpp:310
msgid "Block low"
msgstr ""
-#: engines/scumm/help.cpp:301
+#: engines/scumm/help.cpp:311
msgid "Punch high"
msgstr ""
-#: engines/scumm/help.cpp:302
+#: engines/scumm/help.cpp:312
msgid "Punch middle"
msgstr ""
-#: engines/scumm/help.cpp:303
+#: engines/scumm/help.cpp:313
msgid "Punch low"
msgstr ""
-#: engines/scumm/help.cpp:306
+#: engines/scumm/help.cpp:315
+msgid "Sucker punch"
+msgstr ""
+
+#: engines/scumm/help.cpp:318
msgid "These are for Indy on left."
msgstr ""
-#: engines/scumm/help.cpp:307
+#: engines/scumm/help.cpp:319
msgid "When Indy is on the right,"
msgstr ""
-#: engines/scumm/help.cpp:308
+#: engines/scumm/help.cpp:320
msgid "7, 4, and 1 are switched with"
msgstr ""
-#: engines/scumm/help.cpp:309
+#: engines/scumm/help.cpp:321
msgid "9, 6, and 3, respectively."
msgstr ""
-#: engines/scumm/help.cpp:316
+#: engines/scumm/help.cpp:328
msgid "Biplane controls (numpad):"
msgstr ""
-#: engines/scumm/help.cpp:317
+#: engines/scumm/help.cpp:329
msgid "Fly to upper left"
msgstr ""
-#: engines/scumm/help.cpp:318
+#: engines/scumm/help.cpp:330
msgid "Fly to left"
msgstr ""
-#: engines/scumm/help.cpp:319
+#: engines/scumm/help.cpp:331
msgid "Fly to lower left"
msgstr ""
-#: engines/scumm/help.cpp:320
+#: engines/scumm/help.cpp:332
msgid "Fly upwards"
msgstr ""
-#: engines/scumm/help.cpp:321
+#: engines/scumm/help.cpp:333
msgid "Fly straight"
msgstr ""
-#: engines/scumm/help.cpp:322
+#: engines/scumm/help.cpp:334
msgid "Fly down"
msgstr ""
-#: engines/scumm/help.cpp:323
+#: engines/scumm/help.cpp:335
msgid "Fly to upper right"
msgstr ""
-#: engines/scumm/help.cpp:324
+#: engines/scumm/help.cpp:336
msgid "Fly to right"
msgstr ""
-#: engines/scumm/help.cpp:325
+#: engines/scumm/help.cpp:337
msgid "Fly to lower right"
msgstr ""
-#: engines/scumm/scumm.cpp:1823
+#: engines/scumm/scumm.cpp:1832
#, 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:2594
+#: engines/scumm/scumm.cpp:2644
msgid ""
-"Usually, Maniac Mansion would start now. But ScummVM doesn't do that yet. To "
-"play it, go to 'Add Game' in the ScummVM start menu and select the 'Maniac' "
-"directory inside the Tentacle game directory."
+"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 ""
#: engines/scumm/players/player_v3m.cpp:129
@@ -3211,3 +3294,36 @@ msgstr ""
#: engines/wintermute/detection.cpp:59
msgid "Show the current number of frames per second in the upper left corner"
msgstr ""
+
+#: engines/zvision/detection.cpp:256
+msgid "Double FPS"
+msgstr ""
+
+#: engines/zvision/detection.cpp:257
+msgid "Increase game FPS from 30 to 60"
+msgstr ""
+
+#: engines/zvision/detection.cpp:266
+msgid "Enable Venus"
+msgstr ""
+
+#: engines/zvision/detection.cpp:267
+msgid "Enable the Venus help system"
+msgstr ""
+
+#: engines/zvision/detection.cpp:276
+msgid "Disable animation while turning"
+msgstr ""
+
+#: engines/zvision/detection.cpp:277
+msgid "Disable animation while turning in panoramic mode"
+msgstr ""
+
+#: engines/zvision/detection.cpp:286
+msgid "Use the hires MPEG movies"
+msgstr ""
+
+#: engines/zvision/detection.cpp:287
+msgid ""
+"Use the hires MPEG movies of the DVD version, instead of the lowres AVI ones"
+msgstr ""
diff --git a/po/se_SE.po b/po/se_SE.po
index 5e746a3fd7..d49cf3606a 100644
--- a/po/se_SE.po
+++ b/po/se_SE.po
@@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: ScummVM 1.5.0svn\n"
"Report-Msgid-Bugs-To: scummvm-devel@lists.sf.net\n"
-"POT-Creation-Date: 2014-10-04 00:58+0100\n"
+"POT-Creation-Date: 2015-06-30 20:57+0100\n"
"PO-Revision-Date: 2014-07-02 16:30+0100\n"
"Last-Translator: Hampus Flink <hampus.flink@gmail.com>\n"
"Language-Team: \n"
@@ -55,10 +55,11 @@ msgstr "Uppхt"
#: gui/browser.cpp:75 gui/chooser.cpp:46 gui/KeysDialog.cpp:43
#: gui/launcher.cpp:351 gui/massadd.cpp:95 gui/options.cpp:1239
+#: gui/recorderdialog.cpp:70 gui/recorderdialog.cpp:156
#: gui/saveload-dialog.cpp:216 gui/saveload-dialog.cpp:276
-#: gui/saveload-dialog.cpp:547 gui/saveload-dialog.cpp:922
+#: gui/saveload-dialog.cpp:547 gui/saveload-dialog.cpp:931
#: gui/themebrowser.cpp:55 gui/fluidsynth-dialog.cpp:152
-#: engines/engine.cpp:452 backends/platform/wii/options.cpp:48
+#: engines/engine.cpp:483 backends/platform/wii/options.cpp:48
#: backends/events/default/default-events.cpp:196
#: backends/events/default/default-events.cpp:218
#: engines/drascula/saveload.cpp:49 engines/parallaction/saveload.cpp:274
@@ -71,9 +72,9 @@ msgid "Choose"
msgstr "Vфlj"
#: gui/gui-manager.cpp:117 backends/keymapper/remap-dialog.cpp:53
-#: 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
+#: 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"
@@ -89,7 +90,7 @@ msgstr "Visa tangentbord"
msgid "Remap keys"
msgstr "Stфll in tangenter"
-#: gui/gui-manager.cpp:131 base/main.cpp:326 engines/scumm/help.cpp:86
+#: gui/gui-manager.cpp:131 base/main.cpp:326 engines/scumm/help.cpp:87
msgid "Toggle fullscreen"
msgstr "Fullskфrmslфge"
@@ -103,13 +104,13 @@ 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:1240
-#: gui/saveload-dialog.cpp:923 gui/fluidsynth-dialog.cpp:153
-#: engines/engine.cpp:371 engines/engine.cpp:382
+#: 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:399 engines/parallaction/saveload.cpp:274
-#: engines/scumm/dialogs.cpp:193 engines/scumm/scumm.cpp:1825
+#: 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
@@ -479,7 +480,7 @@ msgstr ""
#: gui/launcher.cpp:793 gui/launcher.cpp:941 gui/launcher.cpp:1000
#: gui/fluidsynth-dialog.cpp:217
-#: backends/events/symbiansdl/symbiansdl-events.cpp:184
+#: 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
@@ -489,7 +490,7 @@ 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:184
+#: 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
@@ -526,6 +527,14 @@ 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
+msgid "Mass Add..."
+msgstr "Masstillфgg..."
+
+#: gui/launcher.cpp:1161
+msgid "Record..."
+msgstr ""
+
#: gui/massadd.cpp:79 gui/massadd.cpp:82
msgid "... progress ..."
msgstr "... progression ..."
@@ -624,7 +633,7 @@ msgid "Special dithering modes supported by some games"
msgstr "Speciella gitterlфgen stіdda av vissa spel"
#: gui/options.cpp:760
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2249
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2298
msgid "Fullscreen mode"
msgstr "Fullskфrmslфge"
@@ -941,6 +950,43 @@ msgstr ""
"Temat du valde stіder inte ditt sprхk. Om du vill anvфnda det hфr temat "
"mхste fіrst byta till ett annat sprхk."
+#: gui/recorderdialog.cpp:64
+msgid "Recorder or Playback Gameplay"
+msgstr ""
+
+#: gui/recorderdialog.cpp:69 gui/recorderdialog.cpp:156
+#: gui/saveload-dialog.cpp:220 gui/saveload-dialog.cpp:276
+msgid "Delete"
+msgstr "Radera"
+
+#: gui/recorderdialog.cpp:71
+msgid "Record"
+msgstr ""
+
+#: gui/recorderdialog.cpp:72
+#, fuzzy
+msgid "Playback"
+msgstr "Spela"
+
+#: gui/recorderdialog.cpp:74
+msgid "Edit"
+msgstr ""
+
+#: gui/recorderdialog.cpp:86 gui/recorderdialog.cpp:243
+#: gui/recorderdialog.cpp:253
+msgid "Author: "
+msgstr ""
+
+#: gui/recorderdialog.cpp:87 gui/recorderdialog.cpp:244
+#: gui/recorderdialog.cpp:254
+msgid "Notes: "
+msgstr ""
+
+#: gui/recorderdialog.cpp:155
+#, fuzzy
+msgid "Do you really want to delete this record?"
+msgstr "Vill du verkligen radera den hфr spardatan?"
+
#: gui/saveload-dialog.cpp:167
msgid "List view"
msgstr "Visa som lista"
@@ -961,23 +1007,19 @@ msgstr "Ingen tid sparad"
msgid "No playtime saved"
msgstr "Ingen speltid sparad"
-#: gui/saveload-dialog.cpp:220 gui/saveload-dialog.cpp:276
-msgid "Delete"
-msgstr "Radera"
-
#: gui/saveload-dialog.cpp:275
msgid "Do you really want to delete this saved game?"
msgstr "Vill du verkligen radera den hфr spardatan?"
-#: gui/saveload-dialog.cpp:385 gui/saveload-dialog.cpp:875
+#: gui/saveload-dialog.cpp:385 gui/saveload-dialog.cpp:884
msgid "Date: "
msgstr "Datum:"
-#: gui/saveload-dialog.cpp:389 gui/saveload-dialog.cpp:881
+#: gui/saveload-dialog.cpp:389 gui/saveload-dialog.cpp:890
msgid "Time: "
msgstr "Tid:"
-#: gui/saveload-dialog.cpp:395 gui/saveload-dialog.cpp:889
+#: gui/saveload-dialog.cpp:395 gui/saveload-dialog.cpp:898
msgid "Playtime: "
msgstr "Speltid:"
@@ -993,19 +1035,19 @@ msgstr "Nфsta"
msgid "Prev"
msgstr "Bakхt"
-#: gui/saveload-dialog.cpp:739
+#: gui/saveload-dialog.cpp:748
msgid "New Save"
msgstr "Ny sparning"
-#: gui/saveload-dialog.cpp:739
+#: gui/saveload-dialog.cpp:748
msgid "Create a new save game"
msgstr "Skapa ett nytt sparat spel"
-#: gui/saveload-dialog.cpp:868
+#: gui/saveload-dialog.cpp:877
msgid "Name: "
msgstr "Namn:"
-#: gui/saveload-dialog.cpp:940
+#: gui/saveload-dialog.cpp:949
#, c-format
msgid "Enter a description for slot %d:"
msgstr "Ange en beskrivning fіr position %d:"
@@ -1159,7 +1201,7 @@ msgstr "Skippa rad"
msgid "Error running game:"
msgstr "Fel under kіrning av spel:"
-#: base/main.cpp:536
+#: base/main.cpp:554
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"
@@ -1277,7 +1319,7 @@ 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:758
+#: engines/pegasus/pegasus.cpp:377 engines/sci/engine/kfile.cpp:759
#: engines/toltecs/menu.cpp:281 engines/tsage/scenes.cpp:598
msgid "Save game:"
msgstr "Spara spelet:"
@@ -1290,7 +1332,7 @@ msgstr "Spara spelet:"
#: 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:758 engines/scumm/dialogs.cpp:188
+#: engines/sci/engine/kfile.cpp:759 engines/scumm/dialogs.cpp:188
#: engines/toltecs/menu.cpp:281 engines/tsage/scenes.cpp:598
msgid "Save"
msgstr "Spara"
@@ -1328,23 +1370,23 @@ msgstr "A~v~bryt"
msgid "~K~eys"
msgstr "~T~angenter"
-#: engines/engine.cpp:245
+#: engines/engine.cpp:276
msgid "Could not initialize color format."
msgstr "Kunde inte initialisera fфrgformat."
-#: engines/engine.cpp:253
+#: engines/engine.cpp:284
msgid "Could not switch to video mode: '"
msgstr "Kunde inte byta till videolфget: '"
-#: engines/engine.cpp:262
+#: engines/engine.cpp:293
msgid "Could not apply aspect ratio setting."
msgstr "Kunde inte фndra instфllningen fіr bildfіrhхllanden."
-#: engines/engine.cpp:267
+#: engines/engine.cpp:298
msgid "Could not apply fullscreen setting."
msgstr "Kunde inte applicera fullskфrmsinstфllning."
-#: engines/engine.cpp:367
+#: engines/engine.cpp:398
msgid ""
"You appear to be playing this game directly\n"
"from the CD. This is known to cause problems,\n"
@@ -1358,7 +1400,7 @@ msgstr ""
"datafilerna till din hхrddisk istфllet.\n"
"Se README-filen fіr detaljer."
-#: engines/engine.cpp:378
+#: engines/engine.cpp:409
msgid ""
"This game has audio tracks in its disk. These\n"
"tracks need to be ripped from the disk using\n"
@@ -1372,7 +1414,7 @@ msgstr ""
"fіr att kunna lyssna pх spelets musik.\n"
"Se README-filen fіr detaljer."
-#: engines/engine.cpp:436
+#: engines/engine.cpp:467
#, c-format
msgid ""
"Gamestate load failed (%s)! Please consult the README for basic information, "
@@ -1381,7 +1423,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:449
+#: engines/engine.cpp:480
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 "
@@ -1391,7 +1433,7 @@ 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:452
+#: engines/engine.cpp:483
msgid "Start anyway"
msgstr "Starta фndх"
@@ -1601,11 +1643,11 @@ msgstr "Touchpad-lфge aktiverat."
msgid "Touchpad mode disabled."
msgstr "Touchpad-lфge inaktiverat."
-#: backends/platform/maemo/maemo.cpp:209
+#: backends/platform/maemo/maemo.cpp:208
msgid "Click Mode"
msgstr "Klicklфge"
-#: backends/platform/maemo/maemo.cpp:215
+#: backends/platform/maemo/maemo.cpp:214
#: backends/platform/symbian/src/SymbianActions.cpp:42
#: backends/platform/wince/CEActionsPocket.cpp:60
#: backends/platform/wince/CEActionsSmartphone.cpp:43
@@ -1613,11 +1655,11 @@ msgstr "Klicklфge"
msgid "Left Click"
msgstr "Vфnsterklick"
-#: backends/platform/maemo/maemo.cpp:218
+#: backends/platform/maemo/maemo.cpp:217
msgid "Middle Click"
msgstr "Mittenklick"
-#: backends/platform/maemo/maemo.cpp:221
+#: 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
@@ -1654,19 +1696,19 @@ msgctxt "lowres"
msgid "Normal (no scaling)"
msgstr "Normalt (ingen skalning)"
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2148
+#: 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:2154
+#: 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:2209
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2258
msgid "Active graphics filter:"
msgstr "Aktivt grafikfilter:"
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2251
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2300
msgid "Windowed mode"
msgstr "Fіnsterlфge"
@@ -1725,8 +1767,8 @@ msgstr "Snabblфge"
#: 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:82
-#: engines/scumm/help.cpp:84
+#: engines/scumm/dialogs.cpp:192 engines/scumm/help.cpp:83
+#: engines/scumm/help.cpp:85
msgid "Quit"
msgstr "Avsluta"
@@ -1746,7 +1788,7 @@ msgstr "Virtuellt tangentbord"
msgid "Key mapper"
msgstr "Tangentinst."
-#: backends/events/symbiansdl/symbiansdl-events.cpp:184
+#: backends/events/symbiansdl/symbiansdl-events.cpp:186
msgid "Do you want to quit ?"
msgstr "Vill du avsluta?"
@@ -2082,33 +2124,54 @@ msgstr "Klickning aktiverad"
msgid "Clicking Disabled"
msgstr "Klickning deaktiverad"
-#: engines/agi/detection.cpp:142 engines/drascula/detection.cpp:302
+#: 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.cpp:103
+#: engines/zvision/detection.cpp:246
msgid "Use original save/load screens"
msgstr "Anvфnd originalskфrmar fіr spara/ladda"
-#: engines/agi/detection.cpp:143 engines/drascula/detection.cpp:303
+#: 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/zvision/detection.cpp:104
+#: engines/zvision/detection.cpp:247
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)"
+
+#: engines/agi/detection.cpp:158
+msgid ""
+"Use an alternative palette, common for all Amiga games. This was the old "
+"behavior"
+msgstr ""
+
+#: engines/agi/detection.cpp:167
+#, fuzzy
+msgid "Mouse support"
+msgstr "Skipp-stіd"
+
+#: 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:857 engines/toltecs/menu.cpp:256
+#: engines/sci/engine/kfile.cpp:858 engines/toltecs/menu.cpp:256
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:857 engines/toltecs/menu.cpp:256
+#: engines/sci/engine/kfile.cpp:858 engines/toltecs/menu.cpp:256
msgid "Restore"
msgstr "Хterstфll"
-#: engines/agos/saveload.cpp:160 engines/scumm/scumm.cpp:2368
+#: engines/agos/saveload.cpp:160 engines/scumm/scumm.cpp:2377
#, c-format
msgid ""
"Failed to load game state from file:\n"
@@ -2119,7 +2182,7 @@ msgstr ""
"\n"
"%s"
-#: engines/agos/saveload.cpp:195 engines/scumm/scumm.cpp:2361
+#: engines/agos/saveload.cpp:195 engines/scumm/scumm.cpp:2370
#, c-format
msgid ""
"Failed to save game state to file:\n"
@@ -2130,7 +2193,7 @@ msgstr ""
"\n"
"%s"
-#: engines/agos/saveload.cpp:203 engines/scumm/scumm.cpp:2379
+#: engines/agos/saveload.cpp:203 engines/scumm/scumm.cpp:2388
#, c-format
msgid ""
"Successfully saved game state in file:\n"
@@ -2146,12 +2209,12 @@ msgstr ""
msgid "Cutscene file '%s' not found!"
msgstr "Filmscensfilen '%s' hittades ej!"
-#: engines/cge/detection.cpp:105 engines/cge2/detection.cpp:81
+#: engines/cge/detection.cpp:105 engines/cge2/detection.cpp:101
#, fuzzy
msgid "Color Blind Mode"
msgstr "Klicklфge"
-#: engines/cge/detection.cpp:106 engines/cge2/detection.cpp:82
+#: engines/cge/detection.cpp:106 engines/cge2/detection.cpp:102
msgid "Enable Color Blind Mode by default"
msgstr ""
@@ -2203,7 +2266,7 @@ msgstr "Snabb filmhastighet"
msgid "Play movies at an increased speed"
msgstr "Spela filmer i hіgre hastighet"
-#: engines/groovie/script.cpp:399
+#: engines/groovie/script.cpp:408
msgid "Failed to save game"
msgstr "Kunde inte spara spelet."
@@ -2501,12 +2564,12 @@ msgid "Use an alternative game intro (CD version only)"
msgstr "Anvфnd alternativt spelintro (endast CD-version)"
#: engines/sci/detection.cpp:374
-msgid "EGA undithering"
-msgstr "EGA anti-gitter"
+msgid "Skip EGA dithering pass (full color backgrounds)"
+msgstr ""
#: engines/sci/detection.cpp:375
-msgid "Enable undithering in EGA games"
-msgstr "Aktivera anti-gitter i EGA-spel"
+msgid "Skip dithering pass in EGA games, graphics are shown with full colors"
+msgstr ""
#: engines/sci/detection.cpp:384
msgid "Prefer digital sound effects"
@@ -2579,12 +2642,14 @@ msgstr "Spelet pausat. Tryck MELLANSLAG fіr att fortsфtta."
#. "Moechten Sie wirklich neu starten? (J/N)J"
#. Will react to J as 'Yes'
#: engines/scumm/dialogs.cpp:183
-msgid "Are you sure you want to restart? (Y/N)"
+#, fuzzy
+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
-msgid "Are you sure you want to quit? (Y/N)"
+#, fuzzy
+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
@@ -2672,516 +2737,541 @@ msgstr "жvning"
msgid "Expert"
msgstr "Expert"
-#: engines/scumm/help.cpp:73
+#: engines/scumm/help.cpp:74
msgid "Common keyboard commands:"
msgstr "Vanliga kortkommandon:"
-#: engines/scumm/help.cpp:74
+#: engines/scumm/help.cpp:75
msgid "Save / Load dialog"
msgstr "Spara / Ladda-fіnster"
-#: engines/scumm/help.cpp:76
+#: engines/scumm/help.cpp:77
msgid "Skip line of text"
msgstr "Skippa textrad"
-#: engines/scumm/help.cpp:77
+#: engines/scumm/help.cpp:78
msgid "Esc"
msgstr "Esc"
-#: engines/scumm/help.cpp:77
+#: engines/scumm/help.cpp:78
msgid "Skip cutscene"
msgstr "Skippa scen"
-#: engines/scumm/help.cpp:78
+#: engines/scumm/help.cpp:79
msgid "Space"
msgstr "Mellanslag"
-#: engines/scumm/help.cpp:78
+#: engines/scumm/help.cpp:79
msgid "Pause game"
msgstr "Pausa spelet"
-#: engines/scumm/help.cpp:79 engines/scumm/help.cpp:84
-#: engines/scumm/help.cpp:95 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: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:79
+#: engines/scumm/help.cpp:80
msgid "Load game state 1-10"
msgstr "Ladda spardata 1-10"
-#: engines/scumm/help.cpp:80 engines/scumm/help.cpp:84
-#: engines/scumm/help.cpp:86 engines/scumm/help.cpp:100
-#: engines/scumm/help.cpp:101 engines/scumm/help.cpp:102
+#: 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:80
+#: engines/scumm/help.cpp:81
msgid "Save game state 1-10"
msgstr "Spara speldata 1-10"
-#: engines/scumm/help.cpp:86 engines/scumm/help.cpp:89
+#: engines/scumm/help.cpp:87 engines/scumm/help.cpp:90
msgid "Enter"
msgstr "Enter"
-#: engines/scumm/help.cpp:87
+#: engines/scumm/help.cpp:88
msgid "Music volume up / down"
msgstr "Musikvolym hіj / sфnk"
-#: engines/scumm/help.cpp:88
+#: engines/scumm/help.cpp:89
msgid "Text speed slower / faster"
msgstr "Texthastighet sфnk / іka"
-#: engines/scumm/help.cpp:89
+#: engines/scumm/help.cpp:90
msgid "Simulate left mouse button"
msgstr "Simulera vфnster musknapp"
-#: engines/scumm/help.cpp:90
+#: engines/scumm/help.cpp:91
msgid "Tab"
msgstr "Tab"
-#: engines/scumm/help.cpp:90
+#: engines/scumm/help.cpp:91
msgid "Simulate right mouse button"
msgstr "Simulera hіger musknapp"
-#: engines/scumm/help.cpp:93
+#: engines/scumm/help.cpp:94
msgid "Special keyboard commands:"
msgstr "Specialkortkommandon:"
-#: engines/scumm/help.cpp:94
+#: engines/scumm/help.cpp:95
msgid "Show / Hide console"
msgstr "Visa / gіm konsol"
-#: engines/scumm/help.cpp:95
+#: engines/scumm/help.cpp:96
msgid "Start the debugger"
msgstr "жppna debug-konsolen"
-#: engines/scumm/help.cpp:96
+#: engines/scumm/help.cpp:97
msgid "Show memory consumption"
msgstr "Visa minnesfіrbrukning"
-#: engines/scumm/help.cpp:97
+#: engines/scumm/help.cpp:98
msgid "Run in fast mode (*)"
msgstr "Kіr i snabblфge (*)"
-#: engines/scumm/help.cpp:98
+#: engines/scumm/help.cpp:99
msgid "Run in really fast mode (*)"
msgstr "Kіr i extra snabbt lфge (*)"
-#: engines/scumm/help.cpp:99
+#: engines/scumm/help.cpp:100
msgid "Toggle mouse capture"
msgstr "Musrestriktion av/pх"
-#: engines/scumm/help.cpp:100
+#: engines/scumm/help.cpp:101
msgid "Switch between graphics filters"
msgstr "Vфxla grafikfilter"
-#: engines/scumm/help.cpp:101
+#: engines/scumm/help.cpp:102
msgid "Increase / Decrease scale factor"
msgstr "жka / sфnk skalningsfaktor"
-#: engines/scumm/help.cpp:102
+#: engines/scumm/help.cpp:103
msgid "Toggle aspect-ratio correction"
msgstr "Korrektion av bildfіrhхllande pх/av"
-#: engines/scumm/help.cpp:107
+#: engines/scumm/help.cpp:108
msgid "* Note that using ctrl-f and"
msgstr "* Observera att anvфndning av ctrl-f"
-#: engines/scumm/help.cpp:108
+#: engines/scumm/help.cpp:109
msgid " ctrl-g are not recommended"
msgstr "och ctrl-g inte rekommenderas"
-#: engines/scumm/help.cpp:109
+#: engines/scumm/help.cpp:110
msgid " since they may cause crashes"
msgstr "dх detta kan orsaka krascher"
-#: engines/scumm/help.cpp:110
+#: engines/scumm/help.cpp:111
msgid " or incorrect game behavior."
msgstr " eller felaktigt spelbeteende."
-#: engines/scumm/help.cpp:114
+#: engines/scumm/help.cpp:115
msgid "Spinning drafts on the keyboard:"
msgstr "Vфva melodier med tangentbordet:"
-#: engines/scumm/help.cpp:116
+#: engines/scumm/help.cpp:117
msgid "Main game controls:"
msgstr "Huvudkontroller:"
-#: engines/scumm/help.cpp:121 engines/scumm/help.cpp:136
-#: engines/scumm/help.cpp:161
+#: engines/scumm/help.cpp:122 engines/scumm/help.cpp:137
+#: engines/scumm/help.cpp:162
msgid "Push"
msgstr "Tryck"
-#: engines/scumm/help.cpp:122 engines/scumm/help.cpp:137
-#: engines/scumm/help.cpp:162
+#: engines/scumm/help.cpp:123 engines/scumm/help.cpp:138
+#: engines/scumm/help.cpp:163
msgid "Pull"
msgstr "Dra"
-#: engines/scumm/help.cpp:123 engines/scumm/help.cpp:138
-#: engines/scumm/help.cpp:163 engines/scumm/help.cpp:197
-#: engines/scumm/help.cpp:207
+#: 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 "Ge"
-#: engines/scumm/help.cpp:124 engines/scumm/help.cpp:139
-#: engines/scumm/help.cpp:164 engines/scumm/help.cpp:190
-#: engines/scumm/help.cpp:208
+#: 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 "жppna"
-#: engines/scumm/help.cpp:126
+#: engines/scumm/help.cpp:127
msgid "Go to"
msgstr "Gх till"
-#: engines/scumm/help.cpp:127
+#: engines/scumm/help.cpp:128
msgid "Get"
msgstr "Ta emot"
-#: engines/scumm/help.cpp:128 engines/scumm/help.cpp:152
-#: engines/scumm/help.cpp:170 engines/scumm/help.cpp:198
-#: engines/scumm/help.cpp:213 engines/scumm/help.cpp:224
-#: engines/scumm/help.cpp:250
+#: 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 "Anvфnd"
-#: engines/scumm/help.cpp:129 engines/scumm/help.cpp:141
+#: engines/scumm/help.cpp:130 engines/scumm/help.cpp:142
msgid "Read"
msgstr "Lфs"
-#: engines/scumm/help.cpp:130 engines/scumm/help.cpp:147
+#: engines/scumm/help.cpp:131 engines/scumm/help.cpp:148
msgid "New kid"
msgstr "Ny unge"
-#: engines/scumm/help.cpp:131 engines/scumm/help.cpp:153
-#: engines/scumm/help.cpp:171
+#: engines/scumm/help.cpp:132 engines/scumm/help.cpp:154
+#: engines/scumm/help.cpp:172
msgid "Turn on"
msgstr "Sфtt pх"
-#: engines/scumm/help.cpp:132 engines/scumm/help.cpp:154
-#: engines/scumm/help.cpp:172
+#: engines/scumm/help.cpp:133 engines/scumm/help.cpp:155
+#: engines/scumm/help.cpp:173
msgid "Turn off"
msgstr "Stфng av"
-#: engines/scumm/help.cpp:142 engines/scumm/help.cpp:167
-#: engines/scumm/help.cpp:194
+#: engines/scumm/help.cpp:143 engines/scumm/help.cpp:168
+#: engines/scumm/help.cpp:195
msgid "Walk to"
msgstr "Gх till"
-#: engines/scumm/help.cpp:143 engines/scumm/help.cpp:168
-#: engines/scumm/help.cpp:195 engines/scumm/help.cpp:210
-#: engines/scumm/help.cpp:227
+#: 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 "Ta"
-#: engines/scumm/help.cpp:144 engines/scumm/help.cpp:169
+#: engines/scumm/help.cpp:145 engines/scumm/help.cpp:170
msgid "What is"
msgstr "Vad фr"
-#: engines/scumm/help.cpp:146
+#: engines/scumm/help.cpp:147
msgid "Unlock"
msgstr "Lхs upp"
-#: engines/scumm/help.cpp:149
+#: engines/scumm/help.cpp:150
msgid "Put on"
msgstr "Ta pх"
-#: engines/scumm/help.cpp:150
+#: engines/scumm/help.cpp:151
msgid "Take off"
msgstr "Ta av"
-#: engines/scumm/help.cpp:156
+#: engines/scumm/help.cpp:157
msgid "Fix"
msgstr "Laga"
-#: engines/scumm/help.cpp:158
+#: engines/scumm/help.cpp:159
msgid "Switch"
msgstr "Byt"
-#: engines/scumm/help.cpp:166 engines/scumm/help.cpp:228
+#: engines/scumm/help.cpp:167 engines/scumm/help.cpp:229
msgid "Look"
msgstr "Titta"
-#: engines/scumm/help.cpp:173 engines/scumm/help.cpp:223
+#: engines/scumm/help.cpp:174 engines/scumm/help.cpp:224
msgid "Talk"
msgstr "Tala"
-#: engines/scumm/help.cpp:174
+#: engines/scumm/help.cpp:175
msgid "Travel"
msgstr "Res"
-#: engines/scumm/help.cpp:175
+#: engines/scumm/help.cpp:176
msgid "To Henry / To Indy"
msgstr "Till Henry / Till Indy"
#. I18N: These are different musical notes
-#: engines/scumm/help.cpp:179
+#: engines/scumm/help.cpp:180
msgid "play C minor on distaff"
msgstr "spela C-moll pх staven"
-#: engines/scumm/help.cpp:180
+#: engines/scumm/help.cpp:181
msgid "play D on distaff"
msgstr "spela D pх staven"
-#: engines/scumm/help.cpp:181
+#: engines/scumm/help.cpp:182
msgid "play E on distaff"
msgstr "spela E pх staven"
-#: engines/scumm/help.cpp:182
+#: engines/scumm/help.cpp:183
msgid "play F on distaff"
msgstr "spela F pх staven"
-#: engines/scumm/help.cpp:183
+#: engines/scumm/help.cpp:184
msgid "play G on distaff"
msgstr "spela G pх staven"
-#: engines/scumm/help.cpp:184
+#: engines/scumm/help.cpp:185
msgid "play A on distaff"
msgstr "spela A pх staven"
-#: engines/scumm/help.cpp:185
+#: engines/scumm/help.cpp:186
msgid "play B on distaff"
msgstr "spela H pх staven"
-#: engines/scumm/help.cpp:186
+#: engines/scumm/help.cpp:187
msgid "play C major on distaff"
msgstr "spela C-dur pх staven"
-#: engines/scumm/help.cpp:192 engines/scumm/help.cpp:214
+#: engines/scumm/help.cpp:193 engines/scumm/help.cpp:215
msgid "puSh"
msgstr "Tryck"
-#: engines/scumm/help.cpp:193 engines/scumm/help.cpp:215
+#: engines/scumm/help.cpp:194 engines/scumm/help.cpp:216
msgid "pull (Yank)"
msgstr "Dra"
-#: engines/scumm/help.cpp:196 engines/scumm/help.cpp:212
-#: engines/scumm/help.cpp:248
+#: engines/scumm/help.cpp:197 engines/scumm/help.cpp:213
+#: engines/scumm/help.cpp:249
msgid "Talk to"
msgstr "Tala med"
-#: engines/scumm/help.cpp:199 engines/scumm/help.cpp:211
+#: engines/scumm/help.cpp:200 engines/scumm/help.cpp:212
msgid "Look at"
msgstr "Titta pх"
-#: engines/scumm/help.cpp:200
+#: engines/scumm/help.cpp:201
msgid "turn oN"
msgstr "Sфtt pх"
-#: engines/scumm/help.cpp:201
+#: engines/scumm/help.cpp:202
msgid "turn oFf"
msgstr "Stфng av"
-#: engines/scumm/help.cpp:217
+#: engines/scumm/help.cpp:218
msgid "KeyUp"
msgstr "Piltangent upp"
-#: engines/scumm/help.cpp:217
+#: engines/scumm/help.cpp:218
msgid "Highlight prev dialogue"
msgstr "Markera fіreg. dialog"
-#: engines/scumm/help.cpp:218
+#: engines/scumm/help.cpp:219
msgid "KeyDown"
msgstr "Piltangent ned"
-#: engines/scumm/help.cpp:218
+#: engines/scumm/help.cpp:219
msgid "Highlight next dialogue"
msgstr "Markera nфsta dialog"
-#: engines/scumm/help.cpp:222
+#: engines/scumm/help.cpp:223
msgid "Walk"
msgstr "Gх"
-#: engines/scumm/help.cpp:225 engines/scumm/help.cpp:234
-#: engines/scumm/help.cpp:241 engines/scumm/help.cpp:249
+#: engines/scumm/help.cpp:226 engines/scumm/help.cpp:235
+#: engines/scumm/help.cpp:242 engines/scumm/help.cpp:250
msgid "Inventory"
msgstr "Inventarie"
-#: engines/scumm/help.cpp:226
+#: engines/scumm/help.cpp:227
msgid "Object"
msgstr "Objekt"
-#: engines/scumm/help.cpp:229
+#: engines/scumm/help.cpp:230
msgid "Black and White / Color"
msgstr "Svartvitt / Fфrg"
-#: engines/scumm/help.cpp:232
+#: engines/scumm/help.cpp:233
msgid "Eyes"
msgstr "жgon"
-#: engines/scumm/help.cpp:233
+#: engines/scumm/help.cpp:234
msgid "Tongue"
msgstr "Tunga"
-#: engines/scumm/help.cpp:235
+#: engines/scumm/help.cpp:236
msgid "Punch"
msgstr "Slх"
-#: engines/scumm/help.cpp:236
+#: engines/scumm/help.cpp:237
msgid "Kick"
msgstr "Sparka"
-#: engines/scumm/help.cpp:239 engines/scumm/help.cpp:247
+#: engines/scumm/help.cpp:240 engines/scumm/help.cpp:248
msgid "Examine"
msgstr "Undersіk"
-#: engines/scumm/help.cpp:240
+#: engines/scumm/help.cpp:241
msgid "Regular cursor"
msgstr "Vanlig pekare"
#. I18N: Comm is a communication device
-#: engines/scumm/help.cpp:243
+#: engines/scumm/help.cpp:244
msgid "Comm"
msgstr "Comm"
-#: engines/scumm/help.cpp:246
+#: engines/scumm/help.cpp:247
msgid "Save / Load / Options"
msgstr "Spara / Ladda / Inst."
-#: engines/scumm/help.cpp:255
+#: engines/scumm/help.cpp:256
msgid "Other game controls:"
msgstr "жvriga spelkontroller:"
-#: engines/scumm/help.cpp:257 engines/scumm/help.cpp:267
+#: engines/scumm/help.cpp:258 engines/scumm/help.cpp:268
msgid "Inventory:"
msgstr "Inventarie:"
-#: engines/scumm/help.cpp:258 engines/scumm/help.cpp:274
+#: engines/scumm/help.cpp:259 engines/scumm/help.cpp:275
msgid "Scroll list up"
msgstr "Blфddra listan uppхt"
-#: engines/scumm/help.cpp:259 engines/scumm/help.cpp:275
+#: engines/scumm/help.cpp:260 engines/scumm/help.cpp:276
msgid "Scroll list down"
msgstr "Blфddra listan nedхt"
-#: engines/scumm/help.cpp:260 engines/scumm/help.cpp:268
+#: engines/scumm/help.cpp:261 engines/scumm/help.cpp:269
msgid "Upper left item"
msgstr "жvre vфnstra fіremхlet"
-#: engines/scumm/help.cpp:261 engines/scumm/help.cpp:270
+#: engines/scumm/help.cpp:262 engines/scumm/help.cpp:271
msgid "Lower left item"
msgstr "Nedre vфnstra fіremхlet"
-#: engines/scumm/help.cpp:262 engines/scumm/help.cpp:271
+#: engines/scumm/help.cpp:263 engines/scumm/help.cpp:272
msgid "Upper right item"
msgstr "жvre hіgra fіremхlet"
-#: engines/scumm/help.cpp:263 engines/scumm/help.cpp:273
+#: engines/scumm/help.cpp:264 engines/scumm/help.cpp:274
msgid "Lower right item"
msgstr "Nedre hіgra fіremхlet"
-#: engines/scumm/help.cpp:269
+#: engines/scumm/help.cpp:270
msgid "Middle left item"
msgstr "Mellersta vфnstra fіremхlet"
-#: engines/scumm/help.cpp:272
+#: engines/scumm/help.cpp:273
msgid "Middle right item"
msgstr "Mellersta hіgra fіremхlet"
-#: engines/scumm/help.cpp:279 engines/scumm/help.cpp:284
+#: engines/scumm/help.cpp:280 engines/scumm/help.cpp:285
msgid "Switching characters:"
msgstr "Byta karaktфrer:"
-#: engines/scumm/help.cpp:281
+#: engines/scumm/help.cpp:282
msgid "Second kid"
msgstr "Andra ungen"
-#: engines/scumm/help.cpp:282
+#: engines/scumm/help.cpp:283
msgid "Third kid"
msgstr "Tredje ungen"
-#: engines/scumm/help.cpp:294
+#: engines/scumm/help.cpp:292
+#, fuzzy
+msgid "Toggle Inventory/IQ Points display"
+msgstr "Aktivera centrerad dataskфrm"
+
+#: engines/scumm/help.cpp:293
+msgid "Toggle Keyboard/Mouse Fighting (*)"
+msgstr ""
+
+#: engines/scumm/help.cpp:295
+msgid "* Keyboard Fighting is always on,"
+msgstr ""
+
+#: engines/scumm/help.cpp:296
+msgid " so despite the in-game message this"
+msgstr ""
+
+#: engines/scumm/help.cpp:297
+msgid " actually toggles Mouse Fighting Off/On"
+msgstr ""
+
+#: engines/scumm/help.cpp:304
msgid "Fighting controls (numpad):"
msgstr "Slagsmхlskontroller (nr. tangenter)"
-#: engines/scumm/help.cpp:295 engines/scumm/help.cpp:296
-#: engines/scumm/help.cpp:297
+#: engines/scumm/help.cpp:305 engines/scumm/help.cpp:306
+#: engines/scumm/help.cpp:307
msgid "Step back"
msgstr "Steg bakхt"
-#: engines/scumm/help.cpp:298
+#: engines/scumm/help.cpp:308
msgid "Block high"
msgstr "Blockera hіgt"
-#: engines/scumm/help.cpp:299
+#: engines/scumm/help.cpp:309
msgid "Block middle"
msgstr "Blockera midjehіjd"
-#: engines/scumm/help.cpp:300
+#: engines/scumm/help.cpp:310
msgid "Block low"
msgstr "Blockera lхgt"
-#: engines/scumm/help.cpp:301
+#: engines/scumm/help.cpp:311
msgid "Punch high"
msgstr "Slх hіgt"
-#: engines/scumm/help.cpp:302
+#: engines/scumm/help.cpp:312
msgid "Punch middle"
msgstr "Slх midjehіjd"
-#: engines/scumm/help.cpp:303
+#: engines/scumm/help.cpp:313
msgid "Punch low"
msgstr "Slх lхgt"
-#: engines/scumm/help.cpp:306
+#: engines/scumm/help.cpp:315
+msgid "Sucker punch"
+msgstr ""
+
+#: engines/scumm/help.cpp:318
msgid "These are for Indy on left."
msgstr "Gфller nфr Indy stхr till vфnster."
-#: engines/scumm/help.cpp:307
+#: engines/scumm/help.cpp:319
msgid "When Indy is on the right,"
msgstr "Nфr Indy stхr till hіger byter"
-#: engines/scumm/help.cpp:308
+#: engines/scumm/help.cpp:320
msgid "7, 4, and 1 are switched with"
msgstr "7, 4 och 1 plats med"
-#: engines/scumm/help.cpp:309
+#: engines/scumm/help.cpp:321
msgid "9, 6, and 3, respectively."
msgstr "9, 6 och 3."
-#: engines/scumm/help.cpp:316
+#: engines/scumm/help.cpp:328
msgid "Biplane controls (numpad):"
msgstr "Biplanskontroller (nr. tangenter)"
-#: engines/scumm/help.cpp:317
+#: engines/scumm/help.cpp:329
msgid "Fly to upper left"
msgstr "Flyg хt іvre vфnster"
-#: engines/scumm/help.cpp:318
+#: engines/scumm/help.cpp:330
msgid "Fly to left"
msgstr "Flyg хt vфnster"
-#: engines/scumm/help.cpp:319
+#: engines/scumm/help.cpp:331
msgid "Fly to lower left"
msgstr "Flyg хt nedre vфnster"
-#: engines/scumm/help.cpp:320
+#: engines/scumm/help.cpp:332
msgid "Fly upwards"
msgstr "Flyg uppхt"
-#: engines/scumm/help.cpp:321
+#: engines/scumm/help.cpp:333
msgid "Fly straight"
msgstr "Flyg rakt fram"
-#: engines/scumm/help.cpp:322
+#: engines/scumm/help.cpp:334
msgid "Fly down"
msgstr "Flyg nedхt"
-#: engines/scumm/help.cpp:323
+#: engines/scumm/help.cpp:335
msgid "Fly to upper right"
msgstr "Flyg хt іvre hіger"
-#: engines/scumm/help.cpp:324
+#: engines/scumm/help.cpp:336
msgid "Fly to right"
msgstr "Flyg хt hіger"
-#: engines/scumm/help.cpp:325
+#: engines/scumm/help.cpp:337
msgid "Fly to lower right"
msgstr "Flyg хt nedre hіger"
-#: engines/scumm/scumm.cpp:1823
+#: engines/scumm/scumm.cpp:1832
#, c-format
msgid ""
"Native MIDI support requires the Roland Upgrade from LucasArts,\n"
@@ -3190,11 +3280,12 @@ 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:2594
+#: engines/scumm/scumm.cpp:2644
+#, fuzzy
msgid ""
-"Usually, Maniac Mansion would start now. But ScummVM doesn't do that yet. To "
-"play it, go to 'Add Game' in the ScummVM start menu and select the 'Maniac' "
-"directory inside the Tentacle game directory."
+"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 "
@@ -3328,6 +3419,48 @@ msgstr ""
msgid "Show the current number of frames per second in the upper left corner"
msgstr ""
+#: engines/zvision/detection.cpp:256
+msgid "Double FPS"
+msgstr ""
+
+#: engines/zvision/detection.cpp:257
+msgid "Increase game FPS from 30 to 60"
+msgstr ""
+
+#: engines/zvision/detection.cpp:266
+#, fuzzy
+msgid "Enable Venus"
+msgstr "Aktivera heliumlфge"
+
+#: engines/zvision/detection.cpp:267
+msgid "Enable the Venus help system"
+msgstr ""
+
+#: engines/zvision/detection.cpp:276
+msgid "Disable animation while turning"
+msgstr ""
+
+#: engines/zvision/detection.cpp:277
+msgid "Disable animation while turning in panoramic mode"
+msgstr ""
+
+#: engines/zvision/detection.cpp:286
+msgid "Use the hires MPEG movies"
+msgstr ""
+
+#: engines/zvision/detection.cpp:287
+#, fuzzy
+msgid ""
+"Use the hires MPEG movies of the DVD version, instead of the lowres AVI ones"
+msgstr ""
+"Anvфnd de alternativa silverpekarna istфllet fіr de normala guldpekarna"
+
+#~ msgid "EGA undithering"
+#~ msgstr "EGA anti-gitter"
+
+#~ msgid "Enable undithering in EGA games"
+#~ msgstr "Aktivera anti-gitter i EGA-spel"
+
#~ msgid "MPEG-2 cutscenes found but ScummVM has been built without MPEG-2"
#~ msgstr "MPEG-2-filmscener hittades men ScummVM har byggts utan MPEG-2"
@@ -3335,9 +3468,6 @@ msgstr ""
#~ msgid "Mass Add..."
#~ msgstr "Masstillфgg..."
-#~ msgid "Mass Add..."
-#~ msgstr "Masstillфgg..."
-
#~ msgid ""
#~ "Turns off General MIDI mapping for games with Roland MT-32 soundtrack"
#~ msgstr ""
diff --git a/po/uk_UA.po b/po/uk_UA.po
index 865bb48db8..7245d1bcf7 100644
--- a/po/uk_UA.po
+++ b/po/uk_UA.po
@@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: ScummVM 1.3.0svn\n"
"Report-Msgid-Bugs-To: scummvm-devel@lists.sf.net\n"
-"POT-Creation-Date: 2014-10-04 00:58+0100\n"
+"POT-Creation-Date: 2015-06-30 20:57+0100\n"
"PO-Revision-Date: 2014-07-01 02:34+0300\n"
"Last-Translator: Eugene Sandulenko <sev@scummvm.org>\n"
"Language-Team: Ukrainian\n"
@@ -55,10 +55,11 @@ msgstr "Вгору"
#: gui/browser.cpp:75 gui/chooser.cpp:46 gui/KeysDialog.cpp:43
#: gui/launcher.cpp:351 gui/massadd.cpp:95 gui/options.cpp:1239
+#: gui/recorderdialog.cpp:70 gui/recorderdialog.cpp:156
#: gui/saveload-dialog.cpp:216 gui/saveload-dialog.cpp:276
-#: gui/saveload-dialog.cpp:547 gui/saveload-dialog.cpp:922
+#: gui/saveload-dialog.cpp:547 gui/saveload-dialog.cpp:931
#: gui/themebrowser.cpp:55 gui/fluidsynth-dialog.cpp:152
-#: engines/engine.cpp:452 backends/platform/wii/options.cpp:48
+#: engines/engine.cpp:483 backends/platform/wii/options.cpp:48
#: backends/events/default/default-events.cpp:196
#: backends/events/default/default-events.cpp:218
#: engines/drascula/saveload.cpp:49 engines/parallaction/saveload.cpp:274
@@ -71,9 +72,9 @@ msgid "Choose"
msgstr "Вибрати"
#: gui/gui-manager.cpp:117 backends/keymapper/remap-dialog.cpp:53
-#: 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
+#: 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 "Закрити"
@@ -89,7 +90,7 @@ msgstr "Показати клавіатуру"
msgid "Remap keys"
msgstr "Перепризначити клавіші"
-#: gui/gui-manager.cpp:131 base/main.cpp:326 engines/scumm/help.cpp:86
+#: gui/gui-manager.cpp:131 base/main.cpp:326 engines/scumm/help.cpp:87
msgid "Toggle fullscreen"
msgstr "Перемкнути повноекранний режим"
@@ -103,13 +104,13 @@ msgstr "Призначити"
#: gui/KeysDialog.cpp:42 gui/launcher.cpp:352 gui/launcher.cpp:1048
#: gui/launcher.cpp:1052 gui/massadd.cpp:92 gui/options.cpp:1240
-#: gui/saveload-dialog.cpp:923 gui/fluidsynth-dialog.cpp:153
-#: engines/engine.cpp:371 engines/engine.cpp:382
+#: 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:399 engines/parallaction/saveload.cpp:274
-#: engines/scumm/dialogs.cpp:193 engines/scumm/scumm.cpp:1825
+#: 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
@@ -479,7 +480,7 @@ msgstr ""
#: gui/launcher.cpp:793 gui/launcher.cpp:941 gui/launcher.cpp:1000
#: gui/fluidsynth-dialog.cpp:217
-#: backends/events/symbiansdl/symbiansdl-events.cpp:184
+#: 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
@@ -489,7 +490,7 @@ msgstr "Так"
#: gui/launcher.cpp:793 gui/launcher.cpp:941 gui/launcher.cpp:1000
#: gui/fluidsynth-dialog.cpp:217
-#: backends/events/symbiansdl/symbiansdl-events.cpp:184
+#: 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
@@ -526,6 +527,14 @@ msgstr "Ця гра не підтримує завантаження збережень через головне меню."
msgid "ScummVM could not find any engine capable of running the selected game!"
msgstr "ScummVM не зміг знайти движок для запуску вибраної гри!"
+#: gui/launcher.cpp:1159
+msgid "Mass Add..."
+msgstr "Дод. багато..."
+
+#: gui/launcher.cpp:1161
+msgid "Record..."
+msgstr ""
+
#: gui/massadd.cpp:79 gui/massadd.cpp:82
msgid "... progress ..."
msgstr "... пошук ..."
@@ -624,7 +633,7 @@ msgid "Special dithering modes supported by some games"
msgstr "Спеціальні режими растрування, які підтримують деякі ігри"
#: gui/options.cpp:760
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2249
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2298
msgid "Fullscreen mode"
msgstr "Повноекранний режим"
@@ -943,6 +952,43 @@ msgstr ""
"Вибрана тема не підтримує поточну мову. Якщо ви хочете використовувати цю "
"тему, потрібно в першу чергу змінити мову."
+#: gui/recorderdialog.cpp:64
+msgid "Recorder or Playback Gameplay"
+msgstr ""
+
+#: gui/recorderdialog.cpp:69 gui/recorderdialog.cpp:156
+#: gui/saveload-dialog.cpp:220 gui/saveload-dialog.cpp:276
+msgid "Delete"
+msgstr "Видалити"
+
+#: gui/recorderdialog.cpp:71
+msgid "Record"
+msgstr ""
+
+#: gui/recorderdialog.cpp:72
+#, fuzzy
+msgid "Playback"
+msgstr "Грати"
+
+#: gui/recorderdialog.cpp:74
+msgid "Edit"
+msgstr ""
+
+#: gui/recorderdialog.cpp:86 gui/recorderdialog.cpp:243
+#: gui/recorderdialog.cpp:253
+msgid "Author: "
+msgstr ""
+
+#: gui/recorderdialog.cpp:87 gui/recorderdialog.cpp:244
+#: gui/recorderdialog.cpp:254
+msgid "Notes: "
+msgstr ""
+
+#: gui/recorderdialog.cpp:155
+#, fuzzy
+msgid "Do you really want to delete this record?"
+msgstr "Ви дійсно хочете видалити це збереження?"
+
#: gui/saveload-dialog.cpp:167
msgid "List view"
msgstr "Вигляд списку"
@@ -963,23 +1009,19 @@ msgstr "Час не записано"
msgid "No playtime saved"
msgstr "Час гри не записано"
-#: gui/saveload-dialog.cpp:220 gui/saveload-dialog.cpp:276
-msgid "Delete"
-msgstr "Видалити"
-
#: gui/saveload-dialog.cpp:275
msgid "Do you really want to delete this saved game?"
msgstr "Ви дійсно хочете видалити це збереження?"
-#: gui/saveload-dialog.cpp:385 gui/saveload-dialog.cpp:875
+#: gui/saveload-dialog.cpp:385 gui/saveload-dialog.cpp:884
msgid "Date: "
msgstr "Дата: "
-#: gui/saveload-dialog.cpp:389 gui/saveload-dialog.cpp:881
+#: gui/saveload-dialog.cpp:389 gui/saveload-dialog.cpp:890
msgid "Time: "
msgstr "Час: "
-#: gui/saveload-dialog.cpp:395 gui/saveload-dialog.cpp:889
+#: gui/saveload-dialog.cpp:395 gui/saveload-dialog.cpp:898
msgid "Playtime: "
msgstr "Час гри: "
@@ -995,19 +1037,19 @@ msgstr "Насутпний"
msgid "Prev"
msgstr "Попередній"
-#: gui/saveload-dialog.cpp:739
+#: gui/saveload-dialog.cpp:748
msgid "New Save"
msgstr "Нове збереження"
-#: gui/saveload-dialog.cpp:739
+#: gui/saveload-dialog.cpp:748
msgid "Create a new save game"
msgstr "Створити новий запис гри"
-#: gui/saveload-dialog.cpp:868
+#: gui/saveload-dialog.cpp:877
msgid "Name: "
msgstr "Назва: "
-#: gui/saveload-dialog.cpp:940
+#: gui/saveload-dialog.cpp:949
#, c-format
msgid "Enter a description for slot %d:"
msgstr "Введіть опис для слоту %d:"
@@ -1160,7 +1202,7 @@ msgstr "Пропустити рядок"
msgid "Error running game:"
msgstr "Помилка запуску гри:"
-#: base/main.cpp:536
+#: base/main.cpp:554
msgid "Could not find any engine capable of running the selected game"
msgstr "Не можу знайти движок для запуску вибраної гри"
@@ -1277,7 +1319,7 @@ 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:758
+#: engines/pegasus/pegasus.cpp:377 engines/sci/engine/kfile.cpp:759
#: engines/toltecs/menu.cpp:281 engines/tsage/scenes.cpp:598
msgid "Save game:"
msgstr "Зберегти гру: "
@@ -1290,7 +1332,7 @@ msgstr "Зберегти гру: "
#: 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:758 engines/scumm/dialogs.cpp:188
+#: engines/sci/engine/kfile.cpp:759 engines/scumm/dialogs.cpp:188
#: engines/toltecs/menu.cpp:281 engines/tsage/scenes.cpp:598
msgid "Save"
msgstr "Записати"
@@ -1328,23 +1370,23 @@ msgstr "Ві~д~міна"
msgid "~K~eys"
msgstr "~К~лавіші"
-#: engines/engine.cpp:245
+#: engines/engine.cpp:276
msgid "Could not initialize color format."
msgstr "Не можу налаштувати формат кольору."
-#: engines/engine.cpp:253
+#: engines/engine.cpp:284
msgid "Could not switch to video mode: '"
msgstr "Не вдалося переключити відеорежим: '"
-#: engines/engine.cpp:262
+#: engines/engine.cpp:293
msgid "Could not apply aspect ratio setting."
msgstr "Не вдалося застосувати корекцію співвідношення сторін."
-#: engines/engine.cpp:267
+#: engines/engine.cpp:298
msgid "Could not apply fullscreen setting."
msgstr "Не вдалося застосувати повноекранний режим."
-#: engines/engine.cpp:367
+#: engines/engine.cpp:398
msgid ""
"You appear to be playing this game directly\n"
"from the CD. This is known to cause problems,\n"
@@ -1358,7 +1400,7 @@ msgstr ""
"гри на жорсткий диск.\n"
"Дивіться файл README для подальших інструкцій."
-#: engines/engine.cpp:378
+#: engines/engine.cpp:409
msgid ""
"This game has audio tracks in its disk. These\n"
"tracks need to be ripped from the disk using\n"
@@ -1372,7 +1414,7 @@ msgstr ""
"того, щоб можна було слухати музику у грі.\n"
"Дивіться файл README для подальших інструкцій."
-#: engines/engine.cpp:436
+#: engines/engine.cpp:467
#, c-format
msgid ""
"Gamestate load failed (%s)! Please consult the README for basic information, "
@@ -1381,7 +1423,7 @@ msgstr ""
"Завантаження стану гри не вдалося (%s)! . Будь-ласка, дивіться файл README "
"для основної інормації, а також інструкцій, як отримати подальшу допомогу."
-#: engines/engine.cpp:449
+#: engines/engine.cpp:480
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 "
@@ -1391,7 +1433,7 @@ msgstr ""
"ScummVM. Скорше за все вона не буде працювати стабільно, і збереження ігор, "
"які ви зробите, можуть не працювати у подальших версіях ScummVM."
-#: engines/engine.cpp:452
+#: engines/engine.cpp:483
msgid "Start anyway"
msgstr "Все одно запустити"
@@ -1601,11 +1643,11 @@ msgstr "Режим тачпаду увімкнено."
msgid "Touchpad mode disabled."
msgstr "Режим тачпаду вимкнено."
-#: backends/platform/maemo/maemo.cpp:209
+#: backends/platform/maemo/maemo.cpp:208
msgid "Click Mode"
msgstr "Режим кліків"
-#: backends/platform/maemo/maemo.cpp:215
+#: backends/platform/maemo/maemo.cpp:214
#: backends/platform/symbian/src/SymbianActions.cpp:42
#: backends/platform/wince/CEActionsPocket.cpp:60
#: backends/platform/wince/CEActionsSmartphone.cpp:43
@@ -1613,11 +1655,11 @@ msgstr "Режим кліків"
msgid "Left Click"
msgstr "Лівий клік"
-#: backends/platform/maemo/maemo.cpp:218
+#: backends/platform/maemo/maemo.cpp:217
msgid "Middle Click"
msgstr "Середній клік"
-#: backends/platform/maemo/maemo.cpp:221
+#: 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
@@ -1654,19 +1696,19 @@ msgctxt "lowres"
msgid "Normal (no scaling)"
msgstr "Без збільшення"
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2148
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2197
msgid "Enabled aspect ratio correction"
msgstr "Корекцію співвідношення сторін увімкнено"
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2154
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2203
msgid "Disabled aspect ratio correction"
msgstr "Корекцію співвідношення сторін вимкнено"
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2209
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2258
msgid "Active graphics filter:"
msgstr "Поточний графічний фільтр:"
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2251
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2300
msgid "Windowed mode"
msgstr "Віконний режим"
@@ -1725,8 +1767,8 @@ msgstr "Швидкий режим"
#: 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:82
-#: engines/scumm/help.cpp:84
+#: engines/scumm/dialogs.cpp:192 engines/scumm/help.cpp:83
+#: engines/scumm/help.cpp:85
msgid "Quit"
msgstr "Вихід"
@@ -1746,7 +1788,7 @@ msgstr "Віртуальна клавіатура"
msgid "Key mapper"
msgstr "Призначення клавіш"
-#: backends/events/symbiansdl/symbiansdl-events.cpp:184
+#: backends/events/symbiansdl/symbiansdl-events.cpp:186
msgid "Do you want to quit ?"
msgstr "Ви дійсно хочете вийти?"
@@ -2081,34 +2123,55 @@ msgstr "Кліки увімкнено"
msgid "Clicking Disabled"
msgstr "Кліки вимкнено"
-#: engines/agi/detection.cpp:142 engines/drascula/detection.cpp:302
+#: 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.cpp:103
+#: engines/zvision/detection.cpp:246
msgid "Use original save/load screens"
msgstr "Використовувати ориг. збереження/завантаження екрани"
-#: engines/agi/detection.cpp:143 engines/drascula/detection.cpp:303
+#: 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/zvision/detection.cpp:104
+#: engines/zvision/detection.cpp:247
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 версія)"
+
+#: engines/agi/detection.cpp:158
+msgid ""
+"Use an alternative palette, common for all Amiga games. This was the old "
+"behavior"
+msgstr ""
+
+#: engines/agi/detection.cpp:167
+#, fuzzy
+msgid "Mouse support"
+msgstr "Підтримувати Пропустити"
+
+#: 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:857 engines/toltecs/menu.cpp:256
+#: engines/sci/engine/kfile.cpp:858 engines/toltecs/menu.cpp:256
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:857 engines/toltecs/menu.cpp:256
+#: engines/sci/engine/kfile.cpp:858 engines/toltecs/menu.cpp:256
msgid "Restore"
msgstr "Відновити"
-#: engines/agos/saveload.cpp:160 engines/scumm/scumm.cpp:2368
+#: engines/agos/saveload.cpp:160 engines/scumm/scumm.cpp:2377
#, c-format
msgid ""
"Failed to load game state from file:\n"
@@ -2119,7 +2182,7 @@ msgstr ""
"\n"
"%s"
-#: engines/agos/saveload.cpp:195 engines/scumm/scumm.cpp:2361
+#: engines/agos/saveload.cpp:195 engines/scumm/scumm.cpp:2370
#, c-format
msgid ""
"Failed to save game state to file:\n"
@@ -2130,7 +2193,7 @@ msgstr ""
"\n"
"%s"
-#: engines/agos/saveload.cpp:203 engines/scumm/scumm.cpp:2379
+#: engines/agos/saveload.cpp:203 engines/scumm/scumm.cpp:2388
#, c-format
msgid ""
"Successfully saved game state in file:\n"
@@ -2146,12 +2209,12 @@ msgstr ""
msgid "Cutscene file '%s' not found!"
msgstr "Файл ролику '%s' не знайдено!"
-#: engines/cge/detection.cpp:105 engines/cge2/detection.cpp:81
+#: engines/cge/detection.cpp:105 engines/cge2/detection.cpp:101
#, fuzzy
msgid "Color Blind Mode"
msgstr "Режим кліків"
-#: engines/cge/detection.cpp:106 engines/cge2/detection.cpp:82
+#: engines/cge/detection.cpp:106 engines/cge2/detection.cpp:102
msgid "Enable Color Blind Mode by default"
msgstr ""
@@ -2202,7 +2265,7 @@ msgstr "Режим швидкого відео"
msgid "Play movies at an increased speed"
msgstr "Програвати відео з підвищенною швидкістю"
-#: engines/groovie/script.cpp:399
+#: engines/groovie/script.cpp:408
msgid "Failed to save game"
msgstr "Не вдалося записати гру"
@@ -2499,12 +2562,12 @@ msgid "Use an alternative game intro (CD version only)"
msgstr "Використовувати альтернативний вступ гри (тільки CD версія)"
#: engines/sci/detection.cpp:374
-msgid "EGA undithering"
-msgstr "EGA без растрування"
+msgid "Skip EGA dithering pass (full color backgrounds)"
+msgstr ""
#: engines/sci/detection.cpp:375
-msgid "Enable undithering in EGA games"
-msgstr "Увімкнути анти-згладжування в EGA іграх"
+msgid "Skip dithering pass in EGA games, graphics are shown with full colors"
+msgstr ""
#: engines/sci/detection.cpp:384
msgid "Prefer digital sound effects"
@@ -2577,12 +2640,14 @@ msgstr "Ігру призупинено. Натисніть пробіл для продовження."
#. "Moechten Sie wirklich neu starten? (J/N)J"
#. Will react to J as 'Yes'
#: engines/scumm/dialogs.cpp:183
-msgid "Are you sure you want to restart? (Y/N)"
+#, fuzzy
+msgid "Are you sure you want to restart? (Y/N)Y"
msgstr "Ви упевнені, що хочете розпочати спочатку? (Y/N)"
#. I18N: you may specify 'Yes' symbol at the end of the line. See previous comment
#: engines/scumm/dialogs.cpp:185
-msgid "Are you sure you want to quit? (Y/N)"
+#, fuzzy
+msgid "Are you sure you want to quit? (Y/N)Y"
msgstr "Ви упевнені, що хочете вийти? (Y/N)"
#: engines/scumm/dialogs.cpp:190
@@ -2670,516 +2735,541 @@ msgstr "Практика"
msgid "Expert"
msgstr "Експерт"
-#: engines/scumm/help.cpp:73
+#: engines/scumm/help.cpp:74
msgid "Common keyboard commands:"
msgstr "Основні команди клавіатури:"
-#: engines/scumm/help.cpp:74
+#: engines/scumm/help.cpp:75
msgid "Save / Load dialog"
msgstr "Діалог збереження / завантаження"
-#: engines/scumm/help.cpp:76
+#: engines/scumm/help.cpp:77
msgid "Skip line of text"
msgstr "Пропустити рядок тексту"
-#: engines/scumm/help.cpp:77
+#: engines/scumm/help.cpp:78
msgid "Esc"
msgstr "Esc"
-#: engines/scumm/help.cpp:77
+#: engines/scumm/help.cpp:78
msgid "Skip cutscene"
msgstr "Пропустити ролик"
-#: engines/scumm/help.cpp:78
+#: engines/scumm/help.cpp:79
msgid "Space"
msgstr "Space"
-#: engines/scumm/help.cpp:78
+#: engines/scumm/help.cpp:79
msgid "Pause game"
msgstr "Пауза"
-#: engines/scumm/help.cpp:79 engines/scumm/help.cpp:84
-#: engines/scumm/help.cpp:95 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: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:79
+#: engines/scumm/help.cpp:80
msgid "Load game state 1-10"
msgstr "Завантажити стан гри 1-10"
-#: engines/scumm/help.cpp:80 engines/scumm/help.cpp:84
-#: engines/scumm/help.cpp:86 engines/scumm/help.cpp:100
-#: engines/scumm/help.cpp:101 engines/scumm/help.cpp:102
+#: 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:80
+#: engines/scumm/help.cpp:81
msgid "Save game state 1-10"
msgstr "Зберегти стан гри 1-10"
-#: engines/scumm/help.cpp:86 engines/scumm/help.cpp:89
+#: engines/scumm/help.cpp:87 engines/scumm/help.cpp:90
msgid "Enter"
msgstr "Enter"
-#: engines/scumm/help.cpp:87
+#: engines/scumm/help.cpp:88
msgid "Music volume up / down"
msgstr "Гучність музики вище / нижче"
-#: engines/scumm/help.cpp:88
+#: engines/scumm/help.cpp:89
msgid "Text speed slower / faster"
msgstr "Швидкість тексту повільніше / швидше"
-#: engines/scumm/help.cpp:89
+#: engines/scumm/help.cpp:90
msgid "Simulate left mouse button"
msgstr "Симулювати лівий клік"
-#: engines/scumm/help.cpp:90
+#: engines/scumm/help.cpp:91
msgid "Tab"
msgstr "Tab"
-#: engines/scumm/help.cpp:90
+#: engines/scumm/help.cpp:91
msgid "Simulate right mouse button"
msgstr "Симулювати правий клік"
-#: engines/scumm/help.cpp:93
+#: engines/scumm/help.cpp:94
msgid "Special keyboard commands:"
msgstr "Спеціальні команди клавіатури:"
-#: engines/scumm/help.cpp:94
+#: engines/scumm/help.cpp:95
msgid "Show / Hide console"
msgstr "Показати / cховати консоль"
-#: engines/scumm/help.cpp:95
+#: engines/scumm/help.cpp:96
msgid "Start the debugger"
msgstr "Запуск відладчика"
-#: engines/scumm/help.cpp:96
+#: engines/scumm/help.cpp:97
msgid "Show memory consumption"
msgstr "Показати споживання пам'яті"
-#: engines/scumm/help.cpp:97
+#: engines/scumm/help.cpp:98
msgid "Run in fast mode (*)"
msgstr "Виконати в швидкому режимі (*)"
-#: engines/scumm/help.cpp:98
+#: engines/scumm/help.cpp:99
msgid "Run in really fast mode (*)"
msgstr "Виконати в дуже швидкому режимі (*)"
-#: engines/scumm/help.cpp:99
+#: engines/scumm/help.cpp:100
msgid "Toggle mouse capture"
msgstr "Увімкнути захоплення миші"
-#: engines/scumm/help.cpp:100
+#: engines/scumm/help.cpp:101
msgid "Switch between graphics filters"
msgstr "Переключення між графічними фільтрами"
-#: engines/scumm/help.cpp:101
+#: engines/scumm/help.cpp:102
msgid "Increase / Decrease scale factor"
msgstr "Збільшення / Зменшення масштабу"
-#: engines/scumm/help.cpp:102
+#: engines/scumm/help.cpp:103
msgid "Toggle aspect-ratio correction"
msgstr "Корекція співвідношення сторін"
-#: engines/scumm/help.cpp:107
+#: engines/scumm/help.cpp:108
msgid "* Note that using ctrl-f and"
msgstr "* Зауважимо, що використання ctrl-f і"
-#: engines/scumm/help.cpp:108
+#: engines/scumm/help.cpp:109
msgid " ctrl-g are not recommended"
msgstr " ctrl-g не рекомендується"
-#: engines/scumm/help.cpp:109
+#: engines/scumm/help.cpp:110
msgid " since they may cause crashes"
msgstr " оскільки вони можуть викликати збої"
-#: engines/scumm/help.cpp:110
+#: engines/scumm/help.cpp:111
msgid " or incorrect game behavior."
msgstr " або неправильну поведінку гри."
-#: engines/scumm/help.cpp:114
+#: engines/scumm/help.cpp:115
msgid "Spinning drafts on the keyboard:"
msgstr "Змінні чорновики на клавіатурі:"
-#: engines/scumm/help.cpp:116
+#: engines/scumm/help.cpp:117
msgid "Main game controls:"
msgstr "Основні опції керування:"
-#: engines/scumm/help.cpp:121 engines/scumm/help.cpp:136
-#: engines/scumm/help.cpp:161
+#: engines/scumm/help.cpp:122 engines/scumm/help.cpp:137
+#: engines/scumm/help.cpp:162
msgid "Push"
msgstr "Натиск"
-#: engines/scumm/help.cpp:122 engines/scumm/help.cpp:137
-#: engines/scumm/help.cpp:162
+#: engines/scumm/help.cpp:123 engines/scumm/help.cpp:138
+#: engines/scumm/help.cpp:163
msgid "Pull"
msgstr "Тягти"
-#: engines/scumm/help.cpp:123 engines/scumm/help.cpp:138
-#: engines/scumm/help.cpp:163 engines/scumm/help.cpp:197
-#: engines/scumm/help.cpp:207
+#: 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 "Дати"
-#: engines/scumm/help.cpp:124 engines/scumm/help.cpp:139
-#: engines/scumm/help.cpp:164 engines/scumm/help.cpp:190
-#: engines/scumm/help.cpp:208
+#: 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 "Відкрити"
-#: engines/scumm/help.cpp:126
+#: engines/scumm/help.cpp:127
msgid "Go to"
msgstr "Йти до"
-#: engines/scumm/help.cpp:127
+#: engines/scumm/help.cpp:128
msgid "Get"
msgstr "Отримати"
-#: engines/scumm/help.cpp:128 engines/scumm/help.cpp:152
-#: engines/scumm/help.cpp:170 engines/scumm/help.cpp:198
-#: engines/scumm/help.cpp:213 engines/scumm/help.cpp:224
-#: engines/scumm/help.cpp:250
+#: 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 "Використати"
-#: engines/scumm/help.cpp:129 engines/scumm/help.cpp:141
+#: engines/scumm/help.cpp:130 engines/scumm/help.cpp:142
msgid "Read"
msgstr "Читати"
-#: engines/scumm/help.cpp:130 engines/scumm/help.cpp:147
+#: engines/scumm/help.cpp:131 engines/scumm/help.cpp:148
msgid "New kid"
msgstr "Нова дитина"
-#: engines/scumm/help.cpp:131 engines/scumm/help.cpp:153
-#: engines/scumm/help.cpp:171
+#: engines/scumm/help.cpp:132 engines/scumm/help.cpp:154
+#: engines/scumm/help.cpp:172
msgid "Turn on"
msgstr "Увімкнути"
-#: engines/scumm/help.cpp:132 engines/scumm/help.cpp:154
-#: engines/scumm/help.cpp:172
+#: engines/scumm/help.cpp:133 engines/scumm/help.cpp:155
+#: engines/scumm/help.cpp:173
msgid "Turn off"
msgstr "Вимкнути"
-#: engines/scumm/help.cpp:142 engines/scumm/help.cpp:167
-#: engines/scumm/help.cpp:194
+#: engines/scumm/help.cpp:143 engines/scumm/help.cpp:168
+#: engines/scumm/help.cpp:195
msgid "Walk to"
msgstr "Іти до"
-#: engines/scumm/help.cpp:143 engines/scumm/help.cpp:168
-#: engines/scumm/help.cpp:195 engines/scumm/help.cpp:210
-#: engines/scumm/help.cpp:227
+#: 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 "Підібрати"
-#: engines/scumm/help.cpp:144 engines/scumm/help.cpp:169
+#: engines/scumm/help.cpp:145 engines/scumm/help.cpp:170
msgid "What is"
msgstr "Що є"
-#: engines/scumm/help.cpp:146
+#: engines/scumm/help.cpp:147
msgid "Unlock"
msgstr "Розблокувати"
-#: engines/scumm/help.cpp:149
+#: engines/scumm/help.cpp:150
msgid "Put on"
msgstr "Поставити на"
-#: engines/scumm/help.cpp:150
+#: engines/scumm/help.cpp:151
msgid "Take off"
msgstr "Зняти"
-#: engines/scumm/help.cpp:156
+#: engines/scumm/help.cpp:157
msgid "Fix"
msgstr "Налагодити"
-#: engines/scumm/help.cpp:158
+#: engines/scumm/help.cpp:159
msgid "Switch"
msgstr "Перемкнути"
-#: engines/scumm/help.cpp:166 engines/scumm/help.cpp:228
+#: engines/scumm/help.cpp:167 engines/scumm/help.cpp:229
msgid "Look"
msgstr "Глянути"
-#: engines/scumm/help.cpp:173 engines/scumm/help.cpp:223
+#: engines/scumm/help.cpp:174 engines/scumm/help.cpp:224
msgid "Talk"
msgstr "Говорити"
-#: engines/scumm/help.cpp:174
+#: engines/scumm/help.cpp:175
msgid "Travel"
msgstr "Подорож"
-#: engines/scumm/help.cpp:175
+#: engines/scumm/help.cpp:176
msgid "To Henry / To Indy"
msgstr "У Генрі / У Інді"
#. I18N: These are different musical notes
-#: engines/scumm/help.cpp:179
+#: engines/scumm/help.cpp:180
msgid "play C minor on distaff"
msgstr "грати до мінор на прядці"
-#: engines/scumm/help.cpp:180
+#: engines/scumm/help.cpp:181
msgid "play D on distaff"
msgstr "грати ре на прядці"
-#: engines/scumm/help.cpp:181
+#: engines/scumm/help.cpp:182
msgid "play E on distaff"
msgstr "грати мі на прядці"
-#: engines/scumm/help.cpp:182
+#: engines/scumm/help.cpp:183
msgid "play F on distaff"
msgstr "грати фа на прядці"
-#: engines/scumm/help.cpp:183
+#: engines/scumm/help.cpp:184
msgid "play G on distaff"
msgstr "грати соль на прядці"
-#: engines/scumm/help.cpp:184
+#: engines/scumm/help.cpp:185
msgid "play A on distaff"
msgstr "грати ля на прядці"
-#: engines/scumm/help.cpp:185
+#: engines/scumm/help.cpp:186
msgid "play B on distaff"
msgstr "грати сі на прядці"
-#: engines/scumm/help.cpp:186
+#: engines/scumm/help.cpp:187
msgid "play C major on distaff"
msgstr "грати до мажор на прядці"
-#: engines/scumm/help.cpp:192 engines/scumm/help.cpp:214
+#: engines/scumm/help.cpp:193 engines/scumm/help.cpp:215
msgid "puSh"
msgstr "Поштовх"
-#: engines/scumm/help.cpp:193 engines/scumm/help.cpp:215
+#: engines/scumm/help.cpp:194 engines/scumm/help.cpp:216
msgid "pull (Yank)"
msgstr "тягнути (Смикнути)"
-#: engines/scumm/help.cpp:196 engines/scumm/help.cpp:212
-#: engines/scumm/help.cpp:248
+#: engines/scumm/help.cpp:197 engines/scumm/help.cpp:213
+#: engines/scumm/help.cpp:249
msgid "Talk to"
msgstr "Говорити до"
-#: engines/scumm/help.cpp:199 engines/scumm/help.cpp:211
+#: engines/scumm/help.cpp:200 engines/scumm/help.cpp:212
msgid "Look at"
msgstr "Глянути на"
-#: engines/scumm/help.cpp:200
+#: engines/scumm/help.cpp:201
msgid "turn oN"
msgstr "Увімкнути"
-#: engines/scumm/help.cpp:201
+#: engines/scumm/help.cpp:202
msgid "turn oFf"
msgstr "Вимкнути"
-#: engines/scumm/help.cpp:217
+#: engines/scumm/help.cpp:218
msgid "KeyUp"
msgstr "Натиснути"
-#: engines/scumm/help.cpp:217
+#: engines/scumm/help.cpp:218
msgid "Highlight prev dialogue"
msgstr "Виділити попередній діалог"
-#: engines/scumm/help.cpp:218
+#: engines/scumm/help.cpp:219
msgid "KeyDown"
msgstr "Відпустити"
-#: engines/scumm/help.cpp:218
+#: engines/scumm/help.cpp:219
msgid "Highlight next dialogue"
msgstr "Виділити наступний діалог"
-#: engines/scumm/help.cpp:222
+#: engines/scumm/help.cpp:223
msgid "Walk"
msgstr "Іти"
-#: engines/scumm/help.cpp:225 engines/scumm/help.cpp:234
-#: engines/scumm/help.cpp:241 engines/scumm/help.cpp:249
+#: engines/scumm/help.cpp:226 engines/scumm/help.cpp:235
+#: engines/scumm/help.cpp:242 engines/scumm/help.cpp:250
msgid "Inventory"
msgstr "Інвентар"
-#: engines/scumm/help.cpp:226
+#: engines/scumm/help.cpp:227
msgid "Object"
msgstr "Об'єкт"
-#: engines/scumm/help.cpp:229
+#: engines/scumm/help.cpp:230
msgid "Black and White / Color"
msgstr "Чорнобілий / Кольоровий"
-#: engines/scumm/help.cpp:232
+#: engines/scumm/help.cpp:233
msgid "Eyes"
msgstr "Очі"
-#: engines/scumm/help.cpp:233
+#: engines/scumm/help.cpp:234
msgid "Tongue"
msgstr "Язик"
-#: engines/scumm/help.cpp:235
+#: engines/scumm/help.cpp:236
msgid "Punch"
msgstr "Вдарити кулаком"
-#: engines/scumm/help.cpp:236
+#: engines/scumm/help.cpp:237
msgid "Kick"
msgstr "Вдарити ногою"
-#: engines/scumm/help.cpp:239 engines/scumm/help.cpp:247
+#: engines/scumm/help.cpp:240 engines/scumm/help.cpp:248
msgid "Examine"
msgstr "Розглянути"
-#: engines/scumm/help.cpp:240
+#: engines/scumm/help.cpp:241
msgid "Regular cursor"
msgstr "Звичайний курсор"
#. I18N: Comm is a communication device
-#: engines/scumm/help.cpp:243
+#: engines/scumm/help.cpp:244
msgid "Comm"
msgstr "Комм"
-#: engines/scumm/help.cpp:246
+#: engines/scumm/help.cpp:247
msgid "Save / Load / Options"
msgstr "Збереження / Завантаження / Налаштування"
-#: engines/scumm/help.cpp:255
+#: engines/scumm/help.cpp:256
msgid "Other game controls:"
msgstr "Інше керування грою:"
-#: engines/scumm/help.cpp:257 engines/scumm/help.cpp:267
+#: engines/scumm/help.cpp:258 engines/scumm/help.cpp:268
msgid "Inventory:"
msgstr "Інвентар:"
-#: engines/scumm/help.cpp:258 engines/scumm/help.cpp:274
+#: engines/scumm/help.cpp:259 engines/scumm/help.cpp:275
msgid "Scroll list up"
msgstr "Прокручення списку догори"
-#: engines/scumm/help.cpp:259 engines/scumm/help.cpp:275
+#: engines/scumm/help.cpp:260 engines/scumm/help.cpp:276
msgid "Scroll list down"
msgstr "Прокручення списку донизу"
-#: engines/scumm/help.cpp:260 engines/scumm/help.cpp:268
+#: engines/scumm/help.cpp:261 engines/scumm/help.cpp:269
msgid "Upper left item"
msgstr "Верхня зліва річ"
-#: engines/scumm/help.cpp:261 engines/scumm/help.cpp:270
+#: engines/scumm/help.cpp:262 engines/scumm/help.cpp:271
msgid "Lower left item"
msgstr "Нижня зліва річ"
-#: engines/scumm/help.cpp:262 engines/scumm/help.cpp:271
+#: engines/scumm/help.cpp:263 engines/scumm/help.cpp:272
msgid "Upper right item"
msgstr "Верхня справа річ"
-#: engines/scumm/help.cpp:263 engines/scumm/help.cpp:273
+#: engines/scumm/help.cpp:264 engines/scumm/help.cpp:274
msgid "Lower right item"
msgstr "Нижня справа річ"
-#: engines/scumm/help.cpp:269
+#: engines/scumm/help.cpp:270
msgid "Middle left item"
msgstr "Середня зліва річ"
-#: engines/scumm/help.cpp:272
+#: engines/scumm/help.cpp:273
msgid "Middle right item"
msgstr "Середня справа річ"
-#: engines/scumm/help.cpp:279 engines/scumm/help.cpp:284
+#: engines/scumm/help.cpp:280 engines/scumm/help.cpp:285
msgid "Switching characters:"
msgstr "Переключення героїв:"
-#: engines/scumm/help.cpp:281
+#: engines/scumm/help.cpp:282
msgid "Second kid"
msgstr "Друга дитина"
-#: engines/scumm/help.cpp:282
+#: engines/scumm/help.cpp:283
msgid "Third kid"
msgstr "Третя дитина"
-#: engines/scumm/help.cpp:294
+#: engines/scumm/help.cpp:292
+#, fuzzy
+msgid "Toggle Inventory/IQ Points display"
+msgstr "Перемкнути показування в центрі екрану"
+
+#: engines/scumm/help.cpp:293
+msgid "Toggle Keyboard/Mouse Fighting (*)"
+msgstr ""
+
+#: engines/scumm/help.cpp:295
+msgid "* Keyboard Fighting is always on,"
+msgstr ""
+
+#: engines/scumm/help.cpp:296
+msgid " so despite the in-game message this"
+msgstr ""
+
+#: engines/scumm/help.cpp:297
+msgid " actually toggles Mouse Fighting Off/On"
+msgstr ""
+
+#: engines/scumm/help.cpp:304
msgid "Fighting controls (numpad):"
msgstr "Керування бійкою (numpad):"
-#: engines/scumm/help.cpp:295 engines/scumm/help.cpp:296
-#: engines/scumm/help.cpp:297
+#: engines/scumm/help.cpp:305 engines/scumm/help.cpp:306
+#: engines/scumm/help.cpp:307
msgid "Step back"
msgstr "Крок назад"
-#: engines/scumm/help.cpp:298
+#: engines/scumm/help.cpp:308
msgid "Block high"
msgstr "Блокувати зверху"
-#: engines/scumm/help.cpp:299
+#: engines/scumm/help.cpp:309
msgid "Block middle"
msgstr "Блокувати посередині"
-#: engines/scumm/help.cpp:300
+#: engines/scumm/help.cpp:310
msgid "Block low"
msgstr "Блокувати знизу"
-#: engines/scumm/help.cpp:301
+#: engines/scumm/help.cpp:311
msgid "Punch high"
msgstr "Бити зверху"
-#: engines/scumm/help.cpp:302
+#: engines/scumm/help.cpp:312
msgid "Punch middle"
msgstr "Бити посередині"
-#: engines/scumm/help.cpp:303
+#: engines/scumm/help.cpp:313
msgid "Punch low"
msgstr "Бити знизу"
-#: engines/scumm/help.cpp:306
+#: engines/scumm/help.cpp:315
+msgid "Sucker punch"
+msgstr ""
+
+#: engines/scumm/help.cpp:318
msgid "These are for Indy on left."
msgstr "У випадку для Інді зліва."
-#: engines/scumm/help.cpp:307
+#: engines/scumm/help.cpp:319
msgid "When Indy is on the right,"
msgstr "Коли Інді є справа,"
-#: engines/scumm/help.cpp:308
+#: engines/scumm/help.cpp:320
msgid "7, 4, and 1 are switched with"
msgstr "7, 4, і 1 перемикаються на"
-#: engines/scumm/help.cpp:309
+#: engines/scumm/help.cpp:321
msgid "9, 6, and 3, respectively."
msgstr "9, 6 і 3 відповідно."
-#: engines/scumm/help.cpp:316
+#: engines/scumm/help.cpp:328
msgid "Biplane controls (numpad):"
msgstr "Керування біпланом (numpad):"
-#: engines/scumm/help.cpp:317
+#: engines/scumm/help.cpp:329
msgid "Fly to upper left"
msgstr "Летіти догори наліво"
-#: engines/scumm/help.cpp:318
+#: engines/scumm/help.cpp:330
msgid "Fly to left"
msgstr "Летіти наліво"
-#: engines/scumm/help.cpp:319
+#: engines/scumm/help.cpp:331
msgid "Fly to lower left"
msgstr "Летіти нижче наліво"
-#: engines/scumm/help.cpp:320
+#: engines/scumm/help.cpp:332
msgid "Fly upwards"
msgstr "Летіти догори"
-#: engines/scumm/help.cpp:321
+#: engines/scumm/help.cpp:333
msgid "Fly straight"
msgstr "Летіти прямо"
-#: engines/scumm/help.cpp:322
+#: engines/scumm/help.cpp:334
msgid "Fly down"
msgstr "Летіти донизу"
-#: engines/scumm/help.cpp:323
+#: engines/scumm/help.cpp:335
msgid "Fly to upper right"
msgstr "Летіти догори направо"
-#: engines/scumm/help.cpp:324
+#: engines/scumm/help.cpp:336
msgid "Fly to right"
msgstr "Летіти направо"
-#: engines/scumm/help.cpp:325
+#: engines/scumm/help.cpp:337
msgid "Fly to lower right"
msgstr "Летіти донизу направо"
-#: engines/scumm/scumm.cpp:1823
+#: engines/scumm/scumm.cpp:1832
#, c-format
msgid ""
"Native MIDI support requires the Roland Upgrade from LucasArts,\n"
@@ -3188,11 +3278,12 @@ msgstr ""
"Режим \"рідного\" MIDI потребує поновлення Roland Upgrade від\n"
"LucasArts, проте %s відсутній. Перемикаюсь на AdLib."
-#: engines/scumm/scumm.cpp:2594
+#: engines/scumm/scumm.cpp:2644
+#, fuzzy
msgid ""
-"Usually, Maniac Mansion would start now. But ScummVM doesn't do that yet. To "
-"play it, go to 'Add Game' in the ScummVM start menu and select the 'Maniac' "
-"directory inside the Tentacle game directory."
+"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, і "
@@ -3328,6 +3419,49 @@ msgstr ""
msgid "Show the current number of frames per second in the upper left corner"
msgstr ""
+#: engines/zvision/detection.cpp:256
+msgid "Double FPS"
+msgstr ""
+
+#: engines/zvision/detection.cpp:257
+msgid "Increase game FPS from 30 to 60"
+msgstr ""
+
+#: engines/zvision/detection.cpp:266
+#, fuzzy
+msgid "Enable Venus"
+msgstr "Увімкнути режим Геліум"
+
+#: engines/zvision/detection.cpp:267
+msgid "Enable the Venus help system"
+msgstr ""
+
+#: engines/zvision/detection.cpp:276
+msgid "Disable animation while turning"
+msgstr ""
+
+#: engines/zvision/detection.cpp:277
+msgid "Disable animation while turning in panoramic mode"
+msgstr ""
+
+#: engines/zvision/detection.cpp:286
+msgid "Use the hires MPEG movies"
+msgstr ""
+
+#: engines/zvision/detection.cpp:287
+#, fuzzy
+msgid ""
+"Use the hires MPEG movies of the DVD version, instead of the lowres AVI ones"
+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"
@@ -3336,9 +3470,6 @@ msgstr ""
#~ msgid "Mass Add..."
#~ msgstr "Дод. багато..."
-#~ msgid "Mass Add..."
-#~ msgstr "Дод. багато..."
-
#~ msgid ""
#~ "Turns off General MIDI mapping for games with Roland MT-32 soundtrack"
#~ msgstr ""