aboutsummaryrefslogtreecommitdiff
path: root/engines
diff options
context:
space:
mode:
Diffstat (limited to 'engines')
-rw-r--r--engines/agos/detection_tables.h26
-rw-r--r--engines/agos/gfx.cpp2
-rw-r--r--engines/agos/input.cpp10
-rw-r--r--engines/bbvs/bbvs.cpp98
-rw-r--r--engines/bbvs/bbvs.h78
-rw-r--r--engines/bbvs/detection.cpp2
-rw-r--r--engines/bbvs/dialogs.cpp8
-rw-r--r--engines/bbvs/dialogs.h6
-rw-r--r--engines/bbvs/gamemodule.cpp40
-rw-r--r--engines/bbvs/gamemodule.h50
-rw-r--r--engines/bbvs/graphics.cpp4
-rw-r--r--engines/bbvs/minigames/bbairguitar.cpp62
-rw-r--r--engines/bbvs/minigames/bbairguitar.h34
-rw-r--r--engines/bbvs/minigames/bbant.cpp64
-rw-r--r--engines/bbvs/minigames/bbant.h26
-rw-r--r--engines/bbvs/minigames/bbloogie.cpp68
-rw-r--r--engines/bbvs/minigames/bbloogie.h36
-rw-r--r--engines/bbvs/minigames/bbtennis.cpp44
-rw-r--r--engines/bbvs/minigames/bbtennis.h22
-rw-r--r--engines/bbvs/minigames/minigame.cpp6
-rw-r--r--engines/bbvs/minigames/minigame.h14
-rw-r--r--engines/bbvs/saveload.cpp26
-rw-r--r--engines/bbvs/scene.cpp20
-rw-r--r--engines/bbvs/spritemodule.cpp12
-rw-r--r--engines/bbvs/videoplayer.cpp4
-rw-r--r--engines/bbvs/walk.cpp24
-rw-r--r--engines/cge/POTFILES2
-rw-r--r--engines/cge/cge.h6
-rw-r--r--engines/cge/detection.cpp175
-rw-r--r--engines/cge/fileio.cpp24
-rw-r--r--engines/cge/vga13h.cpp2
-rw-r--r--engines/cge2/POTFILES1
-rw-r--r--engines/cge2/bitmap.cpp458
-rw-r--r--engines/cge2/bitmap.h94
-rw-r--r--engines/cge2/cge2.cpp207
-rw-r--r--engines/cge2/cge2.h338
-rw-r--r--engines/cge2/cge2_main.cpp959
-rw-r--r--engines/cge2/cge2_main.h52
-rw-r--r--engines/cge2/configure.engine3
-rw-r--r--engines/cge2/console.cpp33
-rw-r--r--engines/cge2/console.h40
-rw-r--r--engines/cge2/detection.cpp280
-rw-r--r--engines/cge2/events.cpp293
-rw-r--r--engines/cge2/events.h116
-rw-r--r--engines/cge2/fileio.cpp282
-rw-r--r--engines/cge2/fileio.h133
-rw-r--r--engines/cge2/general.h45
-rw-r--r--engines/cge2/hero.cpp622
-rw-r--r--engines/cge2/hero.h114
-rw-r--r--engines/cge2/inventory.cpp104
-rw-r--r--engines/cge2/map.cpp92
-rw-r--r--engines/cge2/map.h55
-rw-r--r--engines/cge2/module.mk30
-rw-r--r--engines/cge2/saveload.cpp279
-rw-r--r--engines/cge2/snail.cpp865
-rw-r--r--engines/cge2/snail.h129
-rw-r--r--engines/cge2/sound.cpp273
-rw-r--r--engines/cge2/sound.h131
-rw-r--r--engines/cge2/spare.cpp128
-rw-r--r--engines/cge2/spare.h56
-rw-r--r--engines/cge2/talk.cpp312
-rw-r--r--engines/cge2/talk.h94
-rw-r--r--engines/cge2/text.cpp197
-rw-r--r--engines/cge2/text.h68
-rw-r--r--engines/cge2/toolbar.cpp224
-rw-r--r--engines/cge2/vga13h.cpp1219
-rw-r--r--engines/cge2/vga13h.h308
-rw-r--r--engines/cge2/vmenu.cpp162
-rw-r--r--engines/cge2/vmenu.h89
-rw-r--r--engines/composer/composer.cpp5
-rw-r--r--engines/composer/scripting.cpp1
-rw-r--r--engines/drascula/drascula.cpp14
-rw-r--r--engines/dreamweb/POTFILES2
-rw-r--r--engines/fullpipe/fullpipe.cpp4
-rw-r--r--engines/fullpipe/gfx.cpp8
-rw-r--r--engines/fullpipe/input.cpp2
-rw-r--r--engines/fullpipe/motion.cpp14
-rw-r--r--engines/fullpipe/scene.cpp2
-rw-r--r--engines/fullpipe/scenes/scene02.cpp2
-rw-r--r--engines/fullpipe/scenes/scene14.cpp2
-rw-r--r--engines/fullpipe/scenes/scene15.cpp2
-rw-r--r--engines/fullpipe/scenes/scene16.cpp8
-rw-r--r--engines/fullpipe/scenes/scene23.cpp2
-rw-r--r--engines/fullpipe/scenes/scene27.cpp2
-rw-r--r--engines/fullpipe/scenes/scene28.cpp2
-rw-r--r--engines/fullpipe/scenes/scene29.cpp2
-rw-r--r--engines/fullpipe/scenes/scene37.cpp2
-rw-r--r--engines/fullpipe/sound.cpp2
-rw-r--r--engines/fullpipe/statics.cpp8
-rw-r--r--engines/gob/POTFILES2
-rw-r--r--engines/gob/inter_v1.cpp2
-rw-r--r--engines/groovie/graphics.cpp25
-rw-r--r--engines/groovie/graphics.h2
-rw-r--r--engines/groovie/roq.cpp76
-rw-r--r--engines/groovie/roq.h6
-rw-r--r--engines/groovie/script.cpp69
-rw-r--r--engines/groovie/script.h1
-rw-r--r--engines/hopkins/POTFILES2
-rw-r--r--engines/hopkins/computer.cpp2
-rw-r--r--engines/hopkins/files.cpp2
-rw-r--r--engines/hopkins/sound.cpp53
-rw-r--r--engines/hopkins/sound.h2
-rw-r--r--engines/hopkins/talk.cpp2
-rw-r--r--engines/kyra/POTFILES1
-rw-r--r--engines/kyra/detection_tables.h16
-rw-r--r--engines/kyra/items_lol.cpp2
-rw-r--r--engines/kyra/sound_adlib.cpp327
-rw-r--r--engines/kyra/staticres.cpp2
-rw-r--r--engines/kyra/staticres_eob.cpp28
-rw-r--r--engines/kyra/text_rpg.cpp4
-rw-r--r--engines/kyra/vqa.cpp2
-rw-r--r--engines/mads/animation.cpp84
-rw-r--r--engines/mads/animation.h25
-rw-r--r--engines/mads/audio.cpp43
-rw-r--r--engines/mads/audio.h1
-rw-r--r--engines/mads/debugger.cpp43
-rw-r--r--engines/mads/debugger.h2
-rw-r--r--engines/mads/dialogs.cpp74
-rw-r--r--engines/mads/dialogs.h32
-rw-r--r--engines/mads/game.cpp4
-rw-r--r--engines/mads/mads.cpp5
-rw-r--r--engines/mads/menu_views.cpp768
-rw-r--r--engines/mads/menu_views.h225
-rw-r--r--engines/mads/messages.cpp3
-rw-r--r--engines/mads/module.mk1
-rw-r--r--engines/mads/msurface.cpp9
-rw-r--r--engines/mads/msurface.h8
-rw-r--r--engines/mads/nebular/dialogs_nebular.cpp105
-rw-r--r--engines/mads/nebular/dialogs_nebular.h34
-rw-r--r--engines/mads/nebular/game_nebular.cpp28
-rw-r--r--engines/mads/nebular/game_nebular.h4
-rw-r--r--engines/mads/nebular/menu_nebular.cpp463
-rw-r--r--engines/mads/nebular/menu_nebular.h110
-rw-r--r--engines/mads/nebular/nebular_scenes.cpp2
-rw-r--r--engines/mads/nebular/nebular_scenes5.cpp2
-rw-r--r--engines/mads/nebular/nebular_scenes6.cpp7
-rw-r--r--engines/mads/nebular/nebular_scenes7.cpp2
-rw-r--r--engines/mads/nebular/nebular_scenes8.cpp2
-rw-r--r--engines/mads/nebular/sound_nebular.cpp358
-rw-r--r--engines/mads/nebular/sound_nebular.h84
-rw-r--r--engines/mads/palette.cpp65
-rw-r--r--engines/mads/palette.h2
-rw-r--r--engines/mads/phantom/game_phantom.cpp15
-rw-r--r--engines/mads/scene.cpp14
-rw-r--r--engines/mads/scene.h12
-rw-r--r--engines/mads/scene_data.cpp41
-rw-r--r--engines/mads/scene_data.h3
-rw-r--r--engines/mads/screen.cpp50
-rw-r--r--engines/mads/screen.h24
-rw-r--r--engines/mads/sequence.cpp2
-rw-r--r--engines/mads/sound.cpp38
-rw-r--r--engines/mads/sound.h1
-rw-r--r--engines/mads/sprites.cpp8
-rw-r--r--engines/mads/user_interface.h2
-rw-r--r--engines/mortevielle/detection_tables.h2
-rw-r--r--engines/mortevielle/mortevielle.h2
-rw-r--r--engines/mortevielle/utils.cpp2
-rw-r--r--engines/neverhood/console.cpp2
-rw-r--r--engines/neverhood/sound.cpp2
-rw-r--r--engines/pegasus/energymonitor.cpp4
-rw-r--r--engines/pegasus/input.cpp2
-rw-r--r--engines/pegasus/interaction.cpp38
-rw-r--r--engines/pegasus/interaction.h6
-rw-r--r--engines/pegasus/module.mk1
-rw-r--r--engines/pegasus/neighborhood/caldoria/caldoria.cpp146
-rw-r--r--engines/pegasus/neighborhood/caldoria/caldoria4dsystem.cpp42
-rw-r--r--engines/pegasus/neighborhood/mars/shuttlehud.cpp42
-rw-r--r--engines/pegasus/neighborhood/norad/alpha/ecrmonitor.cpp4
-rw-r--r--engines/pegasus/neighborhood/norad/alpha/fillingstation.cpp118
-rw-r--r--engines/pegasus/neighborhood/norad/delta/globegame.cpp30
-rw-r--r--engines/pegasus/neighborhood/norad/subcontrolroom.cpp191
-rw-r--r--engines/pegasus/neighborhood/tsa/fulltsa.cpp845
-rw-r--r--engines/pegasus/neighborhood/tsa/tinytsa.cpp124
-rw-r--r--engines/pegasus/neighborhood/wsc/wsc.cpp698
-rw-r--r--engines/pegasus/pegasus.cpp4
-rw-r--r--engines/prince/animation.cpp178
-rw-r--r--engines/prince/animation.h73
-rw-r--r--engines/prince/archive.cpp166
-rw-r--r--engines/prince/archive.h62
-rw-r--r--engines/prince/common.h45
-rw-r--r--engines/prince/configure.engine3
-rw-r--r--engines/prince/cursor.cpp54
-rw-r--r--engines/prince/cursor.h46
-rw-r--r--engines/prince/curve_values.h45
-rw-r--r--engines/prince/debugger.cpp174
-rw-r--r--engines/prince/debugger.h58
-rw-r--r--engines/prince/decompress.cpp171
-rw-r--r--engines/prince/decompress.h44
-rw-r--r--engines/prince/detection.cpp75
-rw-r--r--engines/prince/detection.h130
-rw-r--r--engines/prince/flags.cpp420
-rw-r--r--engines/prince/flags.h421
-rw-r--r--engines/prince/font.cpp94
-rw-r--r--engines/prince/font.h64
-rw-r--r--engines/prince/graphics.cpp474
-rw-r--r--engines/prince/graphics.h76
-rw-r--r--engines/prince/hero.cpp1002
-rw-r--r--engines/prince/hero.h184
-rw-r--r--engines/prince/hero_set.h244
-rw-r--r--engines/prince/mhwanh.cpp71
-rw-r--r--engines/prince/mhwanh.h55
-rw-r--r--engines/prince/mob.cpp108
-rw-r--r--engines/prince/mob.h70
-rw-r--r--engines/prince/module.mk30
-rw-r--r--engines/prince/musNum.h87
-rw-r--r--engines/prince/object.cpp113
-rw-r--r--engines/prince/object.h70
-rw-r--r--engines/prince/option_text.h85
-rw-r--r--engines/prince/prince.cpp4846
-rw-r--r--engines/prince/prince.h674
-rw-r--r--engines/prince/pscr.cpp75
-rw-r--r--engines/prince/pscr.h48
-rw-r--r--engines/prince/resource.h100
-rw-r--r--engines/prince/saveload.cpp531
-rw-r--r--engines/prince/script.cpp2082
-rw-r--r--engines/prince/script.h398
-rw-r--r--engines/prince/sound.cpp211
-rw-r--r--engines/prince/sound.h67
-rw-r--r--engines/prince/variatxt.cpp55
-rw-r--r--engines/prince/variatxt.h40
-rw-r--r--engines/queen/POTFILES2
-rw-r--r--engines/queen/logic.cpp6
-rw-r--r--engines/queen/talk.cpp12
-rw-r--r--engines/saga/actor.h1
-rw-r--r--engines/saga/introproc_ite.cpp2
-rw-r--r--engines/saga/saveload.cpp29
-rw-r--r--engines/saga/scene.h3
-rw-r--r--engines/saga/sfuncs.cpp4
-rw-r--r--engines/saga/shorten.cpp2
-rw-r--r--engines/savestate.h2
-rw-r--r--engines/sci/console.cpp5
-rw-r--r--engines/sci/detection.cpp22
-rw-r--r--engines/sci/detection_tables.h32
-rw-r--r--engines/sci/engine/features.cpp6
-rw-r--r--engines/sci/engine/kernel.h4
-rw-r--r--engines/sci/engine/kernel_tables.h3
-rw-r--r--engines/sci/engine/kfile.cpp20
-rw-r--r--engines/sci/engine/kgraphics.cpp33
-rw-r--r--engines/sci/engine/kstring.cpp10
-rw-r--r--engines/sci/engine/savegame.cpp2
-rw-r--r--engines/sci/engine/script_patches.cpp40
-rw-r--r--engines/sci/engine/script_patches.h2
-rw-r--r--engines/sci/engine/seg_manager.cpp2
-rw-r--r--engines/sci/engine/state.cpp115
-rw-r--r--engines/sci/engine/workarounds.cpp3
-rw-r--r--engines/sci/event.cpp2
-rw-r--r--engines/sci/graphics/controls16.cpp12
-rw-r--r--engines/sci/graphics/controls16.h6
-rw-r--r--engines/sci/graphics/cursor.cpp8
-rw-r--r--engines/sci/graphics/font.cpp8
-rw-r--r--engines/sci/graphics/font.h4
-rw-r--r--engines/sci/graphics/frameout.cpp19
-rw-r--r--engines/sci/graphics/paint16.cpp6
-rw-r--r--engines/sci/graphics/paint16.h2
-rw-r--r--engines/sci/graphics/paint32.cpp2
-rw-r--r--engines/sci/graphics/palette.cpp87
-rw-r--r--engines/sci/graphics/palette.h6
-rw-r--r--engines/sci/graphics/picture.cpp88
-rw-r--r--engines/sci/graphics/portrait.cpp42
-rw-r--r--engines/sci/graphics/portrait.h2
-rw-r--r--engines/sci/graphics/ports.cpp16
-rw-r--r--engines/sci/graphics/screen.cpp384
-rw-r--r--engines/sci/graphics/screen.h94
-rw-r--r--engines/sci/graphics/text16.cpp225
-rw-r--r--engines/sci/graphics/text16.h15
-rw-r--r--engines/sci/graphics/transitions.cpp6
-rw-r--r--engines/sci/graphics/view.cpp3
-rw-r--r--engines/sci/module.mk4
-rw-r--r--engines/sci/parser/said.cpp35
-rw-r--r--engines/sci/parser/vocabulary.cpp12
-rw-r--r--engines/sci/resource.cpp55
-rw-r--r--engines/sci/resource.h16
-rw-r--r--engines/sci/resource_audio.cpp3
-rw-r--r--engines/sci/sci.cpp6
-rw-r--r--engines/sci/sci.h13
-rw-r--r--engines/sci/sound/drivers/midi.cpp76
-rw-r--r--engines/sci/sound/music.cpp2
-rw-r--r--engines/sci/sound/music.h2
-rw-r--r--engines/scumm/POTFILES3
-rw-r--r--engines/scumm/cdda.cpp2
-rw-r--r--engines/scumm/charset.cpp95
-rw-r--r--engines/scumm/charset.h29
-rw-r--r--engines/scumm/detection.cpp9
-rw-r--r--engines/scumm/detection_tables.h20
-rw-r--r--engines/scumm/dialogs.cpp10
-rw-r--r--engines/scumm/nut_renderer.cpp55
-rw-r--r--engines/scumm/object.cpp1
-rw-r--r--engines/scumm/players/player_mac.cpp1
-rw-r--r--engines/scumm/saveload.cpp7
-rw-r--r--engines/scumm/script.cpp12
-rw-r--r--engines/scumm/script_v0.cpp6
-rw-r--r--engines/scumm/script_v2.cpp9
-rw-r--r--engines/scumm/scumm-md5.h10
-rw-r--r--engines/scumm/scumm.cpp3
-rw-r--r--engines/scumm/scumm.h5
-rw-r--r--engines/scumm/smush/smush_font.cpp66
-rw-r--r--engines/scumm/sound.cpp4
-rw-r--r--engines/scumm/vars.cpp3
-rw-r--r--engines/sword1/POTFILES2
-rw-r--r--engines/sword1/animation.cpp2
-rw-r--r--engines/sword1/console.cpp23
-rw-r--r--engines/sword1/console.h1
-rw-r--r--engines/sword1/sound.cpp51
-rw-r--r--engines/sword1/sound.h2
-rw-r--r--engines/sword1/sword1.cpp2
-rw-r--r--engines/sword1/sword1.h1
-rw-r--r--engines/sword2/animation.cpp2
-rw-r--r--engines/sword25/gfx/renderobjectmanager.cpp2
-rw-r--r--engines/sword25/kernel/persistenceservice.cpp2
-rw-r--r--engines/sword25/util/pluto/pluto.cpp35
-rw-r--r--engines/tinsel/tinsel.cpp15
-rw-r--r--engines/tony/game.cpp4
-rw-r--r--engines/tony/gfxcore.cpp119
-rw-r--r--engines/tony/mpal/lzo.cpp2
-rw-r--r--engines/tony/window.cpp14
-rw-r--r--engines/toon/character.cpp2
-rw-r--r--engines/toon/state.cpp2
-rw-r--r--engines/toon/toon.cpp22
-rw-r--r--engines/touche/detection.cpp1
-rw-r--r--engines/tsage/POTFILES3
-rw-r--r--engines/tsage/blue_force/blueforce_dialogs.cpp2
-rw-r--r--engines/tsage/debugger.cpp6
-rw-r--r--engines/tsage/debugger.h4
-rw-r--r--engines/tsage/module.mk3
-rw-r--r--engines/tsage/ringworld/ringworld_dialogs.cpp2
-rw-r--r--engines/tsage/ringworld2/ringworld2_airduct.cpp909
-rw-r--r--engines/tsage/ringworld2/ringworld2_airduct.h89
-rw-r--r--engines/tsage/ringworld2/ringworld2_logic.cpp8
-rw-r--r--engines/tsage/ringworld2/ringworld2_outpost.cpp4700
-rw-r--r--engines/tsage/ringworld2/ringworld2_outpost.h259
-rw-r--r--engines/tsage/ringworld2/ringworld2_scenes0.cpp2
-rw-r--r--engines/tsage/ringworld2/ringworld2_scenes1.cpp7254
-rw-r--r--engines/tsage/ringworld2/ringworld2_scenes1.h401
-rw-r--r--engines/tsage/ringworld2/ringworld2_scenes3.cpp2
-rw-r--r--engines/tsage/ringworld2/ringworld2_vampire.cpp1821
-rw-r--r--engines/tsage/ringworld2/ringworld2_vampire.h179
-rw-r--r--engines/tsage/sound.cpp2
-rw-r--r--engines/wintermute/POTFILES1
-rw-r--r--engines/wintermute/base/base_engine.cpp3
-rw-r--r--engines/wintermute/base/base_engine.h9
-rw-r--r--engines/wintermute/base/base_game.cpp9
-rw-r--r--engines/wintermute/base/base_game.h2
-rw-r--r--engines/wintermute/base/base_game_settings.cpp9
-rw-r--r--engines/wintermute/base/base_game_settings.h4
-rw-r--r--engines/wintermute/base/base_keyboard_state.cpp48
-rw-r--r--engines/wintermute/base/base_sprite.cpp15
-rw-r--r--engines/wintermute/base/base_string_table.cpp34
-rw-r--r--engines/wintermute/base/base_string_table.h5
-rw-r--r--engines/wintermute/base/gfx/base_renderer.h1
-rw-r--r--engines/wintermute/base/sound/base_sound.cpp18
-rw-r--r--engines/wintermute/base/sound/base_sound_buffer.cpp29
-rw-r--r--engines/wintermute/base/sound/base_sound_buffer.h15
-rw-r--r--engines/wintermute/base/sound/base_sound_manager.cpp8
-rw-r--r--engines/wintermute/dcgf.h4
-rw-r--r--engines/wintermute/detection.cpp6
-rw-r--r--engines/wintermute/detection_tables.h1552
-rw-r--r--engines/wintermute/game_description.h53
-rw-r--r--engines/wintermute/math/rect32.h2
-rw-r--r--engines/wintermute/module.mk2
-rw-r--r--engines/wintermute/utils/utils.cpp5
-rw-r--r--engines/wintermute/video/subtitle_card.cpp56
-rw-r--r--engines/wintermute/video/subtitle_card.h53
-rw-r--r--engines/wintermute/video/video_subtitler.cpp266
-rw-r--r--engines/wintermute/video/video_subtitler.h53
-rw-r--r--engines/wintermute/video/video_theora_player.cpp27
-rw-r--r--engines/wintermute/video/video_theora_player.h6
-rw-r--r--engines/wintermute/wintermute.cpp4
-rw-r--r--engines/wintermute/wintermute.h5
-rw-r--r--engines/zvision/POTFILES1
-rw-r--r--engines/zvision/archives/zfs_archive.cpp2
-rw-r--r--engines/zvision/core/save_manager.cpp4
-rw-r--r--engines/zvision/fonts/truetype_font.cpp1
-rw-r--r--engines/zvision/scripting/actions.cpp6
-rw-r--r--engines/zvision/scripting/controls/animation_control.h2
-rw-r--r--engines/zvision/scripting/controls/lever_control.cpp12
-rw-r--r--engines/zvision/scripting/controls/push_toggle_control.cpp4
-rw-r--r--engines/zvision/scripting/controls/timer_node.cpp2
-rw-r--r--engines/zvision/scripting/scr_file_handling.cpp2
-rw-r--r--engines/zvision/scripting/script_manager.cpp2
-rw-r--r--engines/zvision/utility/utility.cpp2
380 files changed, 37707 insertions, 12385 deletions
diff --git a/engines/agos/detection_tables.h b/engines/agos/detection_tables.h
index 77fc88c6bb..2f4709c49e 100644
--- a/engines/agos/detection_tables.h
+++ b/engines/agos/detection_tables.h
@@ -1259,6 +1259,32 @@ static const AGOSGameDescription gameDescriptions[] = {
GF_TALKIE | GF_OLD_BUNDLE | GF_PLANAR
},
+ // Simon the Sorcerer 1 - English Amiga CD32 demo, from the cover disc of
+ // issue 5 (October 1994) of Amiga CD32 Gamer
+ {
+ {
+ "simon1",
+ "CD32 Demo",
+
+ {
+ { "gameamiga", GAME_BASEFILE, "e243f9229f9728b3476e54d2cf5f18a1", 27998},
+ { "icon.pkd", GAME_ICONFILE, "565ef7a98dcc21ef526a2bb10b6f42ed", 18979},
+ { "stripped.txt", GAME_STRFILE, "94413c71c86c32ed9baaa1c74a151cb3", 243},
+ { "tbllist", GAME_TBLFILE, "f9d5bf2ce09f82289c791c3ca26e1e4b", 696},
+ { NULL, 0, NULL, 0}
+ },
+ Common::EN_ANY,
+ Common::kPlatformAmiga,
+ ADGF_CD | ADGF_DEMO,
+ GUIO2(GUIO_NOSUBTITLES, GUIO_NOMIDI)
+ },
+
+ GType_SIMON1,
+ GID_SIMON1CD32,
+ GF_TALKIE | GF_OLD_BUNDLE | GF_PLANAR
+ },
+
+
// Simon the Sorcerer 1 - English DOS Floppy Demo
{
{
diff --git a/engines/agos/gfx.cpp b/engines/agos/gfx.cpp
index 33145b7d0d..5a1f9f1917 100644
--- a/engines/agos/gfx.cpp
+++ b/engines/agos/gfx.cpp
@@ -547,7 +547,7 @@ void AGOSEngine_Simon1::drawMaskedImage(VC10_state *state) {
if ((dst[count * 2] & 0xF0) == 0x20)
dst[count * 2] = src[count * 2];
if (mask[count + state->x_skip] & 0x0F)
- if ((dst[count * 2 + 1] & 0x0F) == 0x20)
+ if ((dst[count * 2 + 1] & 0xF0) == 0x20)
dst[count * 2 + 1] = src[count * 2 + 1];
} else {
/* no transparency */
diff --git a/engines/agos/input.cpp b/engines/agos/input.cpp
index 8a4e87017a..687a8ef1cf 100644
--- a/engines/agos/input.cpp
+++ b/engines/agos/input.cpp
@@ -460,7 +460,7 @@ void AGOSEngine_Simon1::handleMouseWheelUp() {
_saveLoadEdit = false;
listSaveGames();
}
- } else {
+ } else {
AGOSEngine::handleMouseWheelUp();
}
}
@@ -472,11 +472,11 @@ void AGOSEngine_Simon1::handleMouseWheelDown() {
_saveLoadRowCurPos += 1;
if (_saveLoadRowCurPos >= _numSaveGameRows)
_saveLoadRowCurPos = _numSaveGameRows;
-
+
_saveLoadEdit = false;
listSaveGames();
}
- } else {
+ } else {
AGOSEngine::handleMouseWheelDown();
}
}
@@ -492,7 +492,7 @@ void AGOSEngine_Elvira2::handleMouseWheelUp() {
_saveLoadRowCurPos -= 3;
listSaveGames();
- } else {
+ } else {
AGOSEngine::handleMouseWheelUp();
}
}
@@ -506,7 +506,7 @@ void AGOSEngine_Elvira2::handleMouseWheelDown() {
_saveLoadRowCurPos = 1;
listSaveGames();
- } else {
+ } else {
AGOSEngine::handleMouseWheelDown();
}
}
diff --git a/engines/bbvs/bbvs.cpp b/engines/bbvs/bbvs.cpp
index d2e13e525c..11e4b6cea7 100644
--- a/engines/bbvs/bbvs.cpp
+++ b/engines/bbvs/bbvs.cpp
@@ -60,7 +60,7 @@ static const BBPoint kInventorySlotPositions[] = {
{135, 93}, {134, 145}, { 96, 224}, {128, 224}, {160, 224},
{192, 224}, {224, 224}, {240, 224}, {256, 224}, { 0, 0}
};
-
+
static const BBRect kVerbRects[6] = {
{-32, -2, 19, 27}, {-33, -33, 19, 27}, { 12, -2, 19, 27},
{ 13, -33, 19, 27}, {-10, 8, 19, 27}, {-11, -49, 19, 27}
@@ -77,7 +77,7 @@ bool WalkArea::contains(const Common::Point &pt) const {
BbvsEngine::BbvsEngine(OSystem *syst, const ADGameDescription *gd) :
Engine(syst), _gameDescription(gd) {
-
+
_random = new Common::RandomSource("bbvs");
_currActionCommandIndex = -1;
_buttheadObject = nullptr;
@@ -148,14 +148,14 @@ Common::Error BbvsEngine::run() {
_gameModule = new GameModule();
_spriteModule = new SpriteModule();
_sound = new SoundMan();
-
+
allocSnapshot();
memset(_easterEggInput, 0, sizeof(_easterEggInput));
-
+
_gameTicks = 0;
_playVideoNumber = 0;
_bootSaveSlot = -1;
-
+
memset(_inventoryItemStatus, 0, sizeof(_inventoryItemStatus));
memset(_gameVars, 0, sizeof(_gameVars));
memset(_sceneVisited, 0, sizeof(_sceneVisited));
@@ -189,7 +189,7 @@ Common::Error BbvsEngine::run() {
_playVideoNumber = 0;
}
}
-
+
writeContinueSavegame();
freeSnapshot();
@@ -282,20 +282,20 @@ void BbvsEngine::updateGame() {
inputTicks = 1;
_gameTicks = _system->getMillis();
}
-
+
if (inputTicks > 20) {
inputTicks = 20;
_gameTicks = _system->getMillis();
}
-
+
if (inputTicks == 0)
return;
-
+
if (_mouseX >= 320 || _mouseY >= 240) {
_mouseY = -1;
_mouseX = -1;
}
-
+
bool done;
do {
@@ -304,14 +304,14 @@ void BbvsEngine::updateGame() {
_mouseButtons &= ~kRightButtonClicked;
_keyCode = Common::KEYCODE_INVALID;
} while (--inputTicks && _playVideoNumber == 0 && _gameTicks > 0 && !done);
-
+
if (!done && _playVideoNumber == 0 && _gameTicks > 0) {
DrawList drawList;
buildDrawList(drawList);
_screen->drawDrawList(drawList, _spriteModule);
drawScreen();
}
-
+
_system->delayMillis(10);
}
@@ -329,7 +329,7 @@ void BbvsEngine::updateBackgroundSounds() {
_backgroundSoundsActive[i] = 0;
}
}
-}
+}
bool BbvsEngine::update(int mouseX, int mouseY, uint mouseButtons, Common::KeyCode keyCode) {
@@ -339,7 +339,7 @@ bool BbvsEngine::update(int mouseX, int mouseY, uint mouseButtons, Common::KeyCo
_bootSaveSlot = -1;
return false;
}
-
+
if (_newSceneNum != 0) {
_gameTicks = 0;
return changeScene();
@@ -413,7 +413,7 @@ bool BbvsEngine::update(int mouseX, int mouseY, uint mouseButtons, Common::KeyCo
}
updateInventory(mouseButtons & kLeftButtonClicked);
break;
-
+
case kGSVerbs:
_isSaveAllowed = false;
updateVerbs();
@@ -426,7 +426,7 @@ bool BbvsEngine::update(int mouseX, int mouseY, uint mouseButtons, Common::KeyCo
}
}
break;
-
+
case kGSWait:
case kGSWaitDialog:
_isSaveAllowed = false;
@@ -438,14 +438,14 @@ bool BbvsEngine::update(int mouseX, int mouseY, uint mouseButtons, Common::KeyCo
else
updateCommon();
break;
-
+
case kGSDialog:
_isSaveAllowed = true;
saveSnapshot();
updateDialog(mouseButtons & kLeftButtonClicked);
updateCommon();
break;
-
+
}
return true;
@@ -503,7 +503,7 @@ void BbvsEngine::buildDrawList(DrawList &drawList) {
// Verbs background
drawList.add(_gameModule->getGuiSpriteIndex(13), _verbPos.x - _cameraPos.x,
_verbPos.y - _cameraPos.y, 500);
- // Selected inventory item
+ // Selected inventory item
if (_currInventoryItem >= 0) {
drawList.add(_gameModule->getInventoryItemSpriteIndex(2 * _currInventoryItem), _verbPos.x - _cameraPos.x,
_verbPos.y - _cameraPos.y + 27, 500);
@@ -538,7 +538,7 @@ void BbvsEngine::updateVerbs() {
_mouseCursorSpriteIndex = 0;
return;
}
-
+
for (int i = 0; i < 6; ++i) {
const BBRect &verbRect = kVerbRects[i];
const int16 x = _verbPos.x + verbRect.x;
@@ -551,7 +551,7 @@ void BbvsEngine::updateVerbs() {
break;
}
}
-
+
switch (_currVerbNum) {
case kVerbLook:
case kVerbUse:
@@ -585,7 +585,7 @@ void BbvsEngine::updateDialog(bool clicked) {
_gameState = kGSScene;
return;
}
-
+
int slotX = (_mousePos.x - _cameraPos.x) / 32;
if (slotX >= _dialogSlotCount) {
@@ -597,7 +597,7 @@ void BbvsEngine::updateDialog(bool clicked) {
_mouseCursorSpriteIndex = _gameModule->getGuiSpriteIndex(5);
_activeItemType = kITDialog;
-
+
// Find the selected dialog item index
for (int i = 0; i < 50 && slotX >= 0; ++i) {
if (_dialogItemStatus[i]) {
@@ -605,7 +605,7 @@ void BbvsEngine::updateDialog(bool clicked) {
_activeItemIndex = i;
}
}
-
+
// Select the dialog item action if it was clicked
if (clicked) {
for (int i = 0; i < _gameModule->getActionsCount(); ++i) {
@@ -622,7 +622,7 @@ void BbvsEngine::updateDialog(bool clicked) {
}
void BbvsEngine::updateInventory(bool clicked) {
-
+
Common::Rect kInvButtonRects[3] = {
Common::Rect(97, 13, 97 + 20, 13 + 26),
Common::Rect(135, 15, 135 + 46, 15 + 25),
@@ -636,10 +636,10 @@ void BbvsEngine::updateInventory(bool clicked) {
if (_currVerbNum != kVerbLook && _currVerbNum != kVerbUse && _currVerbNum != kVerbInvItem)
_currVerbNum = kVerbUse;
-
+
const int16 mx = _mousePos.x - _cameraPos.x;
const int16 my = _mousePos.y - _cameraPos.y;
-
+
// Check inventory exit left/right edge of screen
if (mx < 40 || mx > 280) {
_mouseCursorSpriteIndex = _gameModule->getGuiSpriteIndex(10);
@@ -652,7 +652,7 @@ void BbvsEngine::updateInventory(bool clicked) {
return;
}
- // Check hovered/clicked inventory button
+ // Check hovered/clicked inventory button
_inventoryButtonIndex = -1;
if (kInvButtonRects[0].contains(mx, my)) {
_inventoryButtonIndex = 0;
@@ -677,10 +677,10 @@ void BbvsEngine::updateInventory(bool clicked) {
// Find hovered/clicked inventory item
int currItem = -1;
-
+
if (_currVerbNum == kVerbInvItem)
currItem = _currInventoryItem;
-
+
_activeItemType = kITEmpty;
for (int i = 0; i < 50; ++i) {
@@ -769,7 +769,7 @@ void BbvsEngine::updateScene(bool clicked) {
}
}
}
-
+
for (int i = 0; i < _gameModule->getBgObjectsCount(); ++i) {
BgObject *bgObject = _gameModule->getBgObject(i);
if (lastPriority <= bgObject->rect.bottom && bgObject->rect.contains(_mousePos)) {
@@ -921,7 +921,7 @@ bool BbvsEngine::performActionCommand(ActionCommand *actionCommand) {
return false;
case kActionCmdWalkObject:
- {
+ {
SceneObject *sceneObject = &_sceneObjects[actionCommand->sceneObjectIndex];
debug(5, "[%s] walks from (%d, %d) to (%d, %d)", sceneObject->sceneObjectDef->name,
sceneObject->x >> 16, sceneObject->y >> 16, actionCommand->walkDest.x, actionCommand->walkDest.y);
@@ -998,14 +998,14 @@ bool BbvsEngine::performActionCommand(ActionCommand *actionCommand) {
bool BbvsEngine::processCurrAction() {
bool actionsFinished = false;
-
+
if (_sceneObjectActions.size() == 0) {
-
+
for (uint i = 0; i < _currAction->actionCommands.size(); ++i) {
ActionCommand *actionCommand = &_currAction->actionCommands[i];
if (actionCommand->timeStamp != 0)
break;
-
+
if (actionCommand->cmd == kActionCmdMoveObject || actionCommand->cmd == kActionCmdAnimObject) {
SceneObjectAction *sceneObjectAction = 0;
// See if there's already an entry for the SceneObject
@@ -1027,14 +1027,14 @@ bool BbvsEngine::processCurrAction() {
sceneObjectAction->animationIndex = actionCommand->param;
}
}
-
+
if (actionCommand->cmd == kActionCmdSetCameraPos) {
_currCameraNum = actionCommand->param;
_newCameraPos = _gameModule->getCameraInit(actionCommand->param)->cameraPos;
}
}
-
+
// Delete entries for SceneObjects without anim
for (uint i = 0; i < _sceneObjectActions.size();) {
if (!_sceneObjects[_sceneObjectActions[i].sceneObjectIndex].anim)
@@ -1107,7 +1107,7 @@ void BbvsEngine::updateCommon() {
if (doActionCommands) {
ActionCommand *actionCommand = &_currAction->actionCommands[_currActionCommandIndex];
-
+
while (actionCommand->timeStamp == _currActionCommandTimeStamp &&
_currActionCommandIndex < (int)_currAction->actionCommands.size()) {
if (!performActionCommand(actionCommand)) {
@@ -1161,7 +1161,7 @@ void BbvsEngine::updateCommon() {
}
updateWalkObject(sceneObject);
}
-
+
if (sceneObject->walkCount > 0 && sceneObject->turnCount == 0) {
debug(5, "walk step, xIncr: %d, yIncr: %d", sceneObject->xIncr, sceneObject->yIncr);
sceneObject->x += sceneObject->xIncr;
@@ -1226,7 +1226,7 @@ void BbvsEngine::updateCommon() {
}
}
}
-
+
if (_cameraPos.x < _newCameraPos.x)
++_cameraPos.x;
if (_cameraPos.x > _newCameraPos.x)
@@ -1235,7 +1235,7 @@ void BbvsEngine::updateCommon() {
++_cameraPos.y;
if (_cameraPos.y > _newCameraPos.y)
--_cameraPos.y;
-
+
// Check if Butthead is inside a scene exit
if (_newSceneNum == 0 && !_currAction && _buttheadObject) {
int16 buttheadX = _buttheadObject->x >> 16;
@@ -1314,13 +1314,13 @@ void BbvsEngine::stopSounds() {
bool BbvsEngine::runMinigame(int minigameNum) {
debug(0, "BbvsEngine::runMinigame() minigameNum: %d", minigameNum);
-
+
bool fromMainGame = _currSceneNum != kMainMenu;
-
+
_sound->unloadSounds();
-
+
Minigame *minigame = 0;
-
+
switch (minigameNum) {
case kMinigameBbLoogie:
minigame = new MinigameBbLoogie(this);
@@ -1338,9 +1338,9 @@ bool BbvsEngine::runMinigame(int minigameNum) {
error("Incorrect minigame number %d", minigameNum);
break;
}
-
+
bool minigameResult = minigame->run(fromMainGame);
-
+
delete minigame;
// Check if the principal was hit with a megaloogie in the loogie minigame
@@ -1370,11 +1370,11 @@ void BbvsEngine::checkEasterEgg(char key) {
"SKCUS",
"NAMTAH"
};
-
+
static const int kEasterEggLengths[] = {
7, 5, 5, 6
};
-
+
if (_currSceneNum == kCredits) {
memcpy(&_easterEggInput[1], &_easterEggInput[0], 6);
_easterEggInput[0] = key;
diff --git a/engines/bbvs/bbvs.h b/engines/bbvs/bbvs.h
index 6a9a13905c..bbd8046a8b 100644
--- a/engines/bbvs/bbvs.h
+++ b/engines/bbvs/bbvs.h
@@ -149,7 +149,7 @@ struct BBPoint {
struct BBRect {
int16 x, y, width, height;
-};
+};
struct BBPolygon {
const BBPoint *points;
@@ -229,66 +229,66 @@ public:
private:
const ADGameDescription *_gameDescription;
Graphics::PixelFormat _pixelFormat;
-public:
+public:
Common::RandomSource *_random;
-
+
GameModule *_gameModule;
SpriteModule *_spriteModule;
SoundMan *_sound;
-
+
Screen *_screen;
-
+
int _bootSaveSlot;
-
+
int _mouseX, _mouseY;
uint _mouseButtons;
Common::KeyCode _keyCode;
-
+
int _mouseCursorSpriteIndex;
int _gameState;
int _gameTicks;
-
+
Common::Point _mousePos;
Common::Point _verbPos;
Common::Point _walkMousePos;
-
+
int _activeItemType;
int _activeItemIndex;
int _currTalkObjectIndex;
-
+
Common::Point _cameraPos, _newCameraPos;
-
+
int _newSceneNum, _prevSceneNum, _currSceneNum;
int _playVideoNumber;
-
+
int _dialogSlotCount;
byte _dialogItemStatus[kDialogItemStatusCount];
-
+
byte _gameVars[kGameVarsCount];
byte _sceneVisited[kSceneVisitedCount];
int _currVerbNum;
-
+
int _currInventoryItem;
byte _inventoryItemStatus[kInventoryItemStatusCount];
int _inventoryButtonIndex;
-
+
Action *_currAction;
uint32 _currActionCommandTimeStamp;
int _currActionCommandIndex;
-
+
Common::Array<Action*> _walkAreaActions;
-
+
SceneObject _sceneObjects[kSceneObjectsCount];
Common::Array<SceneObjectAction> _sceneObjectActions;
-
+
SceneObject *_buttheadObject, *_beavisObject;
int _currCameraNum;
-
+
byte _backgroundSoundsActive[kSceneSoundsCount];
Audio::SoundHandle _speechSoundHandle;
-
+
int _walkAreasCount;
WalkArea _walkAreas[80];
int _walkInfosCount;
@@ -298,40 +298,40 @@ public:
Common::Rect _tempWalkableRects1[256];
Common::Rect _tempWalkableRects2[256];
WalkInfo *_walkInfoPtrs[256];
-
+
WalkArea *_sourceWalkArea, *_destWalkArea;
Common::Point _sourceWalkAreaPt, _destWalkAreaPt, _finalWalkPt;
int _currWalkDistance;
bool _walkReachedDestArea;
-
+
bool _hasSnapshot;
byte *_snapshot;
Common::SeekableMemoryWriteStream *_snapshotStream;
-
+
char _easterEggInput[7];
-
+
void updateEvents();
int getRandom(int max);
void drawDebugInfo();
void drawScreen();
-
+
void updateGame();
bool evalCondition(Conditions &conditions);
bool evalCameraCondition(Conditions &conditions, int value);
int evalDialogCondition(Conditions &conditions);
void evalActionResults(ActionResults &results);
-
+
void updateBackgroundSounds();
void loadScene(int sceneNum);
void initScene(bool sounds);
- bool changeScene();
+ bool changeScene();
bool update(int mouseX, int mouseY, uint mouseButtons, Common::KeyCode keyCode);
-
+
void buildDrawList(DrawList &drawList);
-
+
void updateVerbs();
void updateDialog(bool clicked);
void updateInventory(bool clicked);
@@ -342,7 +342,7 @@ public:
void skipCurrAction();
void updateCommon();
-
+
void updateWalkableRects();
void startWalkObject(SceneObject *sceneObject);
void updateWalkObject(SceneObject *sceneObject);
@@ -360,20 +360,20 @@ public:
void walkFindPath(WalkArea *sourceWalkArea, int infoCount);
int calcDistance(const Common::Point &pt1, const Common::Point &pt2);
void walkFoundPath(int count);
-
+
void updateSceneObjectsTurnValue();
void updateDialogConditions();
-
- void playSpeech(int soundNum);
+
+ void playSpeech(int soundNum);
void stopSpeech();
-
+
void playSound(uint soundNum, bool loop = false);
void stopSound(uint soundNum);
void stopSounds();
-
+
bool runMinigame(int minigameNum);
void playVideo(int videoNum);
-
+
void runMainMenu();
void checkEasterEgg(char key);
@@ -409,13 +409,13 @@ public:
bool existsSavegame(int num);
static Common::String getSavegameFilename(const Common::String &target, int num);
static kReadSaveHeaderError readSaveHeader(Common::SeekableReadStream *in, bool loadThumbnail, SaveHeader &header);
-
+
void allocSnapshot();
void freeSnapshot();
void saveSnapshot();
-
+
void writeContinueSavegame();
-
+
};
} // End of namespace Bbvs
diff --git a/engines/bbvs/detection.cpp b/engines/bbvs/detection.cpp
index e7383163f5..3e247aad99 100644
--- a/engines/bbvs/detection.cpp
+++ b/engines/bbvs/detection.cpp
@@ -133,7 +133,7 @@ SaveStateDescriptor BbvsMetaEngine::querySaveMetaInfos(const char *target, int s
Bbvs::BbvsEngine::kReadSaveHeaderError error;
error = Bbvs::BbvsEngine::readSaveHeader(in, true, header);
delete in;
- if (error == Bbvs::BbvsEngine::kRSHENoError) {
+ if (error == Bbvs::BbvsEngine::kRSHENoError) {
SaveStateDescriptor desc(slot, header.description);
// Slot 0 is used for the "Continue" save
desc.setDeletableFlag(slot != 0);
diff --git a/engines/bbvs/dialogs.cpp b/engines/bbvs/dialogs.cpp
index 5247a58ec8..af95f06c1e 100644
--- a/engines/bbvs/dialogs.cpp
+++ b/engines/bbvs/dialogs.cpp
@@ -34,7 +34,7 @@ struct MenuButton {
static const MenuButton kMenuButtons[] = {
// Main menu
- {"New Game", kCmdNewGame},
+ {"New Game", kCmdNewGame},
{"Continue", kCmdContinue},
{"Options", kCmdOptions},
{"Mini Games", kCmdMiniGames},
@@ -61,7 +61,7 @@ MainMenu::~MainMenu() {
}
void MainMenu::init() {
- _buttons[0] = new GUI::ButtonWidget(this, 0, 0, 1, 1, "", 0, 0);
+ _buttons[0] = new GUI::ButtonWidget(this, 0, 0, 1, 1, "", 0, 0);
_buttons[1] = new GUI::ButtonWidget(this, 0, 0, 1, 1, "", 0, 0);
_buttons[2] = new GUI::ButtonWidget(this, 0, 0, 1, 1, "", 0, 0);
_buttons[3] = new GUI::ButtonWidget(this, 0, 0, 1, 1, "", 0, 0);
@@ -76,14 +76,14 @@ void MainMenu::reflowLayout() {
const int buttonWidth = screenW * 70 / 320;
const int buttonHeight = screenH * 14 / 240;
const int buttonPadding = screenW * 3 / 320;
-
+
_w = 2 * buttonWidth + buttonPadding;
_h = 3 * buttonHeight + 3 * buttonPadding;
_x = (screenW - _w) / 2;
_y = screenH - _h;
int x = 0, y = 0;
-
+
x = 0;
y = 0;
_buttons[0]->resize(x, y, buttonWidth, buttonHeight);
diff --git a/engines/bbvs/dialogs.h b/engines/bbvs/dialogs.h
index 2dce2a110b..7db0b182b7 100644
--- a/engines/bbvs/dialogs.h
+++ b/engines/bbvs/dialogs.h
@@ -67,13 +67,13 @@ protected:
BbvsEngine *_vm;
void init();
-
+
GUI::ButtonWidget *_buttons[5];
-
+
void gotoMenuScreen(int index);
bool canContinue();
void gotoScene(int sceneNum);
-
+
};
}
diff --git a/engines/bbvs/gamemodule.cpp b/engines/bbvs/gamemodule.cpp
index d6343084ab..80f0e81450 100644
--- a/engines/bbvs/gamemodule.cpp
+++ b/engines/bbvs/gamemodule.cpp
@@ -39,11 +39,11 @@ GameModule::~GameModule() {
void GameModule::load(const char *filename) {
debug(0, "GameModule::load()");
-
+
unload();
Common::File fd;
-
+
if (!fd.open(filename))
error("GameModule::load() Could not open %s", filename);
@@ -68,7 +68,7 @@ void GameModule::load(const char *filename) {
fd.seek(0x1A8);
_buttheadObjectIndex = fd.readUint32LE();
-
+
fd.close();
debug(0, "GameModule::load() OK");
@@ -177,7 +177,7 @@ int GameModule::getBgSpritePriority(int index) {
int GameModule::getSceneSoundsCount() {
return _sceneSoundsCount;
}
-
+
SceneSound *GameModule::getSceneSound(int index) {
assert(index < _sceneSoundsCount);
return &_sceneSounds[index];
@@ -257,7 +257,7 @@ void GameModule::unload() {
void GameModule::loadBgSprites(Common::SeekableReadStream &s) {
debug(0, "GameModule::loadBgSprites()");
-
+
s.seek(0x14);
_bgSpriteCount = s.readUint32LE();
uint32 bgSpriteIndicesOffs = s.readUint32LE();
@@ -275,7 +275,7 @@ void GameModule::loadBgSprites(Common::SeekableReadStream &s) {
void GameModule::loadCameraInits(Common::SeekableReadStream &s) {
debug(0, "GameModule::loadCameraInits()");
-
+
s.seek(0x20);
for (int i = 0; i < kCameraInitsCount; ++i) {
CameraInit &cameraInit = _cameraInits[i];
@@ -283,13 +283,13 @@ void GameModule::loadCameraInits(Common::SeekableReadStream &s) {
for (int j = 0; j < 8; ++j)
cameraInit.cameraLinks[j] = s.readByte();
for (int j = 0; j < 8; ++j)
- cameraInit.rects[j] = readRect(s);
+ cameraInit.rects[j] = readRect(s);
}
}
void GameModule::loadWalkRects(Common::SeekableReadStream &s) {
debug(0, "GameModule::loadWalkRects()");
-
+
s.seek(0x150);
_walkRectsCount = s.readUint32LE();
uint32 offs = s.readUint32LE();
@@ -301,7 +301,7 @@ void GameModule::loadWalkRects(Common::SeekableReadStream &s) {
void GameModule::loadSceneExits(Common::SeekableReadStream &s) {
debug(0, "GameModule::loadSceneExits()");
-
+
s.seek(0x158);
_sceneExitsCount = s.readUint32LE();
uint32 offs = s.readUint32LE();
@@ -329,13 +329,13 @@ void GameModule::loadBgObjects(Common::SeekableReadStream &s) {
void GameModule::loadAnimations(Common::SeekableReadStream &s) {
debug(0, "GameModule::loadAnimations()");
-
+
s.seek(0x168);
_animationsCount = s.readUint32LE();
uint32 offs = s.readUint32LE();
_animations = new Animation[_animationsCount];
for (int i = 0; i < _animationsCount; ++i) {
- Animation &anim = _animations[i];
+ Animation &anim = _animations[i];
s.seek(offs + i * 20);
anim.frameCount = s.readUint32LE();
uint32 frameSpriteIndicesOffs = s.readUint32LE();
@@ -363,7 +363,7 @@ void GameModule::loadAnimations(Common::SeekableReadStream &s) {
void GameModule::loadSceneObjectDefs(Common::SeekableReadStream &s) {
debug(0, "GameModule::loadSceneObjectDefs()");
-
+
s.seek(0x170);
_sceneObjectDefsCount = s.readUint32LE();
uint32 offs = s.readUint32LE();
@@ -379,7 +379,7 @@ void GameModule::loadSceneObjectDefs(Common::SeekableReadStream &s) {
void GameModule::loadSceneObjectInits(Common::SeekableReadStream &s) {
debug(0, "GameModule::loadSceneObjectInits()");
-
+
s.seek(0x178);
_sceneObjectInitsCount = s.readUint32LE();
uint32 offs = s.readUint32LE();
@@ -396,7 +396,7 @@ void GameModule::loadSceneObjectInits(Common::SeekableReadStream &s) {
void GameModule::loadActions(Common::SeekableReadStream &s) {
debug(0, "GameModule::loadActions()");
-
+
s.seek(0x180);
_actionsCount = s.readUint32LE();
uint32 offs = s.readUint32LE();
@@ -427,7 +427,7 @@ void GameModule::loadActions(Common::SeekableReadStream &s) {
void GameModule::loadGuiSpriteIndices(Common::SeekableReadStream &s) {
debug(0, "GameModule::loadGuiSpriteIndices()");
-
+
s.seek(0x188);
uint32 offs = s.readUint32LE();
s.seek(offs);
@@ -437,7 +437,7 @@ void GameModule::loadGuiSpriteIndices(Common::SeekableReadStream &s) {
void GameModule::loadInventoryItemSpriteIndices(Common::SeekableReadStream &s) {
debug(0, "GameModule::loadInventoryItemSpriteIndices()");
-
+
s.seek(0x18C);
uint32 offs = s.readUint32LE();
s.seek(offs);
@@ -447,7 +447,7 @@ void GameModule::loadInventoryItemSpriteIndices(Common::SeekableReadStream &s) {
void GameModule::loadInventoryItemInfos(Common::SeekableReadStream &s) {
debug(0, "GameModule::loadInventoryItemInfos()");
-
+
s.seek(0x190);
uint32 offs = s.readUint32LE();
s.seek(offs);
@@ -462,7 +462,7 @@ void GameModule::loadInventoryItemInfos(Common::SeekableReadStream &s) {
void GameModule::loadDialogItemSpriteIndices(Common::SeekableReadStream &s) {
debug(0, "GameModule::loadDialogItemSpriteIndices()");
-
+
s.seek(0x194);
uint32 offs = s.readUint32LE();
s.seek(offs);
@@ -473,7 +473,7 @@ void GameModule::loadDialogItemSpriteIndices(Common::SeekableReadStream &s) {
void GameModule::loadSceneSounds(Common::SeekableReadStream &s) {
debug(0, "GameModule::loadSceneSounds()");
-
+
s.seek(0x1A0);
_sceneSoundsCount = s.readUint32LE();
uint32 offs = s.readUint32LE();
@@ -487,7 +487,7 @@ void GameModule::loadSceneSounds(Common::SeekableReadStream &s) {
void GameModule::loadPreloadSounds(Common::SeekableReadStream &s) {
debug(0, "GameModule::loadPreloadSounds()");
-
+
s.seek(0x198);
_preloadSoundsCount = s.readUint32LE();
uint32 offs = s.readUint32LE();
diff --git a/engines/bbvs/gamemodule.h b/engines/bbvs/gamemodule.h
index 4d4f5b90a1..b31b95dcee 100644
--- a/engines/bbvs/gamemodule.h
+++ b/engines/bbvs/gamemodule.h
@@ -134,29 +134,29 @@ class GameModule {
public:
GameModule();
~GameModule();
-
+
void load(const char *filename);
-
+
int getFieldC();
int getButtheadObjectIndex();
-
+
int getGuiSpriteIndex(int index);
int getInventoryItemSpriteIndex(int index);
int getDialogItemSpriteIndex(int index);
-
+
int getActionsCount();
Action *getAction(int index);
-
+
InventoryItemInfo *getInventoryItemInfo(int index);
CameraInit *getCameraInit(int cameraNum);
-
+
int getSceneExitsCount();
SceneExit *getSceneExit(int index);
-
+
int getWalkRectsCount();
Common::Rect *getWalkRects();
-
+
int getSceneObjectDefsCount();
SceneObjectDef *getSceneObjectDef(int index);
@@ -170,44 +170,44 @@ public:
int getBgSpriteIndex(int index);
int getBgSpritePriority(int index);
- int getSceneSoundsCount();
+ int getSceneSoundsCount();
SceneSound *getSceneSound(int index);
- uint getSceneSoundIndex(uint soundNum);
-
+ uint getSceneSoundIndex(uint soundNum);
+
uint getPreloadSoundsCount();
uint getPreloadSound(uint index);
Animation *getAnimation(int index);
-
+
protected:
-
+
int _bgSpriteCount;
int *_bgSpriteIndices;
int16 *_bgSpritePriorities;
-
+
CameraInit _cameraInits[kCameraInitsCount];
-
+
int _walkRectsCount;
Common::Rect *_walkRects;
-
+
int _sceneExitsCount;
SceneExit *_sceneExits;
-
+
int _bgObjectsCount;
BgObject *_bgObjects;
-
+
int _animationsCount;
Animation *_animations;
-
+
int _sceneObjectDefsCount;
SceneObjectDef *_sceneObjectDefs;
-
+
int _sceneObjectInitsCount;
SceneObjectInit *_sceneObjectInits;
int _actionsCount;
Action *_actions;
-
+
int _sceneSoundsCount;
SceneSound *_sceneSounds;
@@ -218,16 +218,16 @@ protected:
int _inventoryItemSpriteIndices[kInventoryItemSpriteCount];
InventoryItemInfo _inventoryItemInfos[kInventoryItemCount];
int _dialogItemSpriteIndices[kDialogItemSpriteCount];
-
+
int _fieldC;
int _buttheadObjectIndex;
Common::Point readPoint(Common::SeekableReadStream &s);
Common::Rect readRect(Common::SeekableReadStream &s);
Conditions readConditions(Common::SeekableReadStream &s);
-
+
void unload();
-
+
void loadBgSprites(Common::SeekableReadStream &s);
void loadCameraInits(Common::SeekableReadStream &s);
void loadWalkRects(Common::SeekableReadStream &s);
@@ -243,7 +243,7 @@ protected:
void loadDialogItemSpriteIndices(Common::SeekableReadStream &s);
void loadSceneSounds(Common::SeekableReadStream &s);
void loadPreloadSounds(Common::SeekableReadStream &s);
-
+
};
} // End of namespace Bbvs
diff --git a/engines/bbvs/graphics.cpp b/engines/bbvs/graphics.cpp
index 810d910abf..43840607c8 100644
--- a/engines/bbvs/graphics.cpp
+++ b/engines/bbvs/graphics.cpp
@@ -104,9 +104,9 @@ void Screen::drawSprite(Sprite &sprite, int x, int y) {
}
if (destX + width >= _surface->w)
width = _surface->w - destX;
-
+
debug(0, "drawSprite() (%d, %d, %d, %d); skipX: %d; skipY: %d; %d", destX, destY, width, height, skipX, skipY, sprite.type);
-
+
if (sprite.type == 1) {
for (int yc = 0; yc < height; ++yc) {
byte *source = sprite.getRow(skipY + yc);
diff --git a/engines/bbvs/minigames/bbairguitar.cpp b/engines/bbvs/minigames/bbairguitar.cpp
index f2e42313e3..1984dbb0fd 100644
--- a/engines/bbvs/minigames/bbairguitar.cpp
+++ b/engines/bbvs/minigames/bbairguitar.cpp
@@ -198,12 +198,12 @@ void MinigameBbAirGuitar::buildDrawList1(DrawList &drawList) {
if (_trackBarX > kTrackBarMaxX)
_trackBarX = kTrackBarMaxX;
-
+
_trackBarThumbRect.top = 208;
_trackBarThumbRect.bottom = 218;
_trackBarThumbRect.left = _trackBarX;
_trackBarThumbRect.right = _trackBarX + 6;
-
+
drawList.add(_objects[5].anim->frameIndices[0], _trackBarX, 208, 100);
if (_playerMode != 0) {
@@ -228,7 +228,7 @@ void MinigameBbAirGuitar::buildDrawList1(DrawList &drawList) {
drawList.add(_objects[i].anim->frameIndices[frameIndex], kPointsTbl2[i - 47].x, kPointsTbl2[i - 47].y, 254);
}
}
-
+
if (_backgroundSpriteIndex > 0)
drawList.add(_backgroundSpriteIndex, 0, 0, 0);
@@ -394,7 +394,7 @@ void MinigameBbAirGuitar::initObjects1() {
_track[0].noteNum = -1;
stop();
changePatch(0);
-
+
}
bool MinigameBbAirGuitar::updateStatus(int mouseX, int mouseY, uint mouseButtons) {
@@ -408,7 +408,7 @@ bool MinigameBbAirGuitar::updateStatus(int mouseX, int mouseY, uint mouseButtons
}
bool MinigameBbAirGuitar::updateStatus0(int mouseX, int mouseY, uint mouseButtons) {
-
+
if (mouseButtons & kAnyButtonDown) {
stopSound(1);
_rockTunePlaying = false;
@@ -436,14 +436,14 @@ bool MinigameBbAirGuitar::updateStatus0(int mouseX, int mouseY, uint mouseButton
}
}
-
+
return true;
}
bool MinigameBbAirGuitar::updateStatus1(int mouseX, int mouseY, uint mouseButtons) {
-
+
int currTicks = _vm->_system->getMillis();
-
+
if (_playerMode == 1 && _track[_trackIndex].ticks <= currTicks - _noteStartTime) {
noteOff(_track[_trackIndex].noteNum);
if (_trackIndex < _trackCount && _track[++_trackIndex].noteNum != -1)
@@ -481,17 +481,17 @@ bool MinigameBbAirGuitar::updateStatus1(int mouseX, int mouseY, uint mouseButton
} else {
++_vuMeterRight2;
}
-
+
if (_resetAnims && _vm->_system->getMillis() - _noteStartTime >= 1000)
resetObjs();
-
+
_objects[0].x = mouseX;
_objects[0].y = mouseY;
-
+
_trackBarMouseX = CLIP(mouseX, kTrackBarMinX, kTrackBarMaxX);
-
+
bool checkClick = false;
-
+
if (mouseButtons & kAnyButtonClicked) {
checkClick = true;
} else if (!(mouseButtons & kAnyButtonDown)) {
@@ -506,14 +506,14 @@ bool MinigameBbAirGuitar::updateStatus1(int mouseX, int mouseY, uint mouseButton
}
} else if (!_movingTrackBar)
checkClick = true;
-
+
if (checkClick) {
afterButtonReleased();
_objects[0].frameIndex = 1;
-
+
if (ptInRect(&kRect2, mouseX, mouseY)) {
-
+
if (_playerMode != 1 && ptInRect(&kPianoRect, mouseX, mouseY)) {
for (int i = 0; i <= 12; ++i) {
if (ptInPoly(&kPianoKeyAreas[i], mouseX, mouseY)) {
@@ -538,7 +538,7 @@ bool MinigameBbAirGuitar::updateStatus1(int mouseX, int mouseY, uint mouseButton
break;
}
}
-
+
if (playerButtonNum >= 0) {
_currButtonNum = playerButtonNum;
_currPlayerButtonRect = &kPlayerButtonRects[playerButtonNum];
@@ -673,12 +673,12 @@ bool MinigameBbAirGuitar::updateStatus1(int mouseX, int mouseY, uint mouseButton
}
}
}
-
+
if (_buttonClickTicks + 1000 < currTicks)
_buttonClickTicks = currTicks;
-
+
int newKind = _buttonClickTicks + 500 < currTicks ? 1 : 0;
-
+
switch (_playerMode) {
case 1:
@@ -770,20 +770,20 @@ bool MinigameBbAirGuitar::run(bool fromMainGame) {
_gameResult = false;
_gameDone = false;
initObjects();
-
+
_spriteModule = new SpriteModule();
_spriteModule->load("bbairg/bbairg.000");
Palette palette = _spriteModule->getPalette();
_vm->_screen->setPalette(palette);
-
+
loadSounds();
-
+
while (!_vm->shouldQuit() &&!_gameDone) {
_vm->updateEvents();
update();
}
-
+
_vm->_sound->unloadSounds();
delete _spriteModule;
@@ -803,15 +803,15 @@ void MinigameBbAirGuitar::update() {
inputTicks = 1;
_gameTicks = _vm->_system->getMillis();
}
-
+
if (_vm->_keyCode == Common::KEYCODE_ESCAPE) {
_gameDone = true;
return;
}
-
+
if (inputTicks == 0)
return;
-
+
bool done;
do {
@@ -820,9 +820,9 @@ void MinigameBbAirGuitar::update() {
_vm->_mouseButtons &= ~kRightButtonClicked;
_vm->_keyCode = Common::KEYCODE_INVALID;
} while (--inputTicks && _gameTicks > 0 && !done);
-
+
drawSprites();
-
+
_vm->_system->delayMillis(10);
}
@@ -1001,7 +1001,7 @@ void MinigameBbAirGuitar::calcTotalTicks1() {
}
void MinigameBbAirGuitar::noteOn(int noteNum) {
-
+
if (_currNoteNum != -2) {
if (noteNum == _currNoteNum)
return;
@@ -1087,7 +1087,7 @@ void MinigameBbAirGuitar::noteOn(int noteNum) {
}
void MinigameBbAirGuitar::noteOff(int noteNum) {
-
+
if (_currNoteNum != noteNum)
return;
diff --git a/engines/bbvs/minigames/bbairguitar.h b/engines/bbvs/minigames/bbairguitar.h
index d4fd6ec30c..40b8a50a03 100644
--- a/engines/bbvs/minigames/bbairguitar.h
+++ b/engines/bbvs/minigames/bbairguitar.h
@@ -32,7 +32,7 @@ public:
MinigameBbAirGuitar(BbvsEngine *vm) : Minigame(vm) {};
bool run(bool fromMainGame);
public:
-
+
struct Obj {
int kind;
int x, y;
@@ -44,24 +44,24 @@ public:
int16 frameIndexAdd;
int16 unk2;
};
-
+
enum {
kMaxObjectsCount = 256,
kMaxTracks = 2049
};
-
+
struct PianoKeyInfo {
int x, y;
int frameIndex;
};
-
+
struct TrackEvt {
int8 noteNum;
int16 ticks;
};
-
+
Obj _objects[kMaxObjectsCount];
-
+
int _playerMode;
bool _modified;
@@ -82,24 +82,24 @@ public:
int *_currFrameIndex;
int _btn3KindToggle;
-
+
const BBPolygon *_currPianoKeyArea;
const Rect *_currPlayerButtonRect;
-
+
bool _movingTrackBar;
int _trackBarMouseX;
int _trackBarX;
Rect _trackBarThumbRect;
-
+
int _currTrackPos, _totalTrackLength;
int _ticksDelta;
-
+
int _actionStartTrackPos, _actionTrackPos;
int _actionStartTime;
int _currNoteNum;
int _currPatchNum;
-
+
const ObjAnimation *getAnimation(int animIndex);
bool ptInRect(const Rect *r, int x, int y);
bool ptInPoly(const BBPolygon *poly, int x, int y);
@@ -109,14 +109,14 @@ public:
void buildDrawList1(DrawList &drawList);
void drawSprites();
-
+
void initObjs();
Obj *getFreeObject();
-
+
void initObjects();
void initObjects0();
void initObjects1();
-
+
bool updateStatus(int mouseX, int mouseY, uint mouseButtons);
bool updateStatus0(int mouseX, int mouseY, uint mouseButtons);
bool updateStatus1(int mouseX, int mouseY, uint mouseButtons);
@@ -124,7 +124,7 @@ public:
void updateObjs();
void update();
-
+
void play();
void record();
void setPlayerMode3();
@@ -136,9 +136,9 @@ public:
void noteOn(int noteNum);
void noteOff(int noteNum);
void resetObjs();
-
+
void loadSounds();
- void playNote(int noteNum);
+ void playNote(int noteNum);
void stopNote(int noteNum);
};
diff --git a/engines/bbvs/minigames/bbant.cpp b/engines/bbvs/minigames/bbant.cpp
index 9786682ada..3678934345 100644
--- a/engines/bbvs/minigames/bbant.cpp
+++ b/engines/bbvs/minigames/bbant.cpp
@@ -94,7 +94,7 @@ void MinigameBbAnt::buildDrawList1(DrawList &drawList) {
drawNumber(drawList, _score, 68, 16);
drawList.add(getAnimation(166)->frameIndices[0], 230, 2, 2000);
drawNumber(drawList, _levelTimeLeft, 280, 16);
-
+
for (int i = 0; i < _stompCount; ++i)
drawList.add(getAnimation(130)->frameIndices[0], 20 + i * 30, 230, 2000);
@@ -116,7 +116,7 @@ void MinigameBbAnt::buildDrawList3(DrawList &drawList) {
drawNumber(drawList, _hiScore, 208, 107);
}
-void MinigameBbAnt::drawMagnifyingGlass(DrawList &drawList) {
+void MinigameBbAnt::drawMagnifyingGlass(DrawList &drawList) {
scale2x(_objects[0].x - 28, _objects[0].y - 27);
drawList.clear();
drawList.add(_objects[0].anim->frameIndices[0], _objects[0].x, _objects[0].y, _objects[0].priority);
@@ -358,7 +358,7 @@ bool MinigameBbAnt::updateStatus0(int mouseX, int mouseY, uint mouseButtons) {
_objects[0].x = 0;
if (_objects[0].y < 0)
_objects[0].y = 0;
-
+
if ((mouseButtons & kLeftButtonDown) || (mouseButtons & kRightButtonDown)) {
_gameState = 1;
initObjects();
@@ -447,7 +447,7 @@ bool MinigameBbAnt::updateStatus1(int mouseX, int mouseY, uint mouseButtons) {
int maxKindCount = 0, objKind = 0;
_stompCounter2 = _stompCounter1;
-
+
for (int i = 0; i < 4; ++i)
testTbl[i] = _vm->getRandom(_bugsChanceByKind[i] - _bugsCountByKind[i]);
@@ -471,7 +471,7 @@ bool MinigameBbAnt::updateStatus1(int mouseX, int mouseY, uint mouseButtons) {
if (_stompCounter1 > 20)
--_stompCounter1;
}
-
+
return true;
}
@@ -701,7 +701,7 @@ void MinigameBbAnt::updateBugObjAnim(int objIndex) {
void MinigameBbAnt::updateObjAnim2(int objIndex) {
Obj *obj = &_objects[objIndex];
-
+
obj->animIndexIncr += _vm->getRandom(3) - 1;
if (obj->animIndexIncr < 0)
obj->animIndexIncr = 7;
@@ -736,7 +736,7 @@ bool MinigameBbAnt::isBugOutOfScreen(int objIndex) {
void MinigameBbAnt::updateObjAnim3(int objIndex) {
Obj *obj = &_objects[objIndex];
-
+
obj->animIndexIncr += _vm->getRandom(3) - 1;
if (obj->animIndexIncr < 0)
obj->animIndexIncr = 7;
@@ -752,7 +752,7 @@ void MinigameBbAnt::updateBugObj1(int objIndex) {
Obj *obj = &_objects[objIndex];
bool flag1 = false;
bool flag2 = false;
-
+
if (--obj->ticks == 0) {
++obj->frameIndex;
if (obj->anim->frameCount == obj->frameIndex) {
@@ -911,7 +911,7 @@ void MinigameBbAnt::updateStompObj(int objIndex) {
void MinigameBbAnt::updateSmokeObj(int objIndex) {
Obj *obj = &_objects[objIndex];
-
+
obj->x += obj->xIncr;
obj->y += obj->yIncr;
@@ -1047,7 +1047,7 @@ bool MinigameBbAnt::isMagGlassAtBug(int objIndex) {
Obj *obj = &_objects[objIndex];
Obj *obj0 = &_objects[0];
bool result = false;
-
+
if (obj->kind >= 1 && obj->kind <= 5) {
const BBRect &frameRect1 = obj0->anim->frameRects[0];
const int obj1X1 = obj0->x + frameRect1.x;
@@ -1102,7 +1102,7 @@ bool MinigameBbAnt::testObj5(int objIndex) {
}
void MinigameBbAnt::updateObjs(uint mouseButtons) {
-
+
for (int i = 12; i < kMaxObjectsCount; ++i) {
Obj *obj = &_objects[i];
@@ -1162,7 +1162,7 @@ void MinigameBbAnt::updateObjs(uint mouseButtons) {
}
}
-
+
}
}
@@ -1170,9 +1170,9 @@ void MinigameBbAnt::updateObjs(uint mouseButtons) {
bool MinigameBbAnt::run(bool fromMainGame) {
memset(_objects, 0, sizeof(_objects));
-
+
_numbersAnim = getAnimation(167);
-
+
_backgroundSpriteIndex = 303;
_titleScreenSpriteIndex = 304;
@@ -1187,23 +1187,23 @@ bool MinigameBbAnt::run(bool fromMainGame) {
_gameDone = false;
initObjects();
initVars();
-
+
_spriteModule = new SpriteModule();
_spriteModule->load("bbant/bbant.000");
Palette palette = _spriteModule->getPalette();
_vm->_screen->setPalette(palette);
-
+
loadSounds();
_gameTicks = 0;
playSound(12, true);
-
+
while (!_vm->shouldQuit() &&!_gameDone) {
_vm->updateEvents();
update();
}
-
+
_vm->_sound->unloadSounds();
if (!_fromMainGame)
@@ -1243,19 +1243,19 @@ void MinigameBbAnt::update() {
_vm->_mouseButtons &= ~kRightButtonClicked;
_vm->_keyCode = Common::KEYCODE_INVALID;
} while (--inputTicks && _gameTicks > 0 && !done);
-
+
drawSprites();
-
+
_vm->_system->delayMillis(10);
}
void MinigameBbAnt::scale2x(int x, int y) {
- Graphics::Surface *surface = _vm->_screen->_surface;
-
+ Graphics::Surface *surface = _vm->_screen->_surface;
+
int srcX = x + 14, srcY = y + 14;
int srcW = kScaleDim, srcH = kScaleDim;
-
+
if (srcX < 0) {
srcW += srcX;
srcX = 0;
@@ -1265,21 +1265,21 @@ void MinigameBbAnt::scale2x(int x, int y) {
srcH += srcY;
srcY = 0;
}
-
+
if (srcX + srcW >= 320)
srcW = 320 - srcX - 1;
-
+
if (srcY + srcH >= 240)
srcH = 240 - srcY - 1;
-
+
for (int yc = 0; yc < srcH; ++yc) {
byte *src = (byte*)surface->getBasePtr(srcX, srcY + yc);
memcpy(&_scaleBuf[yc * kScaleDim], src, srcW);
}
-
+
int dstX = x, dstY = y;
int dstW = 2 * kScaleDim, dstH = 2 * kScaleDim;
-
+
if (dstX < 0) {
dstW += dstX;
dstX = 0;
@@ -1289,15 +1289,15 @@ void MinigameBbAnt::scale2x(int x, int y) {
dstH += dstY;
dstY = 0;
}
-
+
if (dstX + dstW >= 320)
dstW = 320 - dstX - 1;
-
+
if (dstY + dstH >= 240)
dstH = 240 - dstY - 1;
-
+
int w = MIN(srcW * 2, dstW), h = MIN(srcH * 2, dstH);
-
+
for (int yc = 0; yc < h; ++yc) {
byte *src = _scaleBuf + kScaleDim * (yc / 2);
byte *dst = (byte*)surface->getBasePtr(dstX, dstY + yc);
diff --git a/engines/bbvs/minigames/bbant.h b/engines/bbvs/minigames/bbant.h
index be2afe688d..88b4af9c71 100644
--- a/engines/bbvs/minigames/bbant.h
+++ b/engines/bbvs/minigames/bbant.h
@@ -32,7 +32,7 @@ public:
MinigameBbAnt(BbvsEngine *vm) : Minigame(vm) {};
bool run(bool fromMainGame);
public:
-
+
struct Obj {
int kind;
int x, y, priority;
@@ -55,21 +55,21 @@ public:
int status2;
int flag;
};
-
+
enum {
kMaxObjectsCount = 256,
kScaleDim = 28
};
-
+
struct ObjInit {
const ObjAnimation *anim1;
const ObjAnimation *anim2;
const ObjAnimation *anim3;
int x, y;
};
-
+
Obj _objects[kMaxObjectsCount];
-
+
int _score, _hiScore;
int _totalBugsCount;
@@ -96,37 +96,37 @@ public:
int _countdown6;
int _countdown5;
int _countdown7;
-
+
byte _scaleBuf[kScaleDim * kScaleDim];
const ObjAnimation *getAnimation(int animIndex);
const ObjInit *getObjInit(int index);
const ObjAnimation * const *getObjKindAnimTable(int kind);
const ObjAnimation *getObjAnim(int index);
-
+
void buildDrawList0(DrawList &drawList);
void buildDrawList1(DrawList &drawList);
void buildDrawList2(DrawList &drawList);
void buildDrawList3(DrawList &drawList);
void drawMagnifyingGlass(DrawList &drawList);
-
+
void drawSprites();
void drawSprites0();
void drawSprites1();
void drawSprites2();
void drawSprites3();
-
+
Obj *getFreeObject();
-
+
void initObjects();
void initObjects0();
void initObjects1();
-
+
void initVars();
void initVars1();
void initVars2();
void initVars3();
-
+
bool updateStatus(int mouseX, int mouseY, uint mouseButtons);
bool updateStatus0(int mouseX, int mouseY, uint mouseButtons);
bool updateStatus1(int mouseX, int mouseY, uint mouseButtons);
@@ -161,7 +161,7 @@ public:
void updateObjs(uint mouseButtons);
void update();
-
+
void scale2x(int x, int y);
void loadSounds();
diff --git a/engines/bbvs/minigames/bbloogie.cpp b/engines/bbvs/minigames/bbloogie.cpp
index 4601e9ff93..68a3147f9a 100644
--- a/engines/bbvs/minigames/bbloogie.cpp
+++ b/engines/bbvs/minigames/bbloogie.cpp
@@ -117,7 +117,7 @@ void MinigameBbLoogie::buildDrawList0(DrawList &drawList) {
}
void MinigameBbLoogie::buildDrawList1(DrawList &drawList) {
-
+
for (int i = 0; i < kMaxObjectsCount; ++i) {
Obj *obj = &_objects[i];
switch (obj->kind) {
@@ -163,7 +163,7 @@ void MinigameBbLoogie::buildDrawList1(DrawList &drawList) {
}
void MinigameBbLoogie::buildDrawList2(DrawList &drawList) {
-
+
buildDrawList1(drawList);
if (_level > 0 && (_bonusDisplayDelay1 > 0 || _bonusDisplayDelay2 > 0)) {
@@ -180,7 +180,7 @@ void MinigameBbLoogie::buildDrawList2(DrawList &drawList) {
}
void MinigameBbLoogie::buildDrawList3(DrawList &drawList) {
-
+
for (int i = 0; i < kMaxObjectsCount; ++i) {
Obj *obj = &_objects[i];
if (obj->kind == 2)
@@ -191,7 +191,7 @@ void MinigameBbLoogie::buildDrawList3(DrawList &drawList) {
if (_backgroundSpriteIndex)
drawList.add(_backgroundSpriteIndex, 0, 0, 0);
-
+
drawList.add(getAnimation(10)->frameIndices[0], 230, 2, 2000);
drawNumber(drawList, _levelTimeLeft, 280, 16);
@@ -201,7 +201,7 @@ void MinigameBbLoogie::buildDrawList3(DrawList &drawList) {
int numberX2 = drawNumber(drawList, _currScore, 68, 16);
drawList.add(getAnimation(9)->frameIndices[10], numberX2, 16, 2000);
drawNumber(drawList, _dispLevelScore, numberX2 + 10, 16);
-
+
drawList.add(getAnimation(20)->frameIndices[0], 120, 70, 2000);
drawList.add(getAnimation(13)->frameIndices[0], 95, 95, 2000);
@@ -416,7 +416,7 @@ bool MinigameBbLoogie::updateStatus(int mouseX, int mouseY, uint mouseButtons) {
}
bool MinigameBbLoogie::updateStatus0(int mouseX, int mouseY, uint mouseButtons) {
-
+
_objects[0].x = mouseX;
_objects[0].y = mouseY;
@@ -445,7 +445,7 @@ bool MinigameBbLoogie::updateStatus0(int mouseX, int mouseY, uint mouseButtons)
_objects[4].kind = 0;
_objects[2].kind = 1;
}
-
+
for (int i = 0; i < kMaxObjectsCount; ++i) {
Obj *obj = &_objects[i];
if (obj->kind == 11) {
@@ -487,12 +487,12 @@ bool MinigameBbLoogie::updateStatus0(int mouseX, int mouseY, uint mouseButtons)
initVars();
_gameTicks = 0;
}
-
+
return true;
}
bool MinigameBbLoogie::updateStatus1(int mouseX, int mouseY, uint mouseButtons) {
-
+
if (--_levelTimeDelay == 0) {
_levelTimeDelay = 58;
--_levelTimeLeft;
@@ -568,9 +568,9 @@ bool MinigameBbLoogie::updateStatus2(int mouseX, int mouseY, uint mouseButtons)
}
bool MinigameBbLoogie::updateStatus3(int mouseX, int mouseY, uint mouseButtons) {
-
+
_objects[0].x = mouseX;
-
+
for (int i = 0; i < kMaxObjectsCount; ++i) {
Obj *obj = &_objects[i];
if (obj->kind == 2) {
@@ -582,7 +582,7 @@ bool MinigameBbLoogie::updateStatus3(int mouseX, int mouseY, uint mouseButtons)
}
}
}
-
+
return true;
}
@@ -620,7 +620,7 @@ void MinigameBbLoogie::updateObjs(uint mouseButtons) {
break;
}
}
-
+
if (--_carDelay == 0) {
// Car
Obj *obj = getFreeObject();
@@ -633,7 +633,7 @@ void MinigameBbLoogie::updateObjs(uint mouseButtons) {
obj->yIncr = 0;
_carDelay = _vm->getRandom(256) + 800;
}
-
+
if (--_bikeDelay == 0) {
// Bike
Obj *obj = getFreeObject();
@@ -646,7 +646,7 @@ void MinigameBbLoogie::updateObjs(uint mouseButtons) {
obj->yIncr = 0;
_bikeDelay = _vm->getRandom(512) + 500;
}
-
+
if (--_squirrelDelay == 0) {
// Squirrel
Obj *obj = getFreeObject();
@@ -662,7 +662,7 @@ void MinigameBbLoogie::updateObjs(uint mouseButtons) {
playSound(9);
_squirrelDelay = _vm->getRandom(512) + 300;
}
-
+
if (--_paperPlaneDelay == 0) {
// Paper plane
Obj *obj = getFreeObject();
@@ -685,7 +685,7 @@ void MinigameBbLoogie::updateObjs(uint mouseButtons) {
}
_paperPlaneDelay = 400;
}
-
+
if (_principalDelay >= 0 && --_principalDelay == 0) {
// Principal
Obj *obj = getFreeObject();
@@ -703,13 +703,13 @@ void MinigameBbLoogie::updateObjs(uint mouseButtons) {
_principalFirstFrameIndex = 11;
_principalLastFrameIndex = 16;
}
-
+
}
void MinigameBbLoogie::updatePlayer(int objIndex, uint mouseButtons) {
Obj *obj = &_objects[0];
-
+
switch (obj->status) {
case 1:
@@ -817,7 +817,7 @@ void MinigameBbLoogie::updateLoogie(int objIndex) {
obj->y -= kLoogieOffY[obj->unk2 / 8];
--obj->unk2;
}
-
+
if (obj->ticks-- == 0) {
obj->ticks = getAnimation(5)->frameTicks[0];
++obj->frameIndex;
@@ -832,9 +832,9 @@ void MinigameBbLoogie::updateLoogie(int objIndex) {
void MinigameBbLoogie::updateCar(int objIndex) {
Obj *obj = &_objects[objIndex];
-
+
obj->x += obj->xIncr;
-
+
if (obj->ticks-- == 0) {
if (obj->frameIndex++ == 3 || obj->frameIndex == 6)
obj->frameIndex = 0;
@@ -867,7 +867,7 @@ void MinigameBbLoogie::updateCar(int objIndex) {
void MinigameBbLoogie::updateBike(int objIndex) {
Obj *obj = &_objects[objIndex];
-
+
obj->x += obj->xIncr;
if (obj->ticks-- == 0) {
@@ -965,7 +965,7 @@ void MinigameBbLoogie::updatePaperPlane(int objIndex) {
loogieObj = findLoogieObj(loogieObjIndex++);
}
}
-
+
}
void MinigameBbLoogie::updateIndicator(int objIndex) {
@@ -995,7 +995,7 @@ void MinigameBbLoogie::updateIndicator(int objIndex) {
obj->kind = 0;
obj->anim = getAnimation(6);
}
-
+
}
void MinigameBbLoogie::updatePrincipal(int objIndex) {
@@ -1281,22 +1281,22 @@ bool MinigameBbLoogie::run(bool fromMainGame) {
_gameDone = false;
initObjects();
initVars();
-
+
_spriteModule = new SpriteModule();
_spriteModule->load("bbloogie/bbloogie.000");
Palette palette = _spriteModule->getPalette();
_vm->_screen->setPalette(palette);
-
+
loadSounds();
playSound(32, true);
-
+
while (!_vm->shouldQuit() &&!_gameDone) {
_vm->updateEvents();
update();
}
-
+
_vm->_sound->unloadSounds();
if (!_fromMainGame)
@@ -1319,15 +1319,15 @@ void MinigameBbLoogie::update() {
inputTicks = 1;
_gameTicks = _vm->_system->getMillis();
}
-
+
if (_vm->_keyCode == Common::KEYCODE_ESCAPE) {
_gameDone = true;
return;
}
-
+
if (inputTicks == 0)
return;
-
+
bool done;
do {
@@ -1336,9 +1336,9 @@ void MinigameBbLoogie::update() {
_vm->_mouseButtons &= ~kRightButtonClicked;
_vm->_keyCode = Common::KEYCODE_INVALID;
} while (--inputTicks && _gameTicks > 0 && !done);
-
+
drawSprites();
-
+
_vm->_system->delayMillis(10);
}
diff --git a/engines/bbvs/minigames/bbloogie.h b/engines/bbvs/minigames/bbloogie.h
index 1dd4049b41..04ead51a1e 100644
--- a/engines/bbvs/minigames/bbloogie.h
+++ b/engines/bbvs/minigames/bbloogie.h
@@ -32,7 +32,7 @@ public:
MinigameBbLoogie(BbvsEngine *vm) : Minigame(vm) {};
bool run(bool fromMainGame);
public:
-
+
struct Obj {
int kind;
int x, y;
@@ -44,33 +44,33 @@ public:
int16 frameIndexAdd;
int16 unk2;
};
-
+
enum {
kMaxObjectsCount = 256
};
-
+
enum {
kGSTitleScreen = 0, // Title screen
kGSMainGame = 1, // Game when called as part of the main game
kGSStandaloneGame = 2, // Game when called as standalone game
kGSScoreCountUp = 3 // Score countup and next level text
};
-
+
Obj _objects[kMaxObjectsCount];
-
+
int _playerKind;
const ObjAnimation *_playerAnim;
const uint *_playerSounds1, *_playerSounds2;
uint _playerSounds1Count, _playerSounds2Count;
-
+
int _level, _levelTimeLeft, _levelTimeDelay;
- int _numberOfHits, _currScore, _hiScore;
+ int _numberOfHits, _currScore, _hiScore;
int _doubleScore, _megaLoogieCount;
-
+
int _dispLevelScore, _nextLevelScore;
int _timeBonusCtr, _bonusDisplayDelay1, _bonusDisplayDelay2, _bonusDisplayDelay3;
-
+
int _carDelay;
int _bikeDelay;
int _squirrelDelay;
@@ -78,37 +78,37 @@ public:
int _paperPlaneDelay;
int _principalDelay;
- int _prevPrincipalStatus;
+ int _prevPrincipalStatus;
int _principalCtr, _principalFirstFrameIndex, _principalLastFrameIndex;
bool _principalAngry;
-
+
const ObjAnimation *getAnimation(int animIndex);
-
+
void buildDrawList(DrawList &drawList);
void buildDrawList0(DrawList &drawList);
void buildDrawList1(DrawList &drawList);
void buildDrawList2(DrawList &drawList);
void buildDrawList3(DrawList &drawList);
-
+
void drawSprites();
-
+
void initObjs();
Obj *getFreeObject();
Obj *findLoogieObj(int startObjIndex);
bool isHit(Obj *obj1, Obj *obj2);
bool isCursorAtObj(int objIndex);
-
+
void initObjects();
void initObjects0();
void initObjects1();
void initObjects3();
-
+
void initVars();
void initVars0();
void initVars1();
void initVars2();
void initVars3();
-
+
bool updateStatus(int mouseX, int mouseY, uint mouseButtons);
bool updateStatus0(int mouseX, int mouseY, uint mouseButtons);
bool updateStatus1(int mouseX, int mouseY, uint mouseButtons);
@@ -129,7 +129,7 @@ public:
void incNumberOfHits();
void incScore(int incrAmount);
void playRndSound();
-
+
void update();
void loadSounds();
diff --git a/engines/bbvs/minigames/bbtennis.cpp b/engines/bbvs/minigames/bbtennis.cpp
index ddd5cfc804..7763548330 100644
--- a/engines/bbvs/minigames/bbtennis.cpp
+++ b/engines/bbvs/minigames/bbtennis.cpp
@@ -86,7 +86,7 @@ void MinigameBbTennis::buildDrawList(DrawList &drawList) {
}
void MinigameBbTennis::buildDrawList0(DrawList &drawList) {
-
+
drawList.add(_objects[0].anim->frameIndices[_objects[0].frameIndex], _objects[0].x, _objects[0].y, 2000);
for (int i = 0; i < kMaxObjectsCount; ++i) {
@@ -154,7 +154,7 @@ void MinigameBbTennis::buildDrawList1(DrawList &drawList) {
break;
}
-
+
drawList.add(index, x, y, priority);
}
@@ -174,16 +174,16 @@ void MinigameBbTennis::buildDrawList1(DrawList &drawList) {
drawList.add(getAnimation(9)->frameIndices[0], 256, 52, 500);
drawList.add(getAnimation(10)->frameIndices[0], 60, 162, 500);
drawList.add(getAnimation(21)->frameIndices[0], 36, 18, 2000);
-
+
drawNumber(drawList, _score, 70, 18);
-
+
for (int i = 0; i < _numHearts; ++i)
drawList.add(getAnimation(7)->frameIndices[0], 20 + i * 20, 236, 990);
}
void MinigameBbTennis::buildDrawList2(DrawList &drawList) {
-
+
for (int i = 0; i < kMaxObjectsCount; ++i) {
Obj *obj = &_objects[i];
if (obj->kind)
@@ -384,7 +384,7 @@ bool MinigameBbTennis::updateStatus1(int mouseX, int mouseY, uint mouseButtons)
_objects[0].x = mouseX;
_objects[0].y = mouseY;
-
+
if (_allHeartsGone) {
_gameState = 2;
initObjects();
@@ -427,13 +427,13 @@ bool MinigameBbTennis::updateStatus1(int mouseX, int mouseY, uint mouseButtons)
if (_newBallTimer > 0)
--_newBallTimer;
-
+
if (++_delayDecreaseTimer == 30) {
_delayDecreaseTimer = 0;
if (_playerDecrease < 199)
++_playerDecrease;
}
-
+
updateObjs();
if (!_playedThisIsTheCoolest && _score > 3 && _vm->getRandom(10) == 1 && !isAnySoundPlaying(kAllSounds, 11)) {
@@ -482,7 +482,7 @@ void MinigameBbTennis::updateObjs() {
break;
}
}
-
+
if (_rapidFireBallsCount == 0) {
--_squirrelDelay;
if (--_squirrelDelay == 0) {
@@ -763,7 +763,7 @@ void MinigameBbTennis::updateTennisPlayer(int objIndex) {
}
++_tennisPlayerDelay;
break;
-
+
case 2:
if (--obj->ticks == 0) {
++obj->frameIndex;
@@ -1077,7 +1077,7 @@ void MinigameBbTennis::updateNetPlayer(int objIndex) {
void MinigameBbTennis::updateEnemyTennisBall(int objIndex) {
Obj *obj = &_objects[objIndex];
-
+
if (--obj->ticks == 0) {
--obj->frameIndex;
obj->ticks = getAnimation(6)->frameTicks[obj->frameIndex];
@@ -1103,7 +1103,7 @@ void MinigameBbTennis::updateEnemyTennisBall(int objIndex) {
obj->x = (int)obj->fltX;
obj->fltY = obj->fltY - obj->fltStepY;
obj->y = (int)obj->fltY;
-
+
}
void MinigameBbTennis::makeEnemyBall(int x, int y, int frameIndex) {
@@ -1184,7 +1184,7 @@ void MinigameBbTennis::hitSomething() {
bool MinigameBbTennis::run(bool fromMainGame) {
memset(_objects, 0, sizeof(_objects));
-
+
_numbersAnim = getAnimation(20);
_backgroundSpriteIndex = 272;
@@ -1201,23 +1201,23 @@ bool MinigameBbTennis::run(bool fromMainGame) {
_gameDone = false;
initObjects();
initVars();
-
+
_spriteModule = new SpriteModule();
_spriteModule->load("bbtennis/bbtennis.000");
Palette palette = _spriteModule->getPalette();
_vm->_screen->setPalette(palette);
-
+
loadSounds();
_gameTicks = 0;
playSound(29, true);
-
+
while (!_vm->shouldQuit() &&!_gameDone) {
_vm->updateEvents();
update();
}
-
+
_vm->_sound->unloadSounds();
if (!_fromMainGame)
@@ -1240,15 +1240,15 @@ void MinigameBbTennis::update() {
inputTicks = 1;
_gameTicks = _vm->_system->getMillis();
}
-
+
if (_vm->_keyCode == Common::KEYCODE_ESCAPE) {
_gameDone = true;
return;
}
-
+
if (inputTicks == 0)
return;
-
+
bool done;
do {
@@ -1257,9 +1257,9 @@ void MinigameBbTennis::update() {
_vm->_mouseButtons &= ~kRightButtonClicked;
_vm->_keyCode = Common::KEYCODE_INVALID;
} while (--inputTicks && _gameTicks > 0 && !done);
-
+
drawSprites();
-
+
_vm->_system->delayMillis(10);
}
diff --git a/engines/bbvs/minigames/bbtennis.h b/engines/bbvs/minigames/bbtennis.h
index 690bd724a0..7eac904c4d 100644
--- a/engines/bbvs/minigames/bbtennis.h
+++ b/engines/bbvs/minigames/bbtennis.h
@@ -32,7 +32,7 @@ public:
MinigameBbTennis(BbvsEngine *vm) : Minigame(vm) {};
bool run(bool fromMainGame);
public:
-
+
struct Obj {
int kind;
int x, y;
@@ -51,20 +51,20 @@ public:
int ballStepCtr;
int netPlayDirection;
};
-
+
enum {
kMaxObjectsCount = 256
};
-
+
enum {
kGSTitleScreen = 0, // Title screen
kGSMainGame = 1, // Game when called as part of the main game
kGSStandaloneGame = 2, // Game when called as standalone game
kGSScoreCountUp = 3 // Score countup and next level text
};
-
+
Obj _objects[kMaxObjectsCount];
-
+
int _numHearts;
int _squirrelDelay;
int _tennisPlayerDelay;
@@ -85,29 +85,29 @@ public:
bool _endSoundPlaying;
const ObjAnimation *getAnimation(int animIndex);
-
+
void buildDrawList(DrawList &drawList);
void buildDrawList0(DrawList &drawList);
void buildDrawList1(DrawList &drawList);
void buildDrawList2(DrawList &drawList);
-
+
void drawSprites();
-
+
void initObjs();
Obj *getFreeObject();
Obj *findTennisBall(int startObjIndex);
bool isHit(Obj *obj1, Obj *obj2);
-
+
void initObjects();
void initObjects0();
void initObjects1();
void initObjects2();
-
+
void initVars();
void initVars0();
void initVars1();
void initVars2();
-
+
bool updateStatus(int mouseX, int mouseY, uint mouseButtons);
bool updateStatus0(int mouseX, int mouseY, uint mouseButtons);
bool updateStatus1(int mouseX, int mouseY, uint mouseButtons);
diff --git a/engines/bbvs/minigames/minigame.cpp b/engines/bbvs/minigames/minigame.cpp
index aae18072d9..58d98a9df8 100644
--- a/engines/bbvs/minigames/minigame.cpp
+++ b/engines/bbvs/minigames/minigame.cpp
@@ -44,13 +44,13 @@ Minigame::~Minigame() {
int Minigame::drawNumber(DrawList &drawList, int number, int x, int y) {
int digits = 1, rightX = x;
-
+
for (int mag = 10; number / mag != 0; mag *= 10)
++digits;
-
+
rightX = x + digits * 10;
x = rightX;
-
+
while (digits--) {
const int n = number % 10;
x -= 10;
diff --git a/engines/bbvs/minigames/minigame.h b/engines/bbvs/minigames/minigame.h
index 675dec360d..1c24110519 100644
--- a/engines/bbvs/minigames/minigame.h
+++ b/engines/bbvs/minigames/minigame.h
@@ -51,30 +51,30 @@ public:
virtual ~Minigame();
virtual bool run(bool fromMainGame) = 0;
protected:
- BbvsEngine *_vm;
+ BbvsEngine *_vm;
SpriteModule *_spriteModule;
-
+
int _gameState;
int _gameTicks;
bool _gameResult;
bool _gameDone;
bool _fromMainGame;
int _hiScoreTable[kMinigameCount];
-
+
int _backgroundSpriteIndex, _titleScreenSpriteIndex;
-
+
const ObjAnimation *_numbersAnim;
-
+
int drawNumber(DrawList &drawList, int number, int x, int y);
void playSound(uint index, bool loop = false);
void stopSound(uint index);
bool isSoundPlaying(uint index);
bool isAnySoundPlaying(const uint *indices, uint count);
-
+
void saveHiscore(int minigameNum, int score);
int loadHiscore(int minigameNum);
-
+
};
} // End of namespace Bbvs
diff --git a/engines/bbvs/saveload.cpp b/engines/bbvs/saveload.cpp
index ff53cc457b..e7725713fd 100644
--- a/engines/bbvs/saveload.cpp
+++ b/engines/bbvs/saveload.cpp
@@ -73,7 +73,7 @@ void BbvsEngine::savegame(const char *filename, const char *description) {
byte descriptionLen = strlen(description);
out->writeByte(descriptionLen);
out->write(description, descriptionLen);
-
+
Graphics::saveThumbnail(*out);
// Not used yet, reserved for future usage
@@ -86,7 +86,7 @@ void BbvsEngine::savegame(const char *filename, const char *description) {
out->writeUint32LE(saveTime);
out->writeUint32LE(playTime);
// Header end
-
+
out->write(_snapshot, _snapshotStream->pos());
out->finalize();
@@ -103,15 +103,15 @@ void BbvsEngine::loadgame(const char *filename) {
SaveHeader header;
kReadSaveHeaderError errorCode = readSaveHeader(in, false, header);
-
+
if (errorCode != kRSHENoError) {
warning("Error loading savegame '%s'", filename);
delete in;
return;
}
-
+
g_engine->setTotalPlayTime(header.playTime * 1000);
-
+
memset(_sceneObjects, 0, sizeof(_sceneObjects));
for (int i = 0; i < kSceneObjectsCount; ++i) {
_sceneObjects[i].walkDestPt.x = -1;
@@ -120,7 +120,7 @@ void BbvsEngine::loadgame(const char *filename) {
_currSceneNum = 0;
_newSceneNum = in->readUint32LE();
-
+
initScene(false);
_prevSceneNum = in->readUint32LE();
@@ -157,16 +157,16 @@ void BbvsEngine::loadgame(const char *filename) {
obj->frameIndex = in->readUint32LE();
obj->frameTicks = in->readUint32LE();
obj->walkCount = in->readUint32LE();
- obj->xIncr = in->readUint32LE();
+ obj->xIncr = in->readUint32LE();
obj->yIncr = in->readUint32LE();
- obj->turnValue = in->readUint32LE();
- obj->turnCount = in->readUint32LE();
+ obj->turnValue = in->readUint32LE();
+ obj->turnCount = in->readUint32LE();
obj->turnTicks = in->readUint32LE();
obj->walkDestPt.x = in->readUint16LE();
obj->walkDestPt.y = in->readUint16LE();
obj->anim = obj->animIndex > 0 ? _gameModule->getAnimation(obj->animIndex) : 0;
}
-
+
updateWalkableRects();
// Restart scene background sounds
@@ -259,10 +259,10 @@ void BbvsEngine::saveSnapshot() {
_snapshotStream->writeUint32LE(obj->frameIndex);
_snapshotStream->writeUint32LE(obj->frameTicks);
_snapshotStream->writeUint32LE(obj->walkCount);
- _snapshotStream->writeUint32LE(obj->xIncr);
+ _snapshotStream->writeUint32LE(obj->xIncr);
_snapshotStream->writeUint32LE(obj->yIncr);
- _snapshotStream->writeUint32LE(obj->turnValue);
- _snapshotStream->writeUint32LE(obj->turnCount);
+ _snapshotStream->writeUint32LE(obj->turnValue);
+ _snapshotStream->writeUint32LE(obj->turnCount);
_snapshotStream->writeUint32LE(obj->turnTicks);
_snapshotStream->writeUint16LE(obj->walkDestPt.x);
_snapshotStream->writeUint16LE(obj->walkDestPt.y);
diff --git a/engines/bbvs/scene.cpp b/engines/bbvs/scene.cpp
index 0d86eb4dbc..a89c88fd82 100644
--- a/engines/bbvs/scene.cpp
+++ b/engines/bbvs/scene.cpp
@@ -34,7 +34,7 @@ static const int kAfterVideoSceneNum[] = {
void BbvsEngine::loadScene(int sceneNum) {
debug(0, "BbvsEngine::loadScene() sceneNum: %d", sceneNum);
-
+
Common::String sprFilename = Common::String::format("vnm/vspr%04d.vnm", sceneNum);
Common::String gamFilename = Common::String::format("vnm/game%04d.vnm", sceneNum);
@@ -42,7 +42,7 @@ void BbvsEngine::loadScene(int sceneNum) {
_spriteModule->load(sprFilename.c_str());
_gameModule->load(gamFilename.c_str());
-
+
Palette palette = _spriteModule->getPalette();
_screen->setPalette(palette);
@@ -106,10 +106,10 @@ void BbvsEngine::initScene(bool sounds) {
loadScene(_newSceneNum);
_currSceneNum = _newSceneNum;
_newSceneNum = 0;
-
+
for (int i = 0; i < _gameModule->getSceneObjectDefsCount(); ++i)
_sceneObjects[i].sceneObjectDef = _gameModule->getSceneObjectDef(i);
-
+
for (int i = 0; i < _gameModule->getSceneObjectInitsCount(); ++i) {
SceneObjectInit *soInit = _gameModule->getSceneObjectInit(i);
if (evalCondition(soInit->conditions)) {
@@ -149,10 +149,10 @@ void BbvsEngine::initScene(bool sounds) {
}
}
}
-
+
_cameraPos = _gameModule->getCameraInit(_currCameraNum)->cameraPos;
_newCameraPos = _cameraPos;
-
+
_walkAreaActions.clear();
for (int i = 0; i < _gameModule->getActionsCount(); ++i) {
Action *action = _gameModule->getAction(i);
@@ -165,7 +165,7 @@ void BbvsEngine::initScene(bool sounds) {
_activeItemIndex = 0;
_activeItemType = kITEmpty;
-
+
for (int i = 0; i < _gameModule->getActionsCount(); ++i) {
Action *action = _gameModule->getAction(i);
if (evalCondition(action->conditions)) {
@@ -183,7 +183,7 @@ void BbvsEngine::initScene(bool sounds) {
break;
}
}
-
+
if (sounds)
updateBackgroundSounds();
@@ -192,7 +192,7 @@ void BbvsEngine::initScene(bool sounds) {
bool BbvsEngine::changeScene() {
writeContinueSavegame();
-
+
if (_newSceneNum >= 27 && _newSceneNum <= 30) {
// Run minigames
stopSpeech();
@@ -221,7 +221,7 @@ bool BbvsEngine::changeScene() {
}
return true;
-
+
}
} // End of namespace Bbvs
diff --git a/engines/bbvs/spritemodule.cpp b/engines/bbvs/spritemodule.cpp
index 8eae7f9a6a..f8b0d9afd5 100644
--- a/engines/bbvs/spritemodule.cpp
+++ b/engines/bbvs/spritemodule.cpp
@@ -41,15 +41,15 @@ SpriteModule::~SpriteModule() {
void SpriteModule::load(const char *filename) {
unload();
-
+
Common::File fd;
if (!fd.open(filename))
error("SpriteModule::load() Could not open %s", filename);
-
+
fd.readUint32LE(); // Skip magic
fd.readUint32LE(); // Skip unused
fd.readUint32LE(); // Skip filesize
-
+
_paletteOffs = fd.readUint32LE();
fd.readUint32LE(); // Skip unused flagsTbl1Ofs
fd.readUint32LE(); // Skip unused flagsTbl2Ofs
@@ -57,18 +57,18 @@ void SpriteModule::load(const char *filename) {
_paletteStart = fd.readUint32LE();
_paletteCount = fd.readUint32LE();
_spritesCount = fd.readUint32LE();
-
+
debug(0, "_paletteOffs: %08X", _paletteOffs);
debug(0, "_spriteTblOffs: %08X", _spriteTblOffs);
debug(0, "_paletteStart: %d", _paletteStart);
debug(0, "_paletteCount: %d", _paletteCount);
debug(0, "_spritesCount: %d", _spritesCount);
-
+
_spriteDataSize = fd.size();
_spriteData = new byte[_spriteDataSize];
fd.seek(0);
fd.read(_spriteData, _spriteDataSize);
-
+
// Convert palette
byte *palette = _spriteData + _paletteOffs;
for (int i = 0; i < _paletteCount; ++i) {
diff --git a/engines/bbvs/videoplayer.cpp b/engines/bbvs/videoplayer.cpp
index fda9372ade..9ea73ad10b 100644
--- a/engines/bbvs/videoplayer.cpp
+++ b/engines/bbvs/videoplayer.cpp
@@ -42,7 +42,7 @@ void BbvsEngine::playVideo(int videoNum) {
warning("Couldn't switch to a RGB color video mode to play a video.");
return;
}
-
+
Video::VideoDecoder *videoDecoder = new Video::AVIDecoder();
if (!videoDecoder->loadFile(videoFilename)) {
delete videoDecoder;
@@ -74,7 +74,7 @@ void BbvsEngine::playVideo(int videoNum) {
}
delete videoDecoder;
-
+
initGraphics(320, 240, false);
}
diff --git a/engines/bbvs/walk.cpp b/engines/bbvs/walk.cpp
index 077110b867..5ef14101a0 100644
--- a/engines/bbvs/walk.cpp
+++ b/engines/bbvs/walk.cpp
@@ -46,7 +46,7 @@ static const int8 kWalkAnimTbl[32] = {
void BbvsEngine::startWalkObject(SceneObject *sceneObject) {
if (_buttheadObject != sceneObject && _beavisObject != sceneObject)
return;
-
+
initWalkAreas(sceneObject);
_sourceWalkAreaPt.x = sceneObject->x >> 16;
_sourceWalkAreaPt.y = sceneObject->y >> 16;
@@ -60,7 +60,7 @@ void BbvsEngine::startWalkObject(SceneObject *sceneObject) {
_destWalkArea = getWalkAreaAtPos(_destWalkAreaPt);
if (!_destWalkArea)
return;
-
+
if (_sourceWalkArea != _destWalkArea) {
_currWalkDistance = kMaxDistance;
walkFindPath(_sourceWalkArea, 0);
@@ -68,12 +68,12 @@ void BbvsEngine::startWalkObject(SceneObject *sceneObject) {
}
walkObject(sceneObject, _destWalkAreaPt, sceneObject->sceneObjectDef->walkSpeed);
-
+
}
void BbvsEngine::updateWalkObject(SceneObject *sceneObject) {
int animIndex;
-
+
if (sceneObject->walkCount > 0 && (sceneObject->xIncr != 0 || sceneObject->yIncr != 0)) {
if (ABS(sceneObject->xIncr) <= ABS(sceneObject->yIncr))
sceneObject->turnValue = sceneObject->yIncr >= 0 ? 0 : 4;
@@ -89,7 +89,7 @@ void BbvsEngine::updateWalkObject(SceneObject *sceneObject) {
Animation *anim = 0;
if (animIndex > 0)
anim = _gameModule->getAnimation(animIndex);
-
+
if (sceneObject->anim != anim) {
if (anim) {
sceneObject->anim = anim;
@@ -305,12 +305,12 @@ bool BbvsEngine::canButtheadWalkToDest(const Common::Point &destPt) {
}
void BbvsEngine::canWalkToDest(WalkArea *walkArea, int infoCount) {
-
+
if (_destWalkArea == walkArea) {
_walkReachedDestArea = true;
return;
}
-
+
if (_gameModule->getFieldC() <= 320 || infoCount <= 20) {
walkArea->checked = true;
for (int linkIndex = 0; linkIndex < walkArea->linksCount; ++linkIndex) {
@@ -364,10 +364,10 @@ int BbvsEngine::calcDistance(const Common::Point &pt1, const Common::Point &pt2)
void BbvsEngine::walkFoundPath(int count) {
debug(5, "BbvsEngine::walkFoundPath(%d)", count);
-
+
Common::Point midPt = _sourceWalkAreaPt;
int totalMidPtDistance = 0;
-
+
if (count > 0) {
Common::Point lastMidPt;
int halfCount = (count + 1) >> 1;
@@ -384,13 +384,13 @@ void BbvsEngine::walkFoundPath(int count) {
if (distance >= _currWalkDistance)
return;
-
+
debug(5, "BbvsEngine::walkFoundPath() distance smaller");
_currWalkDistance = distance;
Common::Point destPt = _destWalkAreaPt, newDestPt;
-
+
while (1) {
int index = 0;
@@ -408,7 +408,7 @@ void BbvsEngine::walkFoundPath(int count) {
WalkInfo *walkInfo = _walkInfoPtrs[--count];
destPt.x = walkInfo->x;
destPt.y = walkInfo->y;
-
+
if (walkInfo->direction) {
newDestPt.x = walkInfo->x;
newDestPt.y = walkInfo->y + walkInfo->delta - 1;
diff --git a/engines/cge/POTFILES b/engines/cge/POTFILES
new file mode 100644
index 0000000000..55430683c3
--- /dev/null
+++ b/engines/cge/POTFILES
@@ -0,0 +1,2 @@
+engines/cge/detection.cpp
+
diff --git a/engines/cge/cge.h b/engines/cge/cge.h
index a65069ff46..c43358f252 100644
--- a/engines/cge/cge.h
+++ b/engines/cge/cge.h
@@ -80,12 +80,6 @@ class Talk;
#define kSayTheEnd 41
-enum GameType {
- kGameTypeNone = 0,
- kGameTypeSoltys,
- kGameTypeSfinx
-};
-
// our engine debug channels
enum {
kCGEDebugBitmap = 1 << 0,
diff --git a/engines/cge/detection.cpp b/engines/cge/detection.cpp
index 4c2f81c1ae..da5eb2b1f2 100644
--- a/engines/cge/detection.cpp
+++ b/engines/cge/detection.cpp
@@ -28,134 +28,75 @@
#include "base/plugins.h"
#include "graphics/thumbnail.h"
#include "cge/cge.h"
+#include "cge/fileio.h"
namespace CGE {
-struct CgeGameDescription {
- ADGameDescription desc;
- GameType gameType;
-};
-
#define GAMEOPTION_COLOR_BLIND_DEFAULT_OFF GUIO_GAMEOPTIONS1
-} // End of namespace CGE
-
static const PlainGameDescriptor CGEGames[] = {
{ "soltys", "Soltys" },
- { "sfinx", "Sfinx" },
{ 0, 0 }
};
-namespace CGE {
-
-static const CgeGameDescription gameDescriptions[] = {
-
- {
- {
- "soltys", "",
- {
- {"vol.cat", 0, "0c33e2c304821a2444d297fc5e2d67c6", 50176},
- {"vol.dat", 0, "f9ae2e7f8f7cac91378cdafca43faf1e", 8437572},
- AD_LISTEND
- },
- Common::PL_POL, Common::kPlatformDOS, ADGF_NO_FLAGS, GUIO0()
- },
- kGameTypeSoltys
- },
+static const ADGameDescription gameDescriptions[] = {
{
+ "soltys", "Freeware",
{
- "soltys", "Soltys Freeware",
- {
- {"vol.cat", 0, "0c33e2c304821a2444d297fc5e2d67c6", 50176},
- {"vol.dat", 0, "f9ae2e7f8f7cac91378cdafca43faf1e", 8437676},
- AD_LISTEND
- },
- Common::PL_POL, Common::kPlatformDOS, ADGF_NO_FLAGS, GUIO1(GAMEOPTION_COLOR_BLIND_DEFAULT_OFF)
+ {"vol.cat", 0, "0c33e2c304821a2444d297fc5e2d67c6", 50176},
+ {"vol.dat", 0, "f9ae2e7f8f7cac91378cdafca43faf1e", 8437676},
+ AD_LISTEND
},
- kGameTypeSoltys
+ Common::PL_POL, Common::kPlatformDOS, ADGF_NO_FLAGS, GUIO1(GAMEOPTION_COLOR_BLIND_DEFAULT_OFF)
},
{
+ "soltys", "Demo (not supported)",
{
- "soltys", "Soltys Demo (not supported)",
- {
- {"vol.cat", 0, "1e077c8ff58109a187f07ac54b0c873a", 18788},
- {"vol.dat", 0, "75d385a6074c58b69f7730481f256051", 1796710},
- AD_LISTEND
- },
- Common::EN_ANY, Common::kPlatformDOS, ADGF_DEMO , GUIO1(GAMEOPTION_COLOR_BLIND_DEFAULT_OFF)
+ {"vol.cat", 0, "1e077c8ff58109a187f07ac54b0c873a", 18788},
+ {"vol.dat", 0, "75d385a6074c58b69f7730481f256051", 1796710},
+ AD_LISTEND
},
- kGameTypeSoltys
+ Common::EN_ANY, Common::kPlatformDOS, ADGF_DEMO , GUIO1(GAMEOPTION_COLOR_BLIND_DEFAULT_OFF)
},
{
+ "soltys", "Demo (not supported)",
{
- "soltys", "Soltys Demo (not supported)",
- {
- {"vol.cat", 0, "f17987487fab1ebddd781d8d02fedecc", 7168},
- {"vol.dat", 0, "c5d9b15863cab61dc125551576dece04", 1075272},
- AD_LISTEND
- },
- Common::PL_POL, Common::kPlatformDOS, ADGF_DEMO , GUIO1(GAMEOPTION_COLOR_BLIND_DEFAULT_OFF)
+ {"vol.cat", 0, "f17987487fab1ebddd781d8d02fedecc", 7168},
+ {"vol.dat", 0, "c5d9b15863cab61dc125551576dece04", 1075272},
+ AD_LISTEND
},
- kGameTypeSoltys
+ Common::PL_POL, Common::kPlatformDOS, ADGF_DEMO , GUIO1(GAMEOPTION_COLOR_BLIND_DEFAULT_OFF)
},
{
+ "soltys", "Freeware v1.0",
{
- "soltys", "Soltys Freeware v1.0",
- {
- {"vol.cat", 0, "f1675684c68ab90272f5776f8f2c3974", 50176},
- {"vol.dat", 0, "4ffeff4abc99ac5999b55ccfc56ab1df", 8430868},
- AD_LISTEND
- },
- Common::EN_ANY, Common::kPlatformDOS, ADGF_NO_FLAGS , GUIO1(GAMEOPTION_COLOR_BLIND_DEFAULT_OFF)
+ {"vol.cat", 0, "f1675684c68ab90272f5776f8f2c3974", 50176},
+ {"vol.dat", 0, "4ffeff4abc99ac5999b55ccfc56ab1df", 8430868},
+ AD_LISTEND
},
- kGameTypeSoltys
+ Common::EN_ANY, Common::kPlatformDOS, ADGF_NO_FLAGS , GUIO1(GAMEOPTION_COLOR_BLIND_DEFAULT_OFF)
},
{
+ "soltys", "Freeware v1.0",
{
- "soltys", "Soltys Freeware v1.0",
- {
- {"vol.cat", 0, "20fdce799adb618100ef9ee2362be875", 50176},
- {"vol.dat", 0, "0e43331c846094d77f5dd201827e0a3b", 8439339},
- AD_LISTEND
- },
- Common::PL_POL, Common::kPlatformDOS, ADGF_NO_FLAGS, GUIO1(GAMEOPTION_COLOR_BLIND_DEFAULT_OFF)
+ {"vol.cat", 0, "20fdce799adb618100ef9ee2362be875", 50176},
+ {"vol.dat", 0, "0e43331c846094d77f5dd201827e0a3b", 8439339},
+ AD_LISTEND
},
- kGameTypeSoltys
+ Common::PL_POL, Common::kPlatformDOS, ADGF_NO_FLAGS, GUIO1(GAMEOPTION_COLOR_BLIND_DEFAULT_OFF)
},
{
+ "soltys", "Freeware v1.0",
{
- "soltys", "Soltys Freeware v1.0",
- {
- {"vol.cat", 0, "fcae86b20eaa5cedec17b24fa5e85eb4", 50176},
- {"vol.dat", 0, "ff10d54acc2c95696c57e05819b6906f", 8450151},
- AD_LISTEND
- },
- Common::ES_ESP, Common::kPlatformDOS, ADGF_NO_FLAGS , GUIO1(GAMEOPTION_COLOR_BLIND_DEFAULT_OFF)
+ {"vol.cat", 0, "fcae86b20eaa5cedec17b24fa5e85eb4", 50176},
+ {"vol.dat", 0, "ff10d54acc2c95696c57e05819b6906f", 8450151},
+ AD_LISTEND
},
- kGameTypeSoltys
+ Common::ES_ESP, Common::kPlatformDOS, ADGF_NO_FLAGS , GUIO1(GAMEOPTION_COLOR_BLIND_DEFAULT_OFF)
},
- {
- {
- // Polish version, provided by Strangerke
- "sfinx", "Sfinx Freeware",
- {
- {"vol.cat", 0, "21197b287d397c53261b6616bf0dd880", 129024},
- {"vol.dat", 0, "de14291869a8eb7c2732ab783c7542ef", 34180844},
- AD_LISTEND
- },
- Common::PL_POL, Common::kPlatformDOS, ADGF_NO_FLAGS, GUIO1(GAMEOPTION_COLOR_BLIND_DEFAULT_OFF)
- },
- kGameTypeSfinx
- },
-
- {AD_TABLE_END_MARKER, kGameTypeNone}
-};
-static const ADFileBasedFallback fileBasedFallback[] = {
- { &gameDescriptions[0].desc, { "vol.cat", "vol.dat", 0 } },
- { 0, { 0 } }
+ AD_TABLE_END_MARKER
};
-} // End of namespace CGE
static const ADExtraGuiOptionsMap optionsList[] = {
{
@@ -173,14 +114,10 @@ static const ADExtraGuiOptionsMap optionsList[] = {
class CGEMetaEngine : public AdvancedMetaEngine {
public:
- CGEMetaEngine() : AdvancedMetaEngine(CGE::gameDescriptions, sizeof(CGE::CgeGameDescription), CGEGames, optionsList) {
+ CGEMetaEngine() : AdvancedMetaEngine(CGE::gameDescriptions, sizeof(ADGameDescription), CGEGames, optionsList) {
_singleid = "soltys";
}
- virtual const ADGameDescription *fallbackDetect(const FileMap &allFiles, const Common::FSList &fslist) const {
- return detectGameFilebased(allFiles, fslist, CGE::fileBasedFallback);
- }
-
virtual const char *getName() const {
return "CGE";
}
@@ -189,6 +126,7 @@ public:
return "Soltys (c) 1994-1996 L.K. Avalon";
}
+ virtual const ADGameDescription *fallbackDetect(const FileMap &allFiles, const Common::FSList &fslist) const;
virtual bool hasFeature(MetaEngineFeature f) const;
virtual bool createInstance(OSystem *syst, Engine **engine, const ADGameDescription *desc) const;
virtual int getMaximumSaveSlot() const;
@@ -197,6 +135,44 @@ public:
virtual void removeSaveState(const char *target, int slot) const;
};
+static const ADFileBasedFallback fileBasedFallback[] = {
+ { &gameDescriptions[0], { "vol.cat", "vol.dat", 0 } },
+ { 0, { 0 } }
+};
+
+static ADGameDescription s_fallbackDesc = {
+ "Soltys",
+ "Unknown version",
+ AD_ENTRY1(0, 0), // This should always be AD_ENTRY1(0, 0) in the fallback descriptor
+ Common::UNK_LANG,
+ Common::kPlatformDOS,
+ ADGF_NO_FLAGS,
+ GUIO1(GAMEOPTION_COLOR_BLIND_DEFAULT_OFF)
+};
+
+const ADGameDescription *CGEMetaEngine::fallbackDetect(const FileMap &allFiles, const Common::FSList &fslist) const {
+ ADFilePropertiesMap filesProps;
+
+ const ADGameDescription *game;
+ game = detectGameFilebased(allFiles, fslist, CGE::fileBasedFallback, &filesProps);
+
+ if (!game)
+ return nullptr;
+
+ SearchMan.clear();
+ SearchMan.addDirectory(fslist.begin()->getParent().getPath(), fslist.begin()->getParent());
+ ResourceManager *resman;
+ resman = new ResourceManager();
+ bool result = resman->exist("CGE.SAY");
+ delete resman;
+
+ if (!result)
+ return nullptr;
+
+ reportUnknown(fslist.begin()->getParent(), filesProps);
+ return &s_fallbackDesc;
+}
+
bool CGEMetaEngine::hasFeature(MetaEngineFeature f) const {
return
(f == kSupportsListSaves) ||
@@ -306,9 +282,10 @@ bool CGEMetaEngine::createInstance(OSystem *syst, Engine **engine, const ADGameD
}
return desc != 0;
}
+} // End of namespace CGE
#if PLUGIN_ENABLED_DYNAMIC(CGE)
- REGISTER_PLUGIN_DYNAMIC(CGE, PLUGIN_TYPE_ENGINE, CGEMetaEngine);
+REGISTER_PLUGIN_DYNAMIC(CGE, PLUGIN_TYPE_ENGINE, CGE::CGEMetaEngine);
#else
- REGISTER_PLUGIN_STATIC(CGE, PLUGIN_TYPE_ENGINE, CGEMetaEngine);
+REGISTER_PLUGIN_STATIC(CGE, PLUGIN_TYPE_ENGINE, CGE::CGEMetaEngine);
#endif
diff --git a/engines/cge/fileio.cpp b/engines/cge/fileio.cpp
index 2b1f74db02..df5c31d367 100644
--- a/engines/cge/fileio.cpp
+++ b/engines/cge/fileio.cpp
@@ -77,7 +77,7 @@ ResourceManager::ResourceManager() {
_buff[i]._page = new BtPage;
_buff[i]._pageNo = kBtValNone;
_buff[i]._index = -1;
- assert(_buff[i]._page != NULL);
+ assert(_buff[i]._page != nullptr);
}
}
@@ -118,10 +118,16 @@ uint16 ResourceManager::read(byte *buf, uint16 length) {
BtPage *ResourceManager::getPage(int level, uint16 pageId) {
debugC(1, kCGEDebugFile, "ResourceManager::getPage(%d, %d)", level, pageId);
+ if (level >= kBtLevel)
+ return nullptr;
+
if (_buff[level]._pageNo != pageId) {
int32 pos = pageId * kBtSize;
_buff[level]._pageNo = pageId;
- assert(_catFile->size() > pos);
+
+ if (_catFile->size() <= pos)
+ return nullptr;
+
// In the original, there was a check verifying if the
// purpose was to write a new file. This should only be
// to create a new file, thus it was removed.
@@ -146,11 +152,13 @@ BtKeypack *ResourceManager::find(const char *key) {
uint16 nxt = kBtValRoot;
while (!_catFile->eos()) {
BtPage *pg = getPage(lev, nxt);
+ if (!pg)
+ return nullptr;
+
// search
if (pg->_header._down != kBtValNone) {
int i;
for (i = 0; i < pg->_header._count; i++) {
- // Does this work, or does it have to compare the entire buffer?
if (scumm_strnicmp((const char *)key, (const char*)pg->_inner[i]._key, kBtKeySize) < 0)
break;
}
@@ -167,13 +175,17 @@ BtKeypack *ResourceManager::find(const char *key) {
return &pg->_leaf[i];
}
}
- return NULL;
+ return nullptr;
}
bool ResourceManager::exist(const char *name) {
debugC(1, kCGEDebugFile, "ResourceManager::exist(%s)", name);
- return scumm_stricmp(find(name)->_key, name) == 0;
+ BtKeypack* result = find(name);
+ if (!result)
+ return false;
+
+ return scumm_stricmp(result->_key, name) == 0;
}
uint16 ResourceManager::catRead(byte *buf, uint16 length) {
@@ -228,7 +240,7 @@ uint32 EncryptedStream::read(byte *dataPtr, uint32 dataSize) {
}
bool EncryptedStream::err() {
- return (_error & _readStream->err());
+ return (_error || _readStream->err());
}
bool EncryptedStream::eos() {
diff --git a/engines/cge/vga13h.cpp b/engines/cge/vga13h.cpp
index babcb7e667..4d3a103663 100644
--- a/engines/cge/vga13h.cpp
+++ b/engines/cge/vga13h.cpp
@@ -640,7 +640,7 @@ Vga::Vga(CGEEngine *vm) : _frmCnt(0), _msg(NULL), _name(NULL), _setPal(false), _
if (ConfMan.getBool("enable_color_blind"))
_mono = 1;
-
+
_oldColors = (Dac *)malloc(sizeof(Dac) * kPalCount);
_newColors = (Dac *)malloc(sizeof(Dac) * kPalCount);
diff --git a/engines/cge2/POTFILES b/engines/cge2/POTFILES
new file mode 100644
index 0000000000..1e904763ec
--- /dev/null
+++ b/engines/cge2/POTFILES
@@ -0,0 +1 @@
+engines/cge2/detection.cpp
diff --git a/engines/cge2/bitmap.cpp b/engines/cge2/bitmap.cpp
new file mode 100644
index 0000000000..0f442b8c77
--- /dev/null
+++ b/engines/cge2/bitmap.cpp
@@ -0,0 +1,458 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+/*
+ * This code is based on original Sfinx source code
+ * Copyright (c) 1994-1997 Janus B. Wisniewski and L.K. Avalon
+ */
+
+#include "cge2/bitmap.h"
+#include "cge2/cge2.h"
+#include "cge2/vga13h.h"
+#include "cge2/talk.h"
+#include "common/system.h"
+#include "common/debug.h"
+#include "common/debug-channels.h"
+
+namespace CGE2 {
+
+Bitmap::Bitmap() : _w(0), _h(0), _v(nullptr), _b(nullptr), _map(0), _vm(nullptr) {
+}
+
+void Bitmap::setVM(CGE2Engine *vm) {
+ _vm = vm;
+}
+
+Bitmap::Bitmap(CGE2Engine *vm, const char *fname) : _w(0), _h(0), _v(nullptr), _b(nullptr), _map(0), _vm(vm) {
+ Common::String path;
+
+ if (!strcmp(fname, "04tal201")) {
+ path = "04tal202";
+ warning("Workaround for missing VBM: 04tal201");
+ } else if (!strcmp(fname, "11oqlist-")) {
+ path = "11oqlist";
+ warning("Workaround for wrong VBM name: 11oqlist-");
+ } else
+ path = fname;
+
+ path = setExtension(path, ".VBM");
+
+ if (_vm->_resman->exist(path.c_str())) {
+ EncryptedStream file(_vm, path.c_str());
+ if (file.err())
+ error("Unable to find VBM [%s]", fname);
+ if (!loadVBM(&file))
+ error("Bad VBM [%s]", fname);
+ } else {
+ warning("Missing VBM [%s]", path.c_str());
+ }
+}
+
+Bitmap::Bitmap(CGE2Engine *vm, uint16 w, uint16 h, uint8 *map) : _w(w), _h(h), _v(nullptr), _map(0), _b(nullptr), _vm(vm) {
+ if (map)
+ code(map);
+}
+
+// following routine creates filled rectangle
+// immediately as VGA video chunks, in near memory as fast as possible,
+// especially for text line real time display
+Bitmap::Bitmap(CGE2Engine *vm, uint16 w, uint16 h, uint8 fill)
+ : _w((w + 3) & ~3), // only full uint32 allowed!
+ _h(h), _map(0), _b(nullptr), _vm(vm) {
+
+ uint16 dsiz = _w >> 2; // data size (1 plane line size)
+ uint16 lsiz = 2 + dsiz + 2; // uint16 for line header, uint16 for gap
+ uint16 psiz = _h * lsiz; // - last gape, but + plane trailer
+ uint8 *v = new uint8[4 * psiz + _h * sizeof(*_b)];// the same for 4 planes
+ // + room for wash table
+
+ WRITE_LE_UINT16(v, (kBmpCPY | dsiz)); // data chunk hader
+ memset(v + 2, fill, dsiz); // data bytes
+ WRITE_LE_UINT16(v + lsiz - 2, (kBmpSKP | ((kScrWidth / 4) - dsiz))); // gap
+
+ // Replicate lines
+ byte *destP;
+ for (destP = v + lsiz; destP < (v + psiz); destP += lsiz)
+ Common::copy(v, v + lsiz, destP);
+
+ WRITE_LE_UINT16(v + psiz - 2, kBmpEOI); // plane trailer uint16
+
+ // Replicate planes
+ for (destP = v + psiz; destP < (v + 4 * psiz); destP += psiz)
+ Common::copy(v, v + psiz, destP);
+
+ HideDesc *b = (HideDesc *)(v + 4 * psiz);
+ b->_skip = (kScrWidth - _w) >> 2;
+ b->_hide = _w >> 2;
+
+ // Replicate across the entire table
+ for (HideDesc *hdP = b + 1; hdP < (b + _h); hdP++)
+ *hdP = *b;
+
+ b->_skip = 0; // fix the first entry
+ _v = v;
+ _b = b;
+}
+
+Bitmap::Bitmap(CGE2Engine *vm, const Bitmap &bmp) : _w(bmp._w), _h(bmp._h), _v(nullptr), _map(0), _b(nullptr), _vm(vm) {
+ uint8 *v0 = bmp._v;
+ if (!v0)
+ return;
+
+ uint16 vsiz = (uint8 *)(bmp._b) - (uint8 *)(v0);
+ uint16 siz = vsiz + _h * sizeof(HideDesc);
+ uint8 *v1 = new uint8[siz];
+ memcpy(v1, v0, siz);
+ _b = (HideDesc *)((_v = v1) + vsiz);
+}
+
+Bitmap::~Bitmap() {
+ release();
+}
+
+void Bitmap::release() {
+ if (_v != nullptr)
+ delete[] _v;
+ _v = nullptr;
+}
+
+Bitmap &Bitmap::operator=(const Bitmap &bmp) {
+ if (this == &bmp)
+ return *this;
+
+ uint8 *v0 = bmp._v;
+ _w = bmp._w;
+ _h = bmp._h;
+ _map = 0;
+ _vm = bmp._vm;
+ delete[] _v;
+ _v = nullptr;
+
+ if (v0) {
+ uint16 vsiz = (uint8 *)bmp._b - (uint8 *)v0;
+ uint16 siz = vsiz + _h * sizeof(HideDesc);
+ uint8 *v1 = new uint8[siz];
+ memcpy(v1, v0, siz);
+ _b = (HideDesc *)((_v = v1) + vsiz);
+ }
+ return *this;
+}
+
+// Blatant rip from hopkins engine where it's ripped from gob engine. Hi DrMcCoy, hi Strangerke! ;>
+Common::String Bitmap::setExtension(const Common::String &str, const Common::String &ext) {
+ if (str.empty())
+ return str;
+
+ const char *dot = strrchr(str.c_str(), '.');
+ if (dot)
+ return Common::String(str.c_str(), dot - str.c_str()) + ext;
+
+ return str + ext;
+}
+
+BitmapPtr Bitmap::code(uint8 *map) {
+ if (!map)
+ return nullptr;
+
+ uint16 cnt;
+
+ if (_v) { // old X-map exists, so remove it
+ delete[] _v;
+ _v = nullptr;
+ }
+
+ while (true) { // at most 2 times: for (V == NULL) & for allocated block;
+ uint8 *im = _v + 2;
+ uint16 *cp = (uint16 *) _v;
+
+ if (_v) { // 2nd pass - fill the hide table
+ for (uint i = 0; i < _h; i++) {
+ _b[i]._skip = 0xFFFF;
+ _b[i]._hide = 0x0000;
+ }
+ }
+ for (int bpl = 0; bpl < 4; bpl++) { // once per each bitplane
+ uint8 *bm = map;
+ bool skip = (bm[bpl] == kPixelTransp);
+ uint16 j;
+
+ cnt = 0;
+ for (uint i = 0; i < _h; i++) { // once per each line
+ uint8 pix;
+ for (j = bpl; j < _w; j += 4) {
+ pix = bm[j];
+ if (_v && (pix != kPixelTransp)) {
+ if (j < _b[i]._skip)
+ _b[i]._skip = j;
+
+ if (j >= _b[i]._hide)
+ _b[i]._hide = j + 1;
+ }
+ if (((pix == kPixelTransp) != skip) || (cnt >= 0x3FF0)) { // end of block
+ cnt |= (skip) ? kBmpSKP : kBmpCPY;
+ if (_v)
+ WRITE_LE_UINT16(cp, cnt); // store block description uint16
+
+ cp = (uint16 *) im;
+ im += 2;
+ skip = (pix == kPixelTransp);
+ cnt = 0;
+ }
+ if (!skip) {
+ if (_v)
+ *im = pix;
+ im++;
+ }
+ cnt++;
+ }
+
+ bm += _w;
+ if (_w < kScrWidth) {
+ if (skip)
+ cnt += (kScrWidth - j + 3) / 4;
+ else {
+ cnt |= kBmpCPY;
+ if (_v)
+ WRITE_LE_UINT16(cp, cnt);
+
+ cp = (uint16 *) im;
+ im += 2;
+ skip = true;
+ cnt = (kScrWidth - j + 3) / 4;
+ }
+ }
+ }
+ if (cnt && ! skip) {
+ cnt |= kBmpCPY;
+ if (_v)
+ WRITE_LE_UINT16(cp, cnt);
+
+ cp = (uint16 *) im;
+ im += 2;
+ }
+ if (_v)
+ WRITE_LE_UINT16(cp, kBmpEOI);
+ cp = (uint16 *) im;
+ im += 2;
+ }
+ if (_v)
+ break;
+
+ uint16 sizV = (uint16)(im - 2 - _v);
+ _v = new uint8[sizV + _h * sizeof(*_b)];
+ _b = (HideDesc *)(_v + sizV);
+ }
+ cnt = 0;
+ for (uint i = 0; i < _h; i++) {
+ if (_b[i]._skip == 0xFFFF) { // whole line is skipped
+ _b[i]._skip = (cnt + kScrWidth) >> 2;
+ cnt = 0;
+ } else {
+ uint16 s = _b[i]._skip & ~3;
+ uint16 h = (_b[i]._hide + 3) & ~3;
+ _b[i]._skip = (cnt + s) >> 2;
+ _b[i]._hide = (h - s) >> 2;
+ cnt = kScrWidth - h;
+ }
+ }
+
+ return this;
+}
+
+bool Bitmap::solidAt(V2D pos) {
+ pos.x += _w >> 1;
+ pos.y = _h - pos.y;
+
+ if (!pos.limited(V2D(_vm, _w, _h)))
+ return false;
+
+ uint8 *m = _v;
+ uint16 r = static_cast<uint16>(pos.x) % 4;
+ uint16 n0 = (kScrWidth * pos.y + pos.x) / 4;
+ uint16 n = 0;
+
+ while (r) {
+ uint16 w, t;
+
+ w = READ_LE_UINT16(m);
+ m += 2;
+ t = w & 0xC000;
+ w &= 0x3FFF;
+
+ switch (t) {
+ case kBmpEOI:
+ r--;
+ // No break on purpose
+ case kBmpSKP:
+ w = 0;
+ break;
+ case kBmpREP:
+ w = 1;
+ break;
+ }
+ m += w;
+ }
+
+ while (true) {
+ uint16 w, t;
+
+ w = READ_LE_UINT16(m);
+ m += 2;
+ t = w & 0xC000;
+ w &= 0x3FFF;
+
+ if (n > n0)
+ return false;
+
+ n += w;
+ switch (t) {
+ case kBmpEOI:
+ return false;
+ case kBmpSKP:
+ w = 0;
+ break;
+ case kBmpREP:
+ case kBmpCPY:
+ if ((n - w <= n0) && (n > n0))
+ return true;
+ break;
+ }
+ m += ((t == kBmpREP) ? 1 : w);
+ }
+}
+
+bool Bitmap::loadVBM(EncryptedStream *f) {
+ uint16 p = 0, n = 0;
+ if (!f->err())
+ f->read((uint8 *)&p, sizeof(p));
+ p = FROM_LE_16(p);
+
+ if (!f->err())
+ f->read((uint8 *)&n, sizeof(n));
+ n = FROM_LE_16(n);
+
+ if (!f->err())
+ f->read((uint8 *)&_w, sizeof(_w));
+ _w = FROM_LE_16(_w);
+
+ if (!f->err())
+ f->read((uint8 *)&_h, sizeof(_h));
+ _h = FROM_LE_16(_h);
+
+ if (!f->err()) {
+ if (p) {
+ if (_vm->_bitmapPalette) {
+ // Read in the palette
+ byte palData[kPalSize];
+ f->read(palData, kPalSize);
+
+ const byte *srcP = palData;
+ for (int idx = 0; idx < kPalCount; idx++, srcP += 3) {
+ _vm->_bitmapPalette[idx]._r = *srcP;
+ _vm->_bitmapPalette[idx]._g = *(srcP + 1);
+ _vm->_bitmapPalette[idx]._b = *(srcP + 2);
+ }
+ } else
+ f->seek(f->pos() + kPalSize);
+ }
+ }
+ _v = new uint8[n];
+
+ if (!f->err())
+ f->read(_v, n);
+
+ _b = (HideDesc *)(_v + n - _h * sizeof(HideDesc));
+ return (!f->err());
+}
+
+void Bitmap::xLatPos(V2D& p) {
+ p.x -= (_w >> 1);
+ p.y = kWorldHeight - p.y - _h;
+}
+
+#define _ kPixelTransp,
+#define L 1,
+#define G 2,
+#define D 3,
+#define kDesignSize 240
+
+uint8 *Bitmap::makeSpeechBubbleTail(int which, uint8 colorSet[][4]) {
+ static const uint8 kSLDesign[kDesignSize] = {
+ G G G G G G G G G _ _ _ _ _ _
+ L G G G G G G G G D _ _ _ _ _
+ _ L G G G G G G G D _ _ _ _ _
+ _ _ L G G G G G G G D _ _ _ _
+ _ _ _ L G G G G G G D _ _ _ _
+ _ _ _ _ L G G G G G D _ _ _ _
+ _ _ _ _ _ L G G G G G D _ _ _
+ _ _ _ _ _ _ L G G G G D _ _ _
+ _ _ _ _ _ _ _ L G G G D _ _ _
+ _ _ _ _ _ _ _ _ L G G G D _ _
+ _ _ _ _ _ _ _ _ _ L G G D _ _
+ _ _ _ _ _ _ _ _ _ _ L G D _ _
+ _ _ _ _ _ _ _ _ _ _ _ L G D _
+ _ _ _ _ _ _ _ _ _ _ _ _ L D _
+ _ _ _ _ _ _ _ _ _ _ _ _ _ L D
+ _ _ _ _ _ _ _ _ _ _ _ _ _ _ D
+ };
+
+ static const uint8 kSRDesign[kDesignSize] = {
+ _ _ _ _ _ _ G G G G G G G G G
+ _ _ _ _ _ L G G G G G G G G D
+ _ _ _ _ _ L G G G G G G G D _
+ _ _ _ _ L G G G G G G G D _ _
+ _ _ _ _ L G G G G G G D _ _ _
+ _ _ _ _ L G G G G G D _ _ _ _
+ _ _ _ L G G G G G D _ _ _ _ _
+ _ _ _ L G G G G D _ _ _ _ _ _
+ _ _ _ L G G G D _ _ _ _ _ _ _
+ _ _ L G G G D _ _ _ _ _ _ _ _
+ _ _ L G G D _ _ _ _ _ _ _ _ _
+ _ _ L G D _ _ _ _ _ _ _ _ _ _
+ _ L G D _ _ _ _ _ _ _ _ _ _ _
+ _ L D _ _ _ _ _ _ _ _ _ _ _ _
+ L D _ _ _ _ _ _ _ _ _ _ _ _ _
+ D _ _ _ _ _ _ _ _ _ _ _ _ _ _
+ };
+
+ uint8 *des = new uint8[kDesignSize];
+ switch (which) {
+ case 0:
+ memcpy(des, kSLDesign, sizeof(kSLDesign));
+ break;
+ case 1:
+ memcpy(des, kSRDesign, sizeof(kSRDesign));
+ break;
+ default:
+ error("Wrong parameter in Bitmap::makeSpeechBubbleTail!");
+ break;
+ }
+
+ for (int i = 0; i < kDesignSize; i++) {
+ if ((des[i] >= 1) && (des[i] <= 3))
+ des[i] = colorSet[kCBSay][des[i]];
+ }
+
+ return des;
+}
+
+} // End of namespace CGE2
diff --git a/engines/cge2/bitmap.h b/engines/cge2/bitmap.h
new file mode 100644
index 0000000000..613222fc6e
--- /dev/null
+++ b/engines/cge2/bitmap.h
@@ -0,0 +1,94 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+/*
+ * This code is based on original Sfinx source code
+ * Copyright (c) 1994-1997 Janus B. Wisniewski and L.K. Avalon
+ */
+
+#ifndef CGE2_BITMAP_H
+#define CGE2_BITMAP_H
+
+#include "cge2/general.h"
+#include "common/file.h"
+
+namespace CGE2 {
+
+class CGE2Engine;
+class EncryptedStream;
+class V2D;
+
+#define kMaxPath 128
+
+enum {
+ kBmpEOI = 0x0000,
+ kBmpSKP = 0x4000,
+ kBmpREP = 0x8000,
+ kBmpCPY = 0xC000
+};
+
+#include "common/pack-start.h"
+
+struct HideDesc {
+ uint16 _skip;
+ uint16 _hide;
+};
+
+#include "common/pack-end.h"
+
+class Bitmap {
+ CGE2Engine *_vm;
+
+ Common::String setExtension(const Common::String &str, const Common::String &ext);
+ bool loadVBM(EncryptedStream *f);
+public:
+ uint16 _w;
+ uint16 _h;
+ uint8 *_v;
+ int32 _map;
+ HideDesc *_b;
+
+ Bitmap();
+ Bitmap(CGE2Engine *vm, const char *fname);
+ Bitmap(CGE2Engine *vm, uint16 w, uint16 h, uint8 *map);
+ Bitmap(CGE2Engine *vm, uint16 w, uint16 h, uint8 fill);
+ Bitmap(CGE2Engine *vm, const Bitmap &bmp);
+ ~Bitmap();
+
+ void setVM(CGE2Engine *vm);
+ Bitmap *code(uint8 *map);
+ Bitmap &operator=(const Bitmap &bmp);
+ void release();
+ void hide(V2D pos);
+ void show(V2D pos);
+ bool solidAt(V2D pos);
+ void xLatPos(V2D &p);
+
+ static uint8 *makeSpeechBubbleTail(int des, uint8 colorSet[][4]);
+};
+
+
+typedef Bitmap *BitmapPtr;
+
+} // End of namespace CGE2
+
+#endif // CGE2_BITMAP_H
diff --git a/engines/cge2/cge2.cpp b/engines/cge2/cge2.cpp
new file mode 100644
index 0000000000..ee62e20ac6
--- /dev/null
+++ b/engines/cge2/cge2.cpp
@@ -0,0 +1,207 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+/*
+ * This code is based on original Sfinx source code
+ * Copyright (c) 1994-1997 Janus B. Wisniewski and L.K. Avalon
+ */
+
+#include "engines/util.h"
+#include "common/config-manager.h"
+#include "common/debug.h"
+#include "common/debug-channels.h"
+#include "cge2/cge2.h"
+#include "cge2/bitmap.h"
+#include "cge2/vga13h.h"
+#include "cge2/sound.h"
+#include "cge2/text.h"
+#include "cge2/hero.h"
+#include "cge2/general.h"
+#include "cge2/spare.h"
+#include "cge2/talk.h"
+#include "cge2/cge2_main.h"
+#include "cge2/map.h"
+
+namespace CGE2 {
+
+CGE2Engine::CGE2Engine(OSystem *syst, const ADGameDescription *gameDescription)
+ : Engine(syst), _gameDescription(gameDescription), _randomSource("cge2") {
+
+ // Debug/console setup
+ DebugMan.addDebugChannel(kCGE2DebugOpcode, "opcode", "CGE2 opcode debug channel");
+
+ _resman = nullptr;
+ _vga = nullptr;
+ _midiPlayer = nullptr;
+ _fx = nullptr;
+ _sound = nullptr;
+ _text = nullptr;
+ for (int i = 0; i < 2; i++)
+ _heroTab[i] = nullptr;
+ _eye = nullptr;
+ for (int i = 0; i < kSceneMax; i++)
+ _eyeTab[i] = nullptr;
+ _spare = nullptr;
+ _commandHandler = nullptr;
+ _commandHandlerTurbo = nullptr;
+ _font = nullptr;
+ _infoLine = nullptr;
+ _mouse = nullptr;
+ _keyboard = nullptr;
+ _talk = nullptr;
+ for (int i = 0; i < kMaxPoint; i++)
+ _point[i] = nullptr;
+ _sys = nullptr;
+ _busyPtr = nullptr;
+ for (int i = 0; i < 2; i++)
+ _vol[i] = nullptr;
+ _eventManager = nullptr;
+ _map = nullptr;
+ _console = nullptr;
+ _quitFlag = false;
+ _bitmapPalette = nullptr;
+ _gamePhase = kPhaseIntro;
+ _now = 1;
+ _sex = 1;
+ _mouseTop = kWorldHeight / 3;
+ _dark = false;
+ _lastFrame = 0;
+ _lastTick = 0;
+ _waitSeq = 0;
+ _waitRef = 0;
+ _soundStat._wait = nullptr;
+ _soundStat._ref[0] = 0;
+ _soundStat._ref[1] = 0;
+ _taken = false;
+ _endGame = false;
+ _req = 1;
+ _midiNotify = nullptr;
+ _spriteNotify = nullptr;
+ _startGameSlot = 0;
+
+ _sayCap = ConfMan.getBool("subtitles");
+ _sayVox = !ConfMan.getBool("speech_mute");
+ _muteAll = ConfMan.getBool("mute");
+ if (_muteAll) {
+ _oldMusicVolume = _oldSfxVolume = 0;
+ _music = _sayVox = false;
+ } else {
+ _oldMusicVolume = ConfMan.getInt("music_volume");
+ _oldSfxVolume = ConfMan.getInt("sfx_volume");
+ _music = _oldMusicVolume != 0;
+ }
+}
+
+void CGE2Engine::init() {
+ // Create debugger console
+ _console = new CGE2Console(this);
+ _resman = new ResourceManager();
+ _vga = new Vga(this);
+ _fx = new Fx(this, 16);
+ _sound = new Sound(this);
+ _midiPlayer = new MusicPlayer(this);
+ _text = new Text(this, "CGE");
+
+ for (int i = 0; i < 2; i++)
+ _heroTab[i] = new HeroTab(this);
+
+ _eye = new V3D();
+ for (int i = 0; i < kSceneMax; i++)
+ _eyeTab[i] = new V3D();
+
+ _spare = new Spare(this);
+ _commandHandler = new CommandHandler(this, false);
+ _commandHandlerTurbo = new CommandHandler(this, true);
+ _font = new Font(this);
+ _infoLine = new InfoLine(this, kInfoW);
+ _mouse = new Mouse(this);
+ _keyboard = new Keyboard(this);
+
+ for (int i = 0; i < kMaxPoint; i++)
+ _point[i] = new V3D();
+
+ _sys = new System(this);
+ _eventManager = new EventManager(this);
+ _map = new Map(this);
+ _startGameSlot = ConfMan.hasKey("save_slot") ? ConfMan.getInt("save_slot") : -1;
+}
+
+void CGE2Engine::deinit() {
+ // Remove all of our debug levels here
+ DebugMan.clearAllDebugChannels();
+
+ delete _console;
+
+ delete _spare;
+ delete _resman;
+ delete _vga;
+ delete _fx;
+ delete _sound;
+ delete _midiPlayer;
+ delete _text;
+
+ for (int i = 0; i < 2; i++)
+ delete _heroTab[i];
+
+ for (int i = 0; i < kSceneMax; i++)
+ delete _eyeTab[i];
+
+ delete _eye;
+ delete _commandHandler;
+ delete _commandHandlerTurbo;
+ delete _font;
+ delete _infoLine;
+ delete _mouse;
+ delete _keyboard;
+
+ if (_talk != nullptr)
+ delete _talk;
+
+ for (int i = 0; i < kMaxPoint; i++)
+ delete _point[i];
+
+ delete _sys;
+ delete _eventManager;
+ delete _map;
+}
+
+bool CGE2Engine::hasFeature(EngineFeature f) const {
+ return (f == kSupportsLoadingDuringRuntime) || (f == kSupportsSavingDuringRuntime)
+ || (f == kSupportsRTL);
+}
+
+Common::Error CGE2Engine::run() {
+ syncSoundSettings();
+ initGraphics(kScrWidth, kScrHeight, false);
+
+ init();
+ cge2_main();
+ deinit();
+
+ ConfMan.setBool("subtitles", _sayCap);
+ ConfMan.setBool("speech_mute", !_sayVox);
+ ConfMan.flushToDisk();
+
+ return Common::kNoError;
+}
+
+} // End of namespace CGE2
diff --git a/engines/cge2/cge2.h b/engines/cge2/cge2.h
new file mode 100644
index 0000000000..fbe4cb3abc
--- /dev/null
+++ b/engines/cge2/cge2.h
@@ -0,0 +1,338 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+/*
+ * This code is based on original Sfinx source code
+ * Copyright (c) 1994-1997 Janus B. Wisniewski and L.K. Avalon
+ */
+
+#ifndef CGE2_H
+#define CGE2_H
+
+#include "common/random.h"
+#include "common/savefile.h"
+#include "common/serializer.h"
+#include "engines/engine.h"
+#include "engines/advancedDetector.h"
+#include "common/system.h"
+#include "cge2/fileio.h"
+#include "cge2/console.h"
+#include "audio/mixer.h"
+
+namespace CGE2 {
+
+class Vga;
+class Sprite;
+class MusicPlayer;
+class Fx;
+class Sound;
+class Text;
+struct HeroTab;
+class FXP;
+class V3D;
+class V2D;
+struct Dac;
+class Spare;
+class CommandHandler;
+class InfoLine;
+class Mouse;
+class Keyboard;
+class Talk;
+class Hero;
+class Bitmap;
+class System;
+class EventManager;
+class Font;
+class Map;
+struct SavegameHeader;
+
+#define kScrWidth 320
+#define kScrHeight 240
+#define kScrDepth 480
+#define kPanHeight 40
+#define kWorldHeight (kScrHeight - kPanHeight)
+#define kMaxFile 128
+#define kPathMax 128
+#define kDimMax 8
+#define kWayMax 10
+#define kPocketMax 4
+#define kSceneMax 100
+#define kMaxPoint 4
+#define kInfoX 160
+#define kInfoY -11
+#define kInfoW 180
+#define kPocketsWidth 59
+#define kLineMax 512
+
+#define kIntroExt ".I80"
+#define kTabName "CGE.TAB"
+#define kPocketFull 170
+#define kGameFrameDelay (750 / 50)
+#define kGameTickDelay (750 / 62)
+
+#define kMusicRef 122
+#define kPowerRef 123
+#define kDvolRef 124
+#define kMvolRef 125
+#define kBusyRef 127
+
+#define kOffUseCount 130
+#define kOffUseText 131
+
+#define kSysTimeRate 6 // 12 Hz
+#define kBlinkRate 4 // 3 Hz
+
+#define kQuitTitle 200
+#define kQuitText 201
+#define kNoQuitText 202
+
+#define kSavegameVersion 1
+#define kSavegameStrSize 12
+#define kSavegameStr "SCUMMVM_CGE2"
+
+#define kColorNum 6
+
+struct SavegameHeader {
+ uint8 version;
+ Common::String saveName;
+ Graphics::Surface *thumbnail;
+ int saveYear, saveMonth, saveDay;
+ int saveHour, saveMinutes;
+};
+
+enum ColorBank { kCBRel, kCBStd, kCBSay, kCBInf, kCBMnu, kCBWar };
+
+enum GamePhase { kPhaseInGame, kPhaseIntro, kPhaseOver };
+
+// our engine debug channels
+enum {
+ kCGE2DebugOpcode = 1 << 0
+};
+
+enum CallbackType {
+ kNullCB = 0, kQGame, kXScene
+};
+
+enum Action { kNear, kMTake, kFTake, kActions };
+
+typedef void (CGE2Engine::*NotifyFunctionType)();
+
+class CGE2Engine : public Engine {
+private:
+ uint32 _lastFrame, _lastTick;
+ void tick();
+
+ CGE2Console *_console;
+ void init();
+ void deinit();
+
+ Common::String generateSaveName(int slot);
+ void writeSavegameHeader(Common::OutSaveFile *out, SavegameHeader &header);
+ void saveGame(int slotNumber, const Common::String &desc);
+ bool loadGame(int slotNumber);
+ void syncHeader(Common::Serializer &s);
+ void syncGame(Common::SeekableReadStream *readStream, Common::WriteStream *writeStream);
+ void resetGame();
+public:
+ CGE2Engine(OSystem *syst, const ADGameDescription *gameDescription);
+ virtual bool hasFeature(EngineFeature f) const;
+ virtual bool canSaveGameStateCurrently();
+ virtual bool canLoadGameStateCurrently();
+ virtual Common::Error saveGameState(int slot, const Common::String &desc);
+ virtual Common::Error loadGameState(int slot);
+ virtual Common::Error run();
+
+ static bool readSavegameHeader(Common::InSaveFile *in, SavegameHeader &header);
+
+ GUI::Debugger *getDebugger() {
+ return _console;
+ }
+
+ bool showTitle(const char *name);
+ void cge2_main();
+ char *mergeExt(char *buf, const char *name, const char *ext);
+ void inf(const char *text, ColorBank col = kCBInf);
+ void movie(const char *ext);
+ void runGame();
+ void loadHeroes();
+ void loadScript(const char *fname, bool onlyToolbar = false);
+ Sprite *loadSprite(const char *fname, int ref, int scene, V3D &pos);
+ void badLab(const char *fn);
+ void sceneUp(int cav);
+ void sceneDown();
+ void closePocket();
+ void switchScene(int scene);
+ void storeHeroPos();
+ void showBak(int ref);
+ void loadTab();
+ int newRandom(int range);
+ void openPocket();
+ void selectPocket(int n);
+ void busy(bool on);
+ void feedSnail(Sprite *spr, Action snq, Hero *hero);
+ int freePockets(int sx);
+ int findActivePocket(int ref);
+ void pocFul();
+ void killText();
+ void mainLoop();
+ void handleFrame();
+ Sprite *locate(int ref);
+ bool isHero(Sprite *spr);
+ void loadUser();
+ void loadPos();
+ void releasePocket(Sprite *spr);
+ void switchHero(int sex);
+ void offUse();
+ void setAutoColors();
+ bool cross(const V2D &a, const V2D &b, const V2D &c, const V2D &d);
+ bool contain(const V2D &a, const V2D &b, const V2D &p);
+ long det(const V2D &a, const V2D &b, const V2D &c);
+ int sgn(long n);
+ int mapCross(const V2D &a, const V2D &b);
+ Sprite *spriteAt(V2D pos);
+ void keyClick();
+ void swapInPocket(Sprite *spr, Sprite *xspr);
+ void busyStep();
+
+ void optionTouch(int opt, uint16 mask);
+ void switchColorMode();
+ void switchMusic();
+ void quit();
+ void setVolume(int idx, int cnt);
+ void checkVolumeSwitches();
+ void switchCap();
+ void switchVox();
+ void switchSay();
+ void initToolbar();
+ void initVolumeSwitch(Sprite *volSwitch, int val);
+ void checkMute();
+
+ void checkSounds();
+
+ void setEye(const V3D &e);
+ void setEye(const V2D& e2, int z = -kScrWidth);
+ void setEye(const char *s);
+
+ int number(char *s);
+ char *token(char *s);
+ char *tail(char *s);
+ int takeEnum(const char **tab, const char *text);
+ ID ident(const char *s);
+ bool testBool(char *s);
+
+ void snKill(Sprite *spr);
+ void snHide(Sprite *spr, int val);
+ void snMidi(int val);
+ void snSeq(Sprite *spr, int val);
+ void snRSeq(Sprite *spr, int val);
+ void snSend(Sprite *spr, int val);
+ void snSwap(Sprite *spr, int val);
+ void snCover(Sprite *spr, int val);
+ void snUncover(Sprite *spr, Sprite *spr2);
+ void snKeep(Sprite *spr, int val);
+ void snGive(Sprite *spr, int val);
+ void snGoto(Sprite *spr, int val);
+ void snPort(Sprite *spr, int port);
+ void snMouse(bool on);
+ void snNNext(Sprite *spr, Action act, int val);
+ void snRNNext(Sprite *spr, int val);
+ void snRMTNext(Sprite *spr, int val);
+ void snRFTNext(Sprite *spr, int val);
+ void snRmNear(Sprite *spr);
+ void snRmMTake(Sprite *spr);
+ void snRmFTake(Sprite *spr);
+ void snSetRef(Sprite *spr, int val);
+ void snFlash(bool on);
+ void snCycle(int cnt);
+ void snWalk(Sprite *spr, int val);
+ void snReach(Sprite *spr, int val);
+ void snSound(Sprite *spr, int wav, Audio::Mixer::SoundType soundType = Audio::Mixer::kSFXSoundType);
+ void snRoom(Sprite *spr, bool on);
+ void snGhost(Bitmap *bmp);
+ void snSay(Sprite *spr, int val);
+
+ void hide1(Sprite *spr);
+ Sprite *expandSprite(Sprite *spr);
+ void qGame();
+ void xScene();
+
+ const ADGameDescription *_gameDescription;
+
+ Common::RandomSource _randomSource;
+
+ bool _quitFlag;
+ Dac *_bitmapPalette;
+ GamePhase _gamePhase; // Original name: startupmode
+ int _now;
+ int _sex;
+ int _mouseTop;
+ bool _dark;
+ int _waitSeq;
+ int _waitRef;
+
+ struct {
+ int *_wait;
+ int _ref[2];
+ } _soundStat;
+
+ bool _taken;
+ bool _endGame;
+ int _req;
+ NotifyFunctionType _midiNotify;
+ NotifyFunctionType _spriteNotify;
+ int _startGameSlot;
+
+ bool _sayCap;
+ bool _sayVox;
+ int _oldMusicVolume;
+ int _oldSfxVolume;
+ bool _music;
+ bool _muteAll;
+
+ ResourceManager *_resman;
+ Vga *_vga;
+ MusicPlayer *_midiPlayer;
+ Fx *_fx;
+ Sound *_sound;
+ Text *_text;
+ HeroTab *_heroTab[2];
+ V3D *_eye;
+ V3D *_eyeTab[kSceneMax];
+ Spare *_spare;
+ CommandHandler *_commandHandler;
+ CommandHandler *_commandHandlerTurbo;
+ Font *_font;
+ InfoLine *_infoLine;
+ Mouse *_mouse;
+ Keyboard *_keyboard;
+ Talk *_talk;
+ V3D *_point[kMaxPoint];
+ System *_sys;
+ Sprite *_busyPtr;
+ Sprite *_vol[2];
+ EventManager *_eventManager;
+ Map *_map;
+};
+
+} // End of namespace CGE2
+
+#endif // CGE2_H
diff --git a/engines/cge2/cge2_main.cpp b/engines/cge2/cge2_main.cpp
new file mode 100644
index 0000000000..4e3d229618
--- /dev/null
+++ b/engines/cge2/cge2_main.cpp
@@ -0,0 +1,959 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+/*
+ * This code is based on original Sfinx source code
+ * Copyright (c) 1994-1997 Janus B. Wisniewski and L.K. Avalon
+ */
+
+#include "sound.h"
+#include "cge2/cge2_main.h"
+#include "cge2/cge2.h"
+#include "cge2/vga13h.h"
+#include "cge2/text.h"
+#include "cge2/snail.h"
+#include "cge2/hero.h"
+#include "cge2/spare.h"
+#include "cge2/map.h"
+
+namespace CGE2 {
+
+System::System(CGE2Engine *vm) : Sprite(vm), _vm(vm) {
+ _blinkCounter = 0;
+ _blinkSprite = nullptr;
+ tick();
+}
+
+void System::touch(uint16 mask, V2D pos, Common::KeyCode keyCode) {
+ if (mask & kEventKeyb) {
+ if (keyCode == Common::KEYCODE_ESCAPE) {
+ // The original was calling keyClick()
+ // The sound is uselessly annoying and noisy, so it has been removed
+ _vm->killText();
+ if (_vm->_gamePhase == kPhaseIntro) {
+ _vm->_commandHandler->addCommand(kCmdClear, -1, 0, nullptr);
+ return;
+ }
+ }
+ } else {
+ if (_vm->_gamePhase != kPhaseInGame)
+ return;
+ _vm->_infoLine->setText(nullptr);
+
+ if (mask & kMouseLeftUp) {
+ if (pos.y >= 0) { // world
+ if (!_vm->_talk && pos.y < _vm->_mouseTop)
+ _vm->_heroTab[_vm->_sex]->_ptr->walkTo(pos);
+ } else { // panel
+ if (_vm->_commandHandler->idle()) {
+ int sex = pos.x < kPocketsWidth;
+ if (sex || pos.x >= kScrWidth - kPocketsWidth) {
+ _vm->switchHero(sex);
+ if (_vm->_sex == sex) {
+ int dx = kPocketsWidth >> 1,
+ dy = 1 - (kPanHeight >> 1);
+ Sprite *s;
+ if (!sex)
+ pos.x -= kScrWidth - kPocketsWidth;
+ dx -= pos.x;
+ dy -= pos.y;
+ if (dx * dx + dy * dy > 10 * 10) {
+ int n = 0;
+ if (1 - pos.y >= (kPanHeight >> 1))
+ n += 2;
+ if (pos.x >= (kPocketsWidth >> 1))
+ ++n;
+ s = _vm->_heroTab[_vm->_sex]->_pocket[n];
+ if (_vm->_sys->_blinkSprite)
+ _vm->_sys->_blinkSprite->_flags._hide = false;
+ if (_vm->_sys->_blinkSprite == s)
+ _vm->_sys->_blinkSprite = nullptr;
+ else
+ _vm->_sys->_blinkSprite = s;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+void System::tick() {
+ _time = kSysTimeRate;
+
+ if (_blinkCounter)
+ --_blinkCounter;
+ else {
+ if (_blinkSprite)
+ _blinkSprite->_flags._hide ^= 1;
+ _blinkCounter = kBlinkRate;
+ }
+}
+
+int CGE2Engine::number(char *str) {
+ char *s = token(str);
+ if (s == nullptr)
+ error("Wrong input for CGE2Engine::number()");
+ int r = atoi(s);
+ char *pp = strchr(s, ':');
+ if (pp)
+ r = (r << 8) + atoi(pp + 1);
+ return r;
+}
+
+char *CGE2Engine::token(char *s) {
+ return strtok(s, " =\t,;/()");
+}
+
+char *CGE2Engine::tail(char *s) {
+ if (s && (*s == '='))
+ s++;
+ return s;
+}
+
+int CGE2Engine::takeEnum(const char **tab, const char *text) {
+ if (text) {
+ for (const char **e = tab; *e; e++) {
+ if (scumm_stricmp(text, *e) == 0)
+ return e - tab;
+ }
+ }
+ return -1;
+}
+
+ID CGE2Engine::ident(const char *s) {
+ return ID(takeEnum(EncryptedStream::kIdTab, s));
+}
+
+bool CGE2Engine::testBool(char *s) {
+ return number(s) != 0;
+}
+
+void CGE2Engine::badLab(const char *fn) {
+ error("Misplaced label in %s!", fn);
+}
+
+Sprite *CGE2Engine::loadSprite(const char *fname, int ref, int scene, V3D &pos) {
+ int shpcnt = 0;
+ int seqcnt = 0;
+ int cnt[kActions];
+
+ for (int i = 0; i < kActions; i++)
+ cnt[i] = 0;
+
+ ID section = kIdPhase;
+ bool frnt = true;
+ bool east = false;
+ bool port = false;
+ bool tran = false;
+ Hero *h;
+ ID id;
+
+ char tmpStr[kLineMax + 1];
+ mergeExt(tmpStr, fname, kSprExt);
+
+ if (_resman->exist(tmpStr)) { // sprite description file exist
+ EncryptedStream sprf(this, tmpStr);
+ if (sprf.err())
+ error("Bad SPR [%s]", tmpStr);
+
+ int label = kNoByte;
+ Common::String line;
+
+ for (line = sprf.readLine(); !sprf.eos(); line = sprf.readLine()){
+ if (line.empty())
+ continue;
+ Common::strlcpy(tmpStr, line.c_str(), sizeof(tmpStr));
+
+ char *p = token(tmpStr);
+ if (*p == '@') {
+ if (label != kNoByte)
+ badLab(fname);
+ label = atoi(p + 1);
+ continue;
+ }
+
+ id = ident(p);
+ switch (id) {
+ case kIdName: // will be taken in Expand routine
+ if (label != kNoByte)
+ badLab(fname);
+ break;
+ case kIdType:
+ if (label != kNoByte)
+ badLab(fname);
+ break;
+ case kIdNear:
+ case kIdMTake:
+ case kIdFTake:
+ case kIdPhase:
+ case kIdSeq:
+ if (label != kNoByte)
+ badLab(fname);
+ section = id;
+ break;
+ case kIdFront:
+ if (label != kNoByte)
+ badLab(fname);
+ p = token(nullptr);
+ frnt = testBool(p);
+ break;
+ case kIdEast:
+ if (label != kNoByte)
+ badLab(fname);
+ p = token(nullptr);
+ east = testBool(p);
+ break;
+ case kIdPortable:
+ if (label != kNoByte)
+ badLab(fname);
+ p = token(nullptr);
+ port = testBool(p);
+ break;
+ case kIdTransparent:
+ if (label != kNoByte)
+ badLab(fname);
+ p = token(nullptr);
+ tran = testBool(p);
+ break;
+ default:
+ if (id >= kIdNear)
+ break;
+ switch (section) {
+ case kIdNear:
+ case kIdMTake:
+ case kIdFTake:
+ if (_commandHandler->getComId(p) >= 0)
+ ++cnt[section];
+ else
+ error("Bad line %d [%s]", sprf.getLineCount(), tmpStr);
+ break;
+ case kIdPhase:
+ if (label != kNoByte)
+ badLab(fname);
+ ++shpcnt;
+ break;
+ case kIdSeq:
+ if (label != kNoByte)
+ badLab(fname);
+ ++seqcnt;
+ break;
+ default:
+ break;
+ }
+ break;
+ }
+ label = kNoByte;
+ }
+
+ if (!shpcnt)
+ error("No shapes - %s", fname);
+ } else // No sprite description: mono-shaped sprite with only .BMP file.
+ ++shpcnt;
+
+ // Make sprite of chosen type:
+ Sprite *sprite = nullptr;
+ char c = *fname | 0x20;
+ if (c >= 'a' && c <= 'z' && fname[1] == '0' && fname[2] == '\0') {
+ h = new Hero(this);
+ h->gotoxyz(pos);
+ sprite = h;
+ } else {
+ sprite = new Sprite(this);
+ sprite->gotoxyz(pos);
+ }
+
+ if (sprite) {
+ sprite->_ref = ref;
+ sprite->_scene = scene;
+
+ sprite->_flags._frnt = frnt;
+ sprite->_flags._east = east;
+ sprite->_flags._port = port;
+ sprite->_flags._tran = tran;
+ sprite->_flags._kill = true;
+
+ // Extract the filename, without the extension
+ Common::strlcpy(sprite->_file, fname, sizeof(sprite->_file));
+ char *p = strchr(sprite->_file, '.');
+ if (p)
+ *p = '\0';
+
+ sprite->_shpCnt = shpcnt;
+ sprite->_seqCnt = seqcnt;
+
+ for (int i = 0; i < kActions; i++)
+ sprite->_actionCtrl[i]._cnt = cnt[i];
+ }
+
+ return sprite;
+}
+
+void CGE2Engine::loadScript(const char *fname, bool onlyToolbar) {
+ EncryptedStream scrf(this, fname);
+
+ if (scrf.err())
+ return;
+
+ bool ok = true;
+ int lcnt = 0;
+
+ char tmpStr[kLineMax + 1];
+ Common::String line;
+
+ for (line = scrf.readLine(); !scrf.eos(); line = scrf.readLine()) {
+ if (line.empty())
+ continue;
+
+ lcnt++;
+ Common::strlcpy(tmpStr, line.c_str(), sizeof(tmpStr));
+
+ ok = false; // not OK if break
+
+ V3D P;
+
+ // sprite ident number
+ int SpI = number(tmpStr);
+
+ if (onlyToolbar && SpI >= 141)
+ return;
+
+ // sprite file name
+ char *SpN;
+ if ((SpN = token(nullptr)) == nullptr)
+ break;
+
+ // sprite scene
+ int SpA = number(nullptr);
+
+ // sprite column
+ P._x = number(nullptr);
+
+ // sprite row
+ P._y = number(nullptr);
+
+ // sprite Z pos
+ P._z = number(nullptr);
+
+ // sprite life
+ bool BkG = number(nullptr) == 0;
+
+ ok = true; // no break: OK
+
+ Sprite *sprite = loadSprite(SpN, SpI, SpA, P);
+ if (sprite) {
+ if (BkG)
+ sprite->_flags._back = true;
+
+ int n = _spare->count();
+ if (_spare->locate(sprite->_ref) == nullptr)
+ _spare->dispose(sprite);
+ else
+ delete sprite;
+
+ if (_spare->count() == n)
+ error("Duplicate reference! %s", SpN);
+ }
+ }
+
+ if (!ok)
+ error("Bad INI line %d [%s]", scrf.getLineCount(), fname);
+}
+
+void CGE2Engine::movie(const char *ext) {
+ assert(ext);
+
+ if (_quitFlag)
+ return;
+
+ char fn[12];
+ snprintf(fn, 12, "CGE%s", ext);
+
+ if (_resman->exist(fn)) {
+ int now = _now;
+ _now = atoi(ext + 2);
+ loadScript(fn);
+ sceneUp(_now);
+ _keyboard->setClient(_sys);
+
+ while (!_commandHandler->idle() && !_quitFlag)
+ mainLoop();
+
+ _keyboard->setClient(nullptr);
+ _commandHandler->addCommand(kCmdClear, -1, 0, nullptr);
+ _commandHandlerTurbo->addCommand(kCmdClear, -1, 0, nullptr);
+ _spare->clear();
+ _vga->_showQ->clear();
+ _now = now;
+ }
+}
+
+void CGE2Engine::sceneUp(int cav) {
+ _now = cav;
+ int bakRef = _now << 8;
+ if (_music)
+ _midiPlayer->loadMidi(bakRef);
+ showBak(bakRef);
+ *_eye = *(_eyeTab[_now]);
+ _mouseTop = V2D(this, V3D(0, 1, kScrDepth)).y;
+ _map->load(_now);
+ _spare->takeScene(_now);
+ openPocket();
+
+ for (int i = 0; i < 2; i++) {
+ Hero *h = _heroTab[i]->_ptr;
+ if (h && h->_scene == _now) {
+ V2D p = *_heroTab[i]->_posTab[_now];
+ h->gotoxyz(V3D(p.x, 0, p.y));
+ h->clrHide();
+ _vga->_showQ->insert(h);
+ h->park();
+ h->setCurrent();
+ h->setContact();
+ }
+ }
+
+ _sound->stop();
+ _fx->clear();
+
+ selectPocket(-1);
+ _infoLine->setText(nullptr);
+ busy(false);
+
+ if (!_dark)
+ _vga->sunset();
+
+ _vga->show();
+ _vga->copyPage(1, 0);
+ _vga->show();
+ _vga->sunrise(_vga->_sysPal);
+
+ _dark = false;
+
+ if (_gamePhase == kPhaseInGame)
+ _mouse->on();
+
+ feedSnail(_vga->_showQ->locate(bakRef + 255), kNear, _heroTab[_sex]->_ptr);
+}
+
+void CGE2Engine::sceneDown() {
+ busy(true);
+ _soundStat._wait = nullptr; // unlock snail
+ Sprite *spr = _vga->_showQ->locate((_now << 8) | 254);
+
+ if (spr)
+ feedSnail(spr, kNear, _heroTab[_sex]->_ptr);
+
+ while (!(_commandHandler->idle() && _commandHandlerTurbo->idle())) {
+ _commandHandlerTurbo->runCommand();
+ _commandHandler->runCommand();
+ }
+
+ closePocket();
+ for (int i = 0; i < 2; i++)
+ _spare->update(_vga->_showQ->remove(_heroTab[i]->_ptr));
+ _spare->dispose();
+}
+
+void CGE2Engine::switchScene(int scene) {
+ if (scene == _now)
+ return;
+
+ _req = scene;
+ storeHeroPos();
+ *(_eyeTab[_now]) = *_eye;
+
+ if (scene < 0)
+ _commandHandler->addCallback(kCmdExec, -1, 0, kQGame); // quit game
+ else {
+ if (_heroTab[_sex]->_ptr->_scene == _now) {
+ _heroTab[_sex]->_ptr->setScene(scene);
+ if (_heroTab[!_sex]->_ptr->_scene == _now)
+ _heroTab[!_sex]->_ptr->setScene(scene);
+ }
+ _mouse->off();
+ if (_heroTab[_sex]->_ptr)
+ _heroTab[_sex]->_ptr->park();
+ killText();
+ _commandHandler->addCallback(kCmdExec, -1, 0, kXScene); // switch scene
+ }
+}
+
+void CGE2Engine::storeHeroPos() {
+ for (int i = 0; i < 2; i++) {
+ Hero *h = _heroTab[i]->_ptr;
+ if (h->_scene == _now) {
+ delete _heroTab[i]->_posTab[_now];
+ V2D *temp = new V2D(this, h->_pos3D._x.trunc(), h->_pos3D._z.trunc());
+ _heroTab[i]->_posTab[_now] = temp;
+ }
+ }
+}
+
+void CGE2Engine::showBak(int ref) {
+ Sprite *spr = _spare->locate(ref);
+ if (spr != nullptr) {
+ _bitmapPalette = _vga->_sysPal;
+ spr->expand();
+ _bitmapPalette = nullptr;
+ spr->show(2);
+ _vga->copyPage(1, 2);
+ }
+}
+
+void CGE2Engine::mainLoop() {
+ if (_gamePhase == kPhaseInGame)
+ checkSounds();
+
+ _vga->show();
+ _commandHandlerTurbo->runCommand();
+ _commandHandler->runCommand();
+
+ // Handle a delay between game frames
+ handleFrame();
+
+ // Handle any pending events
+ _eventManager->poll();
+
+ // Check shouldQuit()
+ _quitFlag = shouldQuit();
+}
+
+void CGE2Engine::checkSounds() {
+ checkMute();
+ _sound->checkSoundHandles();
+ checkVolumeSwitches();
+ _midiPlayer->syncVolume();
+ syncSoundSettings();
+}
+
+void CGE2Engine::handleFrame() {
+ // Game frame delay
+ uint32 millis = g_system->getMillis();
+ while (!_quitFlag && (millis < (_lastFrame + kGameFrameDelay))) {
+ // Handle any pending events
+ _eventManager->poll();
+
+ if (millis >= (_lastTick + kGameTickDelay)) {
+ // Dispatch the tick to any active objects
+ tick();
+ _lastTick = millis;
+ }
+
+ // Slight delay
+ g_system->delayMillis(5);
+ millis = g_system->getMillis();
+ }
+ _lastFrame = millis;
+
+ if (millis >= (_lastTick + kGameTickDelay)) {
+ // Dispatch the tick to any active objects
+ tick();
+ _lastTick = millis;
+ }
+}
+
+Sprite *CGE2Engine::locate(int ref) {
+ _taken = false;
+ Sprite *spr = _vga->_showQ->locate(ref);
+ if (!spr) {
+ spr = _spare->locate(ref);
+ if (spr)
+ _taken = true;
+ }
+ return spr;
+}
+
+bool CGE2Engine::isHero(Sprite *spr) {
+ return spr && spr->_ref / 10 == 14;
+}
+
+void CGE2Engine::tick() {
+ // system pseudo-sprite
+ if (_sys && _sys->_time && (--_sys->_time == 0))
+ _sys->tick();
+
+ for (Sprite *spr = _vga->_showQ->first(); spr; spr = spr->_next) {
+ if (spr->_time && (--spr->_time == 0))
+ spr->tick();
+
+ if (_waitRef && (_waitRef == spr->_ref) && spr->seqTest(_waitSeq))
+ _waitRef = 0;
+ }
+
+ _mouse->tick();
+}
+
+void CGE2Engine::busy(bool on) {
+ if (on) {
+ _spriteNotify = _midiNotify = &CGE2::CGE2Engine::busyStep;
+ busyStep();
+ } else {
+ if (_busyPtr)
+ _busyPtr->step(0);
+ _spriteNotify = _midiNotify = nullptr;
+ }
+}
+
+void CGE2Engine::busyStep() {
+ if (_busyPtr) {
+ _busyPtr->step((_busyPtr->_seqPtr) ? -1 : 1);
+ _busyPtr->show(0);
+ }
+}
+
+void CGE2Engine::runGame() {
+ if (_quitFlag)
+ return;
+
+ loadUser();
+ sceneUp(_now);
+ initToolbar();
+
+ // main loop
+ while (!_endGame && !_quitFlag)
+ mainLoop();
+
+ // If leaving the game (close window, return to launcher, etc.
+ // - except finishing the game), explicitly save it's state:
+ if (!_endGame && canSaveGameStateCurrently())
+ qGame();
+
+ _keyboard->setClient(nullptr);
+ _commandHandler->addCommand(kCmdClear, -1, 0, nullptr);
+ _commandHandlerTurbo->addCommand(kCmdClear, -1, 0, nullptr);
+ _mouse->off();
+}
+
+void CGE2Engine::loadUser() {
+ loadPos();
+
+ if (_startGameSlot != -1)
+ loadGame(_startGameSlot);
+ else {
+ loadScript("CGE.INI");
+ loadHeroes();
+ }
+}
+
+void CGE2Engine::loadHeroes() { // Original name: loadGame()
+ // load sprites & pocket
+
+ Sprite *s;
+ Hero *h = nullptr;
+
+ // initialize Andzia/Anna
+ s = _spare->take(142);
+ if (s) {
+ h = new Hero(this);
+ *(Sprite*)h = *s;
+ delete s;
+ h->expand();
+ _spare->update(h);
+ }
+ _heroTab[0]->_ptr = h;
+ s = _spare->locate(152);
+ _vga->_showQ->insert(s);
+ _heroTab[0]->_face = s;
+
+ // initialize Wacek/Vincent
+ s = _spare->take(141);
+ if (s) {
+ h = new Hero(this);
+ *(Sprite*)h = *s;
+ delete s;
+ h->expand();
+ _spare->update(h);
+ }
+ _heroTab[1]->_ptr = h;
+ s = _spare->locate(151);
+ _vga->_showQ->insert(s);
+ _heroTab[1]->_face = s;
+
+ //--- start!
+ switchHero(_sex);
+}
+
+void CGE2Engine::loadPos() {
+ if (_resman->exist("CGE.HXY")) {
+ for (int cav = 0; cav < kSceneMax; cav++)
+ _heroTab[1]->_posTab[cav] = new V2D(this, 180, 10);
+
+ EncryptedStream file(this, "CGE.HXY");
+
+ for (int cav = 0; cav < kSceneMax; cav++) {
+ _heroTab[0]->_posTab[cav] = new V2D(this);
+ _heroTab[0]->_posTab[cav]->x = file.readSint16LE();
+ _heroTab[0]->_posTab[cav]->y = file.readSint16LE();
+ }
+
+ for (int cav = 0; cav < 41; cav++) { // (564 - 400) / 4 = 41
+ _heroTab[1]->_posTab[cav]->x = file.readSint16LE();
+ _heroTab[1]->_posTab[cav]->y = file.readSint16LE();
+ }
+ } else
+ error("Missing file: CGE.HXY");
+}
+
+void CGE2Engine::loadTab() {
+ setEye(_text->getText(240));
+ for (int i = 0; i < kSceneMax; i++)
+ *(_eyeTab[i]) = *_eye;
+
+ if (_resman->exist(kTabName)) {
+ EncryptedStream f(this, kTabName);
+
+ for (int i = 0; i < kSceneMax; i++) {
+ uint32 v = f.readUint32LE();
+ _eyeTab[i]->_x = FXP(v >> 8, static_cast<int>((int8)(v & 0xff)));
+
+ v = f.readUint32LE();
+ _eyeTab[i]->_y = FXP(v >> 8, static_cast<int>((int8)(v & 0xff)));
+
+ v = f.readUint32LE();
+ _eyeTab[i]->_z = FXP(v >> 8, static_cast<int>((int8)(v & 0xff)));
+ }
+ }
+}
+
+void CGE2Engine::cge2_main() {
+ loadTab();
+
+ if (_startGameSlot != -1) {
+ // Starting up a savegame from the launcher
+ runGame();
+ return;
+ }
+
+ if (showTitle("WELCOME")) {
+ movie(kIntroExt);
+
+ if (_text->getText(255) != nullptr) {
+ runGame();
+ _gamePhase = kPhaseOver;
+ }
+
+ _vga->sunset();
+ } else
+ _vga->sunset();
+}
+
+char *CGE2Engine::mergeExt(char *buf, const char *name, const char *ext) {
+ strcpy(buf, name);
+ char *dot = strrchr(buf, '.');
+ if (!dot)
+ strcat(buf, ext);
+
+ return buf;
+}
+
+void CGE2Engine::setEye(const V3D &e) {
+ *_eye = e;
+}
+
+void CGE2Engine::setEye(const V2D& e2, int z) {
+ _eye->_x = e2.x;
+ _eye->_y = e2.y;
+ _eye->_z = z;
+}
+
+void CGE2Engine::setEye(const char *s) {
+ char *tempStr = new char[strlen(s) + 1];
+ strcpy(tempStr, s);
+ _eye->_x = atoi(token(tempStr));
+ _eye->_y = atoi(token(nullptr));
+ _eye->_z = atoi(token(nullptr));
+ delete[] tempStr;
+}
+
+int CGE2Engine::newRandom(int range) {
+ if (!range)
+ return 0;
+
+ return _randomSource.getRandomNumber(range - 1);
+}
+
+bool CGE2Engine::showTitle(const char *name) {
+ if (_quitFlag)
+ return false;
+
+ _bitmapPalette = _vga->_sysPal;
+ BitmapPtr LB = new Bitmap[1];
+ LB[0] = Bitmap(this, name);
+ _bitmapPalette = nullptr;
+
+ Sprite D(this, LB, 1);
+ D._flags._kill = true;
+ D.gotoxyz(kScrWidth >> 1, -(kPanHeight >> 1));
+
+ _vga->sunset();
+ D.show(2);
+ _vga->copyPage(1, 2);
+ _vga->copyPage(0, 1);
+ _vga->sunrise(_vga->_sysPal);
+ _vga->update();
+
+ g_system->delayMillis(2500);
+
+ return true;
+}
+
+void CGE2Engine::killText() {
+ if (!_talk)
+ return;
+
+ _commandHandlerTurbo->addCommand(kCmdKill, -1, 0, _talk);
+ _talk = nullptr;
+}
+
+void CGE2Engine::switchHero(int sex) {
+ if (sex != _sex) {
+ int scene = _heroTab[sex]->_ptr->_scene;
+ if (_sys->_blinkSprite) {
+ _sys->_blinkSprite->_flags._hide = false;
+ _sys->_blinkSprite = nullptr;
+ }
+
+ if (scene >= 0) {
+ _commandHandler->addCommand(kCmdSeq, -1, 2, _heroTab[_sex]->_face);
+ _sex ^= 1;
+ switchScene(scene);
+ }
+ }
+ Sprite *face = _heroTab[_sex]->_face;
+ if (face->_seqPtr == 0)
+ _commandHandler->addCommand(kCmdSeq, -1, 1, face);
+}
+
+void Sprite::touch(uint16 mask, V2D pos, Common::KeyCode keyCode) {
+ if ((mask & kEventAttn) != 0)
+ return;
+
+ if (_vm->_gamePhase == kPhaseInGame)
+ _vm->_infoLine->setText(name());
+
+ if (_ref < 0)
+ return; // cannot access system sprites
+
+ if (_ref / 10 == 12) {
+ _vm->optionTouch(_ref % 10, mask);
+ return;
+ }
+
+ if ((mask & kMouseLeftUp) && _vm->_commandHandler->idle()) {
+ if (_vm->isHero(this) && !_vm->_sys->_blinkSprite) {
+ _vm->switchHero((this == _vm->_heroTab[1]->_ptr) ? 1 : 0);
+ } else if (_flags._kept) { // sprite in pocket
+ for (int sex = 0; sex < 2; ++sex) {
+ for (int p = 0; p < kPocketMax; ++p) {
+ if (_vm->_heroTab[sex]->_pocket[p] == this) {
+ _vm->switchHero(sex);
+ if (_vm->_sex == sex) {
+ if (_vm->_sys->_blinkSprite)
+ _vm->_sys->_blinkSprite->_flags._hide = false;
+
+ if (_vm->_sys->_blinkSprite == this)
+ _vm->_sys->_blinkSprite = nullptr;
+ else
+ _vm->_sys->_blinkSprite = this;
+ }
+ }
+ }
+ }
+ } else { // sprite NOT in pocket
+ Hero *h = _vm->_heroTab[_vm->_sex]->_ptr;
+ if (!_vm->_talk) {
+ // the "+3" is a hack used to work around a script issue in scene 5
+ if ((_ref & 0xFF) < 200 && h->distance(this) > (h->_maxDist << 1) + 3)
+ h->walkTo(this);
+ else if (_vm->_sys->_blinkSprite) {
+ if (works(_vm->_sys->_blinkSprite)) {
+ _vm->feedSnail(_vm->_sys->_blinkSprite, (_vm->_sex) ? kMTake : kFTake, _vm->_heroTab[_vm->_sex]->_ptr);
+ _vm->_sys->_blinkSprite->_flags._hide = false;
+ _vm->_sys->_blinkSprite = nullptr;
+ } else
+ _vm->offUse();
+
+ _vm->selectPocket(-1);
+ // else, no pocket sprite selected
+ } else if (_flags._port) { // portable
+ if (_vm->findActivePocket(-1) < 0)
+ _vm->pocFul();
+ else {
+ _vm->_commandHandler->addCommand(kCmdReach, -2, _ref, nullptr);
+ _vm->_commandHandler->addCommand(kCmdKeep, -1, -1, this);
+ _flags._port = false;
+ }
+ } else { // non-portable
+ Action a = h->action();
+ if (_actionCtrl[a]._cnt) {
+ CommandHandler::Command *cmdList = snList(a);
+ if (cmdList[_actionCtrl[a]._ptr]._commandType == kCmdNext)
+ _vm->offUse();
+ else
+ _vm->feedSnail(this, a, h);
+ } else
+ _vm->offUse();
+ }
+ }
+ }
+ }
+}
+
+void CGE2Engine::keyClick() {
+ _commandHandlerTurbo->addCommand(kCmdSound, -1, 5, nullptr);
+}
+
+void CGE2Engine::offUse() {
+ int seq = 0;
+ int offUseCount = atoi(_text->getText(kOffUseCount));
+
+ // This fixes the issue of empty speech bubbles in the original.
+ // Now we only let this cycle pass if it randoms a valid value for getText().
+ int txt = 0;
+ do {
+ txt = kOffUseText + _sex * offUseCount + newRandom(offUseCount);
+ } while (_text->getText(txt) == nullptr);
+
+ Hero *h = _heroTab[_sex]->_ptr;
+ h->park();
+ _commandHandler->addCommand(kCmdWait, -1, -1, h);
+ _commandHandler->addCommand(kCmdSeq, -1, seq, h);
+ if (!_sayVox)
+ _commandHandler->addCommand(kCmdSound, -1, 6 + _sex, h);
+ _commandHandler->addCommand(kCmdWait, -1, -1, h);
+ _commandHandler->addCommand(kCmdSay, -1, txt, h);
+}
+
+Sprite *CGE2Engine::spriteAt(V2D pos) {
+ Sprite *spr;
+
+ for (spr = _vga->_showQ->last(); spr; spr = spr->_prev) {
+ if (!spr->_flags._hide && !spr->_flags._tran && (spr->getShp()->solidAt(pos - spr->_pos2D)))
+ break;
+ }
+
+ return spr;
+}
+
+} // End of namespace CGE2
diff --git a/engines/cge2/cge2_main.h b/engines/cge2/cge2_main.h
new file mode 100644
index 0000000000..4d92c33e50
--- /dev/null
+++ b/engines/cge2/cge2_main.h
@@ -0,0 +1,52 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+/*
+ * This code is based on original Sfinx source code
+ * Copyright (c) 1994-1997 Janus B. Wisniewski and L.K. Avalon
+ */
+
+#ifndef CGE2_MAIN_H
+#define CGE2_MAIN_H
+
+#include "cge2/events.h"
+
+namespace CGE2 {
+
+#define kShowScummVMVersion 15
+
+class System : public Sprite {
+public:
+ int _blinkCounter;
+ Sprite *_blinkSprite;
+
+ System(CGE2Engine *vm);
+
+ virtual void touch(uint16 mask, V2D pos, Common::KeyCode keyCode);
+ void tick();
+private:
+ CGE2Engine *_vm;
+};
+
+} // End of namespace CGE2
+
+#endif // CGE2_MAIN_H
diff --git a/engines/cge2/configure.engine b/engines/cge2/configure.engine
new file mode 100644
index 0000000000..6ccbfee088
--- /dev/null
+++ b/engines/cge2/configure.engine
@@ -0,0 +1,3 @@
+# This file is included from the main "configure" script
+# add_engine [name] [desc] [build-by-default] [subengines] [base games] [deps]
+add_engine cge2 "CGE2" no
diff --git a/engines/cge2/console.cpp b/engines/cge2/console.cpp
new file mode 100644
index 0000000000..c67c7ab788
--- /dev/null
+++ b/engines/cge2/console.cpp
@@ -0,0 +1,33 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "cge2/console.h"
+
+namespace CGE2 {
+
+CGE2Console::CGE2Console(CGE2Engine *vm) : GUI::Debugger() {
+}
+
+CGE2Console::~CGE2Console() {
+}
+
+} // End of namespace CGE
diff --git a/engines/cge2/console.h b/engines/cge2/console.h
new file mode 100644
index 0000000000..15956bf728
--- /dev/null
+++ b/engines/cge2/console.h
@@ -0,0 +1,40 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef CGE2_CONSOLE_H
+#define CGE2_CONSOLE_H
+
+#include "gui/debugger.h"
+
+namespace CGE2 {
+
+class CGE2Engine;
+
+class CGE2Console : public GUI::Debugger {
+public:
+ CGE2Console(CGE2Engine *vm);
+ virtual ~CGE2Console();
+};
+
+} // End of namespace CGE
+
+#endif // CGE2_CONSOLE_H
diff --git a/engines/cge2/detection.cpp b/engines/cge2/detection.cpp
new file mode 100644
index 0000000000..6e1b93d0b8
--- /dev/null
+++ b/engines/cge2/detection.cpp
@@ -0,0 +1,280 @@
+/* ScummVM - Graphic Adventure Engine
+*
+* ScummVM is the legal property of its developers, whose names
+* are too numerous to list here. Please refer to the COPYRIGHT
+* file distributed with this source distribution.
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License
+* as published by the Free Software Foundation; either version 2
+* of the License, or (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software
+* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*/
+
+/*
+ * This code is based on original Sfinx source code
+ * Copyright (c) 1994-1997 Janus B. Wisniewski and L.K. Avalon
+ */
+
+#include "cge2/cge2.h"
+#include "cge2/fileio.h"
+#include "engines/advancedDetector.h"
+#include "common/translation.h"
+#include "graphics/surface.h"
+
+namespace CGE2 {
+
+#define GAMEOPTION_COLOR_BLIND_DEFAULT_OFF GUIO_GAMEOPTIONS1
+
+static const PlainGameDescriptor CGE2Games[] = {
+ { "sfinx", "Sfinx" },
+ { 0, 0 }
+};
+
+static const ADGameDescription gameDescriptions[] = {
+ {
+ "sfinx", "Freeware",
+ {
+ { "vol.cat", 0, "21197b287d397c53261b6616bf0dd880", 129024 },
+ { "vol.dat", 0, "de14291869a8eb7c2732ab783c7542ef", 34180844 },
+ AD_LISTEND
+ },
+ Common::PL_POL, Common::kPlatformDOS, ADGF_NO_FLAGS, GUIO1(GAMEOPTION_COLOR_BLIND_DEFAULT_OFF)
+ },
+
+ {
+ "sfinx", "Freeware v1.0",
+ {
+ {"vol.cat", 0, "aa402aed24a72c53a4d1211c456b79dd", 129024},
+ {"vol.dat", 0, "5966ac26d91d664714349669f9dd09b5", 34180164},
+ AD_LISTEND
+ },
+ Common::PL_POL, Common::kPlatformDOS, ADGF_NO_FLAGS, GUIO1(GAMEOPTION_COLOR_BLIND_DEFAULT_OFF)
+ },
+
+ {
+ "sfinx", "Freeware v0.3",
+ {
+ {"vol.cat", 0, "f158e469dccbebc5a632eb848df89779", 129024},
+ {"vol.dat", 0, "d40a6b4ae173d6930be54ba56bee15d5", 34183430},
+ AD_LISTEND
+ },
+ Common::EN_ANY, Common::kPlatformDOS, ADGF_NO_FLAGS, GUIO1(GAMEOPTION_COLOR_BLIND_DEFAULT_OFF)
+ },
+
+ {
+ "sfinx", "Freeware v1.0",
+ {
+ {"vol.cat", 0, "f158e469dccbebc5a632eb848df89779", 129024},
+ {"vol.dat", 0, "d40a6b4ae173d6930be54ba56bee15d5", 34183443},
+ AD_LISTEND
+ },
+ Common::EN_ANY, Common::kPlatformDOS, ADGF_NO_FLAGS, GUIO1(GAMEOPTION_COLOR_BLIND_DEFAULT_OFF)
+ },
+
+ AD_TABLE_END_MARKER
+};
+
+static const ADExtraGuiOptionsMap optionsList[] = {
+ {
+ GAMEOPTION_COLOR_BLIND_DEFAULT_OFF,
+ {
+ _s("Color Blind Mode"),
+ _s("Enable Color Blind Mode by default"),
+ "enable_color_blind",
+ false
+ }
+ },
+
+ AD_EXTRA_GUI_OPTIONS_TERMINATOR
+};
+
+class CGE2MetaEngine : public AdvancedMetaEngine {
+public:
+ CGE2MetaEngine() : AdvancedMetaEngine(gameDescriptions, sizeof(ADGameDescription), CGE2Games, optionsList) {
+ _singleid = "sfinx";
+ }
+
+ virtual const char *getName() const {
+ return "CGE2";
+ }
+
+ virtual const char *getOriginalCopyright() const {
+ return "Sfinx (c) 1994-1997 Janus B. Wisniewski and L.K. Avalon";
+ }
+
+ virtual const ADGameDescription *fallbackDetect(const FileMap &allFiles, const Common::FSList &fslist) const;
+ virtual bool createInstance(OSystem *syst, Engine **engine, const ADGameDescription *desc) const;
+ virtual bool hasFeature(MetaEngineFeature f) const;
+ virtual int getMaximumSaveSlot() const;
+ virtual SaveStateList listSaves(const char *target) const;
+ SaveStateDescriptor querySaveMetaInfos(const char *target, int slot) const;
+ virtual void removeSaveState(const char *target, int slot) const;
+};
+
+static const ADFileBasedFallback fileBasedFallback[] = {
+ { &gameDescriptions[0], { "vol.cat", "vol.dat", 0 } },
+ { 0, { 0 } }
+};
+
+static ADGameDescription s_fallbackDesc = {
+ "Sfinx",
+ "Unknown version",
+ AD_ENTRY1(0, 0), // This should always be AD_ENTRY1(0, 0) in the fallback descriptor
+ Common::UNK_LANG,
+ Common::kPlatformDOS,
+ ADGF_NO_FLAGS,
+ GUIO1(GAMEOPTION_COLOR_BLIND_DEFAULT_OFF)
+};
+
+// This fallback detection looks identical to the one used for CGE. In fact, the difference resides
+// in the ResourceManager which handles a different archive format. The rest of the detection is identical.
+const ADGameDescription *CGE2MetaEngine::fallbackDetect(const FileMap &allFiles, const Common::FSList &fslist) const {
+ ADFilePropertiesMap filesProps;
+
+ const ADGameDescription *game;
+ game = detectGameFilebased(allFiles, fslist, CGE2::fileBasedFallback, &filesProps);
+
+ if (!game)
+ return 0;
+
+ SearchMan.clear();
+ SearchMan.addDirectory(fslist.begin()->getParent().getPath(), fslist.begin()->getParent());
+ ResourceManager *resman;
+ resman = new ResourceManager();
+ bool result = resman->exist("CGE.SAY");
+ delete resman;
+
+ if (!result)
+ return 0;
+
+ reportUnknown(fslist.begin()->getParent(), filesProps);
+ return &s_fallbackDesc;
+}
+
+bool CGE2MetaEngine::createInstance(OSystem *syst, Engine **engine, const ADGameDescription *desc) const {
+ if (desc)
+ *engine = new CGE2::CGE2Engine(syst, desc);
+
+ return desc != 0;
+}
+
+bool CGE2MetaEngine::hasFeature(MetaEngineFeature f) const {
+ return
+ (f == kSupportsDeleteSave) ||
+ (f == kSavesSupportMetaInfo) ||
+ (f == kSavesSupportThumbnail) ||
+ (f == kSavesSupportCreationDate) ||
+ (f == kSupportsListSaves) ||
+ (f == kSupportsLoadingDuringStartup);
+}
+
+int CGE2MetaEngine::getMaximumSaveSlot() const {
+ return 99;
+}
+
+SaveStateList CGE2MetaEngine::listSaves(const char *target) const {
+ Common::SaveFileManager *saveFileMan = g_system->getSavefileManager();
+ Common::StringArray filenames;
+ Common::String pattern = target;
+ pattern += ".???";
+
+ filenames = saveFileMan->listSavefiles(pattern);
+ sort(filenames.begin(), filenames.end()); // Sort (hopefully ensuring we are sorted numerically..)
+
+ SaveStateList saveList;
+ for (Common::StringArray::const_iterator filename = filenames.begin(); filename != filenames.end(); ++filename) {
+ // Obtain the last 3 digits of the filename, since they correspond to the save slot
+ int slotNum = atoi(filename->c_str() + filename->size() - 3);
+
+ if (slotNum >= 0 && slotNum <= 99) {
+
+ Common::InSaveFile *file = saveFileMan->openForLoading(*filename);
+ if (file) {
+ CGE2::SavegameHeader header;
+
+ // Check to see if it's a ScummVM savegame or not
+ char buffer[kSavegameStrSize + 1];
+ file->read(buffer, kSavegameStrSize + 1);
+
+ if (!strncmp(buffer, kSavegameStr, kSavegameStrSize + 1)) {
+ // Valid savegame
+ if (CGE2::CGE2Engine::readSavegameHeader(file, header)) {
+ saveList.push_back(SaveStateDescriptor(slotNum, header.saveName));
+ if (header.thumbnail) {
+ header.thumbnail->free();
+ delete header.thumbnail;
+ }
+ }
+ } else {
+ // Must be an original format savegame
+ saveList.push_back(SaveStateDescriptor(slotNum, "Unknown"));
+ }
+
+ delete file;
+ }
+ }
+ }
+
+ return saveList;
+}
+
+SaveStateDescriptor CGE2MetaEngine::querySaveMetaInfos(const char *target, int slot) const {
+ Common::String fileName = Common::String::format("%s.%03d", target, slot);
+ Common::InSaveFile *f = g_system->getSavefileManager()->openForLoading(fileName);
+
+ if (f) {
+ CGE2::SavegameHeader header;
+
+ // Check to see if it's a ScummVM savegame or not
+ char buffer[kSavegameStrSize + 1];
+ f->read(buffer, kSavegameStrSize + 1);
+
+ bool hasHeader = !strncmp(buffer, kSavegameStr, kSavegameStrSize + 1) &&
+ CGE2::CGE2Engine::readSavegameHeader(f, header);
+ delete f;
+
+ if (!hasHeader) {
+ // Original savegame perhaps?
+ SaveStateDescriptor desc(slot, "Unknown");
+ return desc;
+ } else {
+ // Create the return descriptor
+ SaveStateDescriptor desc(slot, header.saveName);
+ desc.setThumbnail(header.thumbnail);
+ desc.setSaveDate(header.saveYear, header.saveMonth, header.saveDay);
+ desc.setSaveTime(header.saveHour, header.saveMinutes);
+
+ // Slot 0 is used for the 'automatic save on exit' save in Soltys, thus
+ // we prevent it from being deleted or overwritten by accident.
+ desc.setDeletableFlag(slot != 0);
+ desc.setWriteProtectedFlag(slot == 0);
+
+ return desc;
+ }
+ }
+
+ return SaveStateDescriptor();
+}
+
+void CGE2MetaEngine::removeSaveState(const char *target, int slot) const {
+ Common::String fileName = Common::String::format("%s.%03d", target, slot);
+ g_system->getSavefileManager()->removeSavefile(fileName);
+}
+
+} // End of namespace CGE2
+
+#if PLUGIN_ENABLED_DYNAMIC(CGE2)
+ REGISTER_PLUGIN_DYNAMIC(CGE2, PLUGIN_TYPE_ENGINE, CGE2::CGE2MetaEngine);
+#else
+ REGISTER_PLUGIN_STATIC(CGE2, PLUGIN_TYPE_ENGINE, CGE2::CGE2MetaEngine);
+#endif
diff --git a/engines/cge2/events.cpp b/engines/cge2/events.cpp
new file mode 100644
index 0000000000..85743c8011
--- /dev/null
+++ b/engines/cge2/events.cpp
@@ -0,0 +1,293 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+/*
+ * This code is based on original Sfinx source code
+ * Copyright (c) 1994-1997 Janus B. Wisniewski and L.K. Avalon
+ */
+
+#include "gui/saveload.h"
+#include "gui/about.h"
+#include "gui/message.h"
+#include "common/config-manager.h"
+#include "common/events.h"
+#include "engines/advancedDetector.h"
+#include "cge2/events.h"
+#include "cge2/text.h"
+#include "cge2/cge2_main.h"
+
+namespace CGE2 {
+
+/*----------------- KEYBOARD interface -----------------*/
+
+Keyboard::Keyboard(CGE2Engine *vm) : _client(nullptr), _vm(vm) {
+}
+
+Keyboard::~Keyboard() {
+}
+
+Sprite *Keyboard::setClient(Sprite *spr) {
+ SWAP(_client, spr);
+ return spr;
+}
+
+bool Keyboard::getKey(Common::Event &event) {
+ Common::KeyCode keycode = event.kbd.keycode;
+
+ switch (keycode) {
+ case Common::KEYCODE_F1:
+ if (event.type == Common::EVENT_KEYUP)
+ return false;
+ // Display ScummVM version and translation strings
+ for (int i = 0; i < 3; i++)
+ _vm->_commandHandler->addCommand(kCmdInf, 1, kShowScummVMVersion + i, NULL);
+ return false;
+ case Common::KEYCODE_F5:
+ if (_vm->canSaveGameStateCurrently()) {
+ GUI::SaveLoadChooser *dialog = new GUI::SaveLoadChooser("Save game:", "Save", true);
+ int16 savegameId = dialog->runModalWithCurrentTarget();
+ Common::String savegameDescription = dialog->getResultString();
+ delete dialog;
+
+ if (savegameId != -1)
+ _vm->saveGameState(savegameId, savegameDescription);
+ }
+ return false;
+ case Common::KEYCODE_F7:
+ if (_vm->canLoadGameStateCurrently()) {
+ GUI::SaveLoadChooser *dialog = new GUI::SaveLoadChooser("Restore game:", "Restore", false);
+ int16 savegameId = dialog->runModalWithCurrentTarget();
+ delete dialog;
+
+ if (savegameId != -1)
+ _vm->loadGameState(savegameId);
+ }
+ return false;
+ case Common::KEYCODE_d:
+ if (event.kbd.flags & Common::KBD_CTRL) {
+ // Start the debugger
+ _vm->getDebugger()->attach();
+ _vm->getDebugger()->onFrame();
+ return false;
+ }
+ break;
+ case Common::KEYCODE_x:
+ if (event.kbd.flags & Common::KBD_ALT) {
+ _vm->quit();
+ return false;
+ }
+ break;
+ case Common::KEYCODE_F10:
+ if (_vm->_commandHandler->idle())
+ _vm->switchScene(-1); // Exits the game.
+ return false;
+ default:
+ break;
+ }
+
+ return true;
+}
+
+void Keyboard::newKeyboard(Common::Event &event) {
+ if (!getKey(event))
+ return;
+
+ if ((event.type == Common::EVENT_KEYDOWN) && _client) {
+ CGE2Event &evt = _vm->_eventManager->getNextEvent();
+ evt._x = 0;
+ evt._y = 0;
+ evt._keyCode = event.kbd.keycode; // Keycode
+ evt._mask = kEventKeyb; // Event mask
+ evt._spritePtr = _client; // Sprite pointer
+ }
+}
+
+/*----------------- MOUSE interface -----------------*/
+
+Mouse::Mouse(CGE2Engine *vm) : Sprite(vm), _busy(nullptr), _hold(nullptr), _hx(0), _point(vm), _vm(vm) {
+ _hold = nullptr;
+ _hx = 0;
+ _hy = 0;
+ _exist = true;
+ _buttons = 0;
+ _busy = nullptr;
+ _active = false;
+ _flags._kill = false;
+
+ setSeq(_stdSeq8);
+
+ BitmapPtr MC = new Bitmap[2];
+ MC[0] = Bitmap(_vm, "MOUSE");
+ MC[1] = Bitmap(_vm, "DUMMY");
+ setShapeList(MC, 2);
+
+ step(1);
+ on();
+ off();
+}
+
+Mouse::~Mouse() {
+ off();
+}
+
+void Mouse::on() {
+ if (_seqPtr && _exist) {
+ _active = true;
+ step(0);
+ if (_busy)
+ _busy->step(0);
+ }
+}
+
+void Mouse::off() {
+ if (_seqPtr == 0) {
+ if (_exist)
+ _active = false;
+
+ step(1);
+ if (_busy)
+ _busy->step(1);
+ }
+}
+
+void Mouse::newMouse(Common::Event &event) {
+ if (!_active)
+ return;
+
+ CGE2Event &evt = _vm->_eventManager->getNextEvent();
+ evt._x = event.mouse.x;
+ evt._y = event.mouse.y;
+ evt._keyCode = Common::KEYCODE_INVALID;
+ evt._spritePtr = _vm->spriteAt(V2D(_vm, evt._x, evt._y));
+
+ switch (event.type) {
+ case Common::EVENT_MOUSEMOVE:
+ evt._mask = kMouseRoll;
+ break;
+ case Common::EVENT_LBUTTONDOWN:
+ evt._mask = kMouseLeftDown;
+ _buttons |= 1;
+ break;
+ case Common::EVENT_LBUTTONUP:
+ evt._mask = kMouseLeftUp;
+ _buttons &= ~1;
+ break;
+ case Common::EVENT_RBUTTONDOWN:
+ evt._mask = kMouseRightDown;
+ _buttons |= 2;
+ break;
+ case Common::EVENT_RBUTTONUP:
+ evt._mask = kMouseRightUp;
+ _buttons &= ~2;
+ break;
+ default:
+ break;
+ }
+}
+
+/*----------------- EventManager interface -----------------*/
+
+EventManager::EventManager(CGE2Engine *vm) : _vm(vm) {
+ _eventQueueHead = 0;
+ _eventQueueTail = 0;
+ memset(&_eventQueue, 0, kEventMax * sizeof(CGE2Event));
+ memset(&_event, 0, sizeof(Common::Event));
+}
+
+void EventManager::poll() {
+ while (g_system->getEventManager()->pollEvent(_event)) {
+ _event.mouse.y = kWorldHeight - _event.mouse.y;
+ switch (_event.type) {
+ case Common::EVENT_KEYDOWN:
+ case Common::EVENT_KEYUP:
+ // Handle keyboard events
+ _vm->_keyboard->newKeyboard(_event);
+ handleEvents();
+ break;
+ case Common::EVENT_MOUSEMOVE:
+ case Common::EVENT_LBUTTONDOWN:
+ case Common::EVENT_LBUTTONUP:
+ case Common::EVENT_RBUTTONDOWN:
+ case Common::EVENT_RBUTTONUP:
+ // Handle mouse events
+ _vm->_mouse->newMouse(_event);
+ handleEvents();
+ break;
+ default:
+ break;
+ }
+ }
+}
+
+void EventManager::handleEvents() {
+ while (_eventQueueTail != _eventQueueHead) {
+ CGE2Event e = _eventQueue[_eventQueueTail];
+ _vm->_mouse->_point = V2D(_vm, e._x, e._y);
+ if (e._mask) {
+ if (e._mask & kMouseMask) {
+ e._spritePtr = _vm->spriteAt(_vm->_mouse->_point);
+ e._x += (_vm->_mouse->_siz.x >> 1);
+ e._y -= _vm->_mouse->_siz.y;
+ if (_vm->_mouse->_hold && (e._spritePtr != _vm->_mouse->_hold)) {
+ _vm->_mouse->_hold->touch(e._mask | kEventAttn,
+ V2D(_vm, e._x - _vm->_mouse->_hold->_pos2D.x, e._y - _vm->_mouse->_hold->_pos2D.y), e._keyCode);
+ }
+ // update mouse cursor position
+ if (e._mask & kMouseRoll)
+ _vm->_mouse->gotoxyz(V2D(_vm, e._x, e._y));
+ }
+
+ // activate current touched SPRITE
+ if (e._spritePtr) {
+ if (e._mask & kEventKeyb)
+ e._spritePtr->touch(e._mask, _vm->_mouse->_point, e._keyCode);
+ else
+ e._spritePtr->touch(e._mask, _vm->_mouse->_point - e._spritePtr->_pos2D, e._keyCode);
+ } else if (_vm->_sys)
+ _vm->_sys->touch(e._mask, _vm->_mouse->_point, e._keyCode);
+
+ // discard Text if button released
+ if (e._mask & (kMouseLeftUp | kMouseRightUp))
+ _vm->killText();
+ }
+ _eventQueueTail = (_eventQueueTail + 1) % kEventMax;
+ }
+}
+
+void EventManager::clearEvent(Sprite *spr) {
+ if (spr) {
+ for (uint16 e = _eventQueueTail; e != _eventQueueHead; e = (e + 1) % kEventMax) {
+ if (_eventQueue[e]._spritePtr == spr)
+ _eventQueue[e]._mask = 0;
+ }
+ } else
+ _eventQueueTail = _eventQueueHead;
+}
+
+CGE2Event &EventManager::getNextEvent() {
+ CGE2Event &evt = _eventQueue[_eventQueueHead];
+ _eventQueueHead = (_eventQueueHead + 1) % kEventMax;
+
+ return evt;
+}
+
+} // End of namespace CGE2
diff --git a/engines/cge2/events.h b/engines/cge2/events.h
new file mode 100644
index 0000000000..d1aaca2ded
--- /dev/null
+++ b/engines/cge2/events.h
@@ -0,0 +1,116 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+/*
+ * This code is based on original Sfinx source code
+ * Copyright (c) 1994-1997 Janus B. Wisniewski and L.K. Avalon
+ */
+
+#ifndef CGE2_EVENTS_H
+#define CGE2_EVENTS_H
+
+#include "common/events.h"
+#include "cge2/talk.h"
+#include "cge2/vga13h.h"
+
+namespace CGE2 {
+
+/*----------------- KEYBOARD interface -----------------*/
+
+#define kEventMax 256
+
+enum EventMask {
+ kMouseRoll = 1 << 0,
+ kMouseLeftDown = 1 << 1,
+ kMouseLeftUp = 1 << 2,
+ kMouseRightDown = 1 << 3,
+ kMouseRightUp = 1 << 4,
+ kEventAttn = 1 << 5,
+ kMouseMask = (kMouseRoll | kMouseLeftDown | kMouseLeftUp | kMouseRightDown | kMouseRightUp),
+ kEventKeyb = 1 << 7
+};
+
+class Keyboard {
+private:
+ bool getKey(Common::Event &event);
+ CGE2Engine *_vm;
+public:
+ Sprite *_client;
+
+ void newKeyboard(Common::Event &event);
+ Sprite *setClient(Sprite *spr);
+
+ Keyboard(CGE2Engine *vm);
+ ~Keyboard();
+};
+
+/*----------------- MOUSE interface -----------------*/
+
+struct CGE2Event {
+ uint16 _mask;
+ uint16 _x;
+ uint16 _y;
+ Common::KeyCode _keyCode;
+ Sprite *_spritePtr;
+};
+
+class Mouse : public Sprite {
+public:
+ V2D _point;
+ Sprite *_hold;
+ bool _active;
+ int _hx;
+ int _hy;
+ bool _exist;
+ int _buttons;
+ Sprite *_busy;
+ Mouse(CGE2Engine *vm);
+ ~Mouse();
+ void on();
+ void off();
+ void newMouse(Common::Event &event);
+private:
+ CGE2Engine *_vm;
+};
+
+/*----------------- EventManager interface -----------------*/
+
+class EventManager {
+private:
+ CGE2Engine *_vm;
+ Common::Event _event;
+ CGE2Event _eventQueue[kEventMax];
+ uint16 _eventQueueHead;
+ uint16 _eventQueueTail;
+
+ void handleEvents();
+public:
+ EventManager(CGE2Engine *vm);
+ void poll();
+ void clearEvent(Sprite *spr);
+
+ CGE2Event &getNextEvent();
+};
+
+} // End of namespace CGE
+
+#endif // #define CGE2_EVENTS_H
diff --git a/engines/cge2/fileio.cpp b/engines/cge2/fileio.cpp
new file mode 100644
index 0000000000..acb5bb870f
--- /dev/null
+++ b/engines/cge2/fileio.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.
+ *
+ */
+
+/*
+ * This code is based on original Sfinx source code
+ * Copyright (c) 1994-1997 Janus B. Wisniewski and L.K. Avalon
+ */
+
+#include "common/system.h"
+#include "common/str.h"
+#include "common/debug.h"
+#include "common/debug-channels.h"
+#include "common/memstream.h"
+#include "cge2/cge2.h"
+#include "cge2/fileio.h"
+
+namespace CGE2 {
+
+/*-----------------------------------------------------------------------
+ * BtPage
+ *-----------------------------------------------------------------------*/
+void BtPage::readBTree(Common::ReadStream &s) {
+ _header._count = s.readUint16LE();
+ _header._down = s.readUint16LE();
+
+ if (_header._down == kBtValNone) {
+ // Leaf list
+ for (int i = 0; i < kBtLeafCount; ++i) {
+ s.read(_leaf[i]._key, kBtKeySize);
+ _leaf[i]._pos = s.readUint32LE();
+ _leaf[i]._size = s.readUint32LE();
+ }
+ } else {
+ // Root index
+ for (int i = 0; i < kBtInnerCount; ++i) {
+ s.read(_inner[i]._key, kBtKeySize);
+ _inner[i]._down = s.readUint16LE();
+ }
+ }
+}
+
+/*-----------------------------------------------------------------------
+ * ResourceManager
+ *-----------------------------------------------------------------------*/
+ResourceManager::ResourceManager() {
+ _datFile = new Common::File();
+ _datFile->open(kDatName);
+
+ _catFile = new Common::File();
+ _catFile->open(kCatName);
+
+ if (!_datFile->isOpen() || !_catFile->isOpen())
+ error("Unable to open data files");
+
+ for (int i = 0; i < kBtLevel; i++) {
+ _buff[i]._page = new BtPage;
+ _buff[i]._pageNo = kBtValNone;
+ _buff[i]._index = -1;
+ assert(_buff[i]._page != nullptr);
+ }
+}
+
+ResourceManager::~ResourceManager() {
+ _datFile->close();
+ delete _datFile;
+
+ _catFile->close();
+ delete _catFile;
+
+ for (int i = 0; i < kBtLevel; i++)
+ delete _buff[i]._page;
+}
+
+void ResourceManager::xCrypt(byte *buf, uint16 length) {
+ byte *b = buf;
+
+ for (uint16 i = 0; i < length; i++)
+ *b++ ^= kCryptSeed;
+}
+
+bool ResourceManager::seek(int32 offs, int whence) {
+ return _datFile->seek(offs, whence);
+}
+
+uint16 ResourceManager::read(byte *buf, uint16 length) {
+ if (!_datFile->isOpen())
+ return 0;
+
+ uint16 bytesRead = _datFile->read(buf, length);
+ if (!bytesRead)
+ error("Read %s - %d bytes", _datFile->getName(), length);
+ xCrypt(buf, length);
+ return bytesRead;
+}
+
+BtPage *ResourceManager::getPage(int level, uint16 pageId) {
+ if (_buff[level]._pageNo != pageId) {
+ int32 pos = pageId * kBtSize;
+ _buff[level]._pageNo = pageId;
+
+ if (_catFile->size() <= pos)
+ return nullptr;
+
+ // In the original, there was a check verifying if the
+ // purpose was to write a new file. This should only be
+ // to create a new file, thus it was removed.
+ _catFile->seek(pageId * kBtSize, SEEK_SET);
+
+ // Read in the page
+ byte buffer[kBtSize];
+ int bytesRead = catRead(buffer, kBtSize);
+
+ // Unpack it into the page structure
+ Common::MemoryReadStream stream(buffer, bytesRead, DisposeAfterUse::NO);
+ _buff[level]._page->readBTree(stream);
+ _buff[level]._index = -1;
+ }
+ return _buff[level]._page;
+}
+
+BtKeypack *ResourceManager::find(const char *key) {
+ int lev = 0;
+ uint16 nxt = kBtValRoot;
+ while (!_catFile->eos()) {
+ BtPage *pg = getPage(lev, nxt);
+ if (!pg)
+ return nullptr;
+
+ // search
+ if (pg->_header._down != kBtValNone) {
+ int i;
+ for (i = 0; i < pg->_header._count; i++) {
+ // Does this work, or does it have to compare the entire buffer?
+ if (scumm_strnicmp((const char *)key, (const char*)pg->_inner[i]._key, kBtKeySize) < 0)
+ break;
+ }
+ nxt = (i) ? pg->_inner[i - 1]._down : pg->_header._down;
+ _buff[lev]._index = i - 1;
+ lev++;
+ } else {
+ int i;
+ for (i = 0; i < pg->_header._count - 1; i++) {
+ if (scumm_stricmp((const char *)key, (const char *)pg->_leaf[i]._key) <= 0)
+ break;
+ }
+
+ // Hack to work around a mix between 24piram_ and 24pirami
+ if (!strcmp(key, "24piram_.SPR") && (scumm_stricmp((const char *)key, (const char *)pg->_leaf[i]._key) < 0))
+ ++i;
+ //
+
+ _buff[lev]._index = i;
+ return &pg->_leaf[i];
+ }
+ }
+ return nullptr;
+}
+
+bool ResourceManager::exist(const char *name) {
+ BtKeypack *result = find(name);
+ if (!result)
+ return false;
+
+ return scumm_stricmp(result->_key, name) == 0;
+}
+
+uint16 ResourceManager::catRead(byte *buf, uint16 length) {
+ if (!_catFile->isOpen())
+ return 0;
+
+ uint16 bytesRead = _catFile->read(buf, length);
+ if (!bytesRead)
+ error("Read %s - %d bytes", _catFile->getName(), length);
+ xCrypt(buf, length);
+ return bytesRead;
+}
+
+/*-----------------------------------------------------------------------
+ * EncryptedStream
+ *-----------------------------------------------------------------------*/
+EncryptedStream::EncryptedStream(CGE2Engine *vm, const char *name) : _vm(vm), _lineCount(0) {
+ _error = false;
+ BtKeypack *kp = _vm->_resman->find(name);
+ if (scumm_stricmp(kp->_key, name) != 0)
+ _error = true;
+
+ _vm->_resman->seek(kp->_pos);
+ byte *dataBuffer;
+ int bufSize;
+
+ if ((strlen(name) > 4) && (scumm_stricmp(name + strlen(name) - 4, ".SPR") == 0)) {
+ // SPR files have some inconsistencies. Some have extra 0x1A at the end, some others
+ // do not have a carriage return at the end of the last line
+ // Therefore, we remove this ending 0x1A and add extra new lines.
+ // This fixes bug #3537527
+ dataBuffer = (byte *)malloc(kp->_size + 2);
+ _vm->_resman->read(dataBuffer, kp->_size);
+ if (dataBuffer[kp->_size - 1] == 0x1A)
+ dataBuffer[kp->_size - 1] = '\n';
+ dataBuffer[kp->_size] = '\n';
+ dataBuffer[kp->_size + 1] = '\n';
+ bufSize = kp->_size + 2;
+ } else {
+ dataBuffer = (byte *)malloc(kp->_size);
+ _vm->_resman->read(dataBuffer, kp->_size);
+ bufSize = kp->_size;
+ }
+
+ _readStream = new Common::MemoryReadStream(dataBuffer, bufSize, DisposeAfterUse::YES);
+}
+
+uint32 EncryptedStream::read(byte *dataPtr, uint32 dataSize) {
+ return _readStream->read(dataPtr, dataSize);
+}
+
+int16 EncryptedStream::readSint16LE() {
+ return _readStream->readSint16LE();
+}
+
+uint32 EncryptedStream::readUint32LE() {
+ return _readStream->readUint32LE();
+}
+
+bool EncryptedStream::err() {
+ return (_error || _readStream->err());
+}
+
+bool EncryptedStream::eos() {
+ return _readStream->eos();
+}
+
+bool EncryptedStream::seek(int32 offset) {
+ return _readStream->seek(offset);
+}
+
+Common::String EncryptedStream::readLine() {
+ _lineCount++;
+ Common::String line = _readStream->readLine();
+ if (!line.empty() && (line[0] == ';' || line[0] == '.' || line[0] == '*'))
+ line.clear(); // Returns an empty string, if the line is invalid.
+ return line;
+}
+
+int32 EncryptedStream::size() {
+ return _readStream->size();
+}
+
+int32 EncryptedStream::pos() {
+ return _readStream->pos();
+}
+
+EncryptedStream::~EncryptedStream() {
+ delete _readStream;
+}
+
+const char *EncryptedStream::kIdTab[] = {
+ "[near]", "[mtake]", "[ftake]", "[phase]", "[seq]",
+ "Name", "Type", "Front", "East",
+ "Portable", "Transparent",
+ nullptr
+};
+
+} // End of namespace CGE2
diff --git a/engines/cge2/fileio.h b/engines/cge2/fileio.h
new file mode 100644
index 0000000000..e236c73b49
--- /dev/null
+++ b/engines/cge2/fileio.h
@@ -0,0 +1,133 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+/*
+ * This code is based on original Sfinx source code
+ * Copyright (c) 1994-1997 Janus B. Wisniewski and L.K. Avalon
+ */
+
+#ifndef CGE2_FILEIO_H
+#define CGE2_FILEIO_H
+
+#include "common/file.h"
+
+namespace CGE2 {
+
+class CGE2Engine;
+
+#define kBtSize 2048
+#define kBtKeySize 13
+#define kBtLevel 2
+#define kBtInnerCount ((kBtSize - 4 /*sizeof(Header) */) / (kBtKeySize + 2 /*sizeof(Inner) */))
+#define kBtLeafCount ((kBtSize - 4 /*sizeof(Header) */) / (kBtKeySize + 4 + 4 /*sizeof(BtKeypack) */))
+#define kBtValNone 0xFFFF
+#define kBtValRoot 0
+#define kCatName "VOL.CAT"
+#define kDatName "VOL.DAT"
+#define kCryptSeed 0xA5
+
+enum ID {
+ kIdNear, kIdMTake, kIdFTake, kIdPhase, kIdSeq,
+ kIdName, kIdType, kIdFront, kIdEast,
+ kIdPortable, kIdTransparent,
+ kIdNone = -1
+};
+
+struct BtKeypack {
+ char _key[kBtKeySize];
+ uint32 _pos;
+ uint32 _size;
+};
+
+struct Inner {
+ uint8 _key[kBtKeySize];
+ uint16 _down;
+};
+
+struct Header {
+ uint16 _count;
+ uint16 _down;
+};
+
+struct BtPage {
+ Header _header;
+ union {
+ // dummy filler to make proper size of union
+ uint8 _data[kBtSize - 4]; /* 4 is the size of struct Header */
+ // inner version of data: key + word-sized page link
+ Inner _inner[kBtInnerCount];
+ // leaf version of data: key + all user data
+ BtKeypack _leaf[kBtLeafCount];
+ };
+
+ void readBTree(Common::ReadStream &s);
+};
+
+class ResourceManager {
+private:
+ struct {
+ BtPage *_page;
+ uint16 _pageNo;
+ int _index;
+ } _buff[kBtLevel];
+
+ BtPage *getPage(int level, uint16 pageId);
+ uint16 catRead(byte *buf, uint16 length);
+ Common::File *_catFile;
+ Common::File *_datFile;
+ void xCrypt(byte *buf, uint16 length);
+public:
+ ResourceManager();
+ ~ResourceManager();
+ uint16 read(byte *buf, uint16 length);
+ bool seek(int32 offs, int whence = SEEK_SET);
+
+ BtKeypack *find(const char *key);
+ bool exist(const char *name);
+};
+
+class EncryptedStream {
+private:
+ CGE2Engine *_vm;
+ Common::SeekableReadStream *_readStream;
+ int _lineCount;
+ bool _error;
+public:
+ EncryptedStream(CGE2Engine *vm, const char *name);
+ ~EncryptedStream();
+ bool err();
+ bool eos();
+ bool seek(int32 offset);
+ int32 pos();
+ int32 size();
+ uint32 read(byte *dataPtr, uint32 dataSize);
+ int16 readSint16LE();
+ uint32 readUint32LE();
+ Common::String readLine();
+ int getLineCount() { return _lineCount; }
+
+ static const char *kIdTab[];
+};
+
+} // End of namespace CGE2
+
+#endif // CGE2_FILEIO_H
diff --git a/engines/cge2/general.h b/engines/cge2/general.h
new file mode 100644
index 0000000000..7213c2e24d
--- /dev/null
+++ b/engines/cge2/general.h
@@ -0,0 +1,45 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+/*
+ * This code is based on original Sfinx source code
+ * Copyright (c) 1994-1997 Janus B. Wisniewski and L.K. Avalon
+ */
+
+#ifndef CGE2_GENERAL_H
+#define CGE2_GENERAL_H
+
+#include "common/file.h"
+
+namespace CGE2 {
+
+class CGE2Engine;
+
+struct Dac {
+ uint8 _r;
+ uint8 _g;
+ uint8 _b;
+};
+
+} // End of namespace CGE2
+
+#endif // CGE2_GENERAL_H
diff --git a/engines/cge2/hero.cpp b/engines/cge2/hero.cpp
new file mode 100644
index 0000000000..42ae67cc2b
--- /dev/null
+++ b/engines/cge2/hero.cpp
@@ -0,0 +1,622 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+/*
+ * This code is based on original Sfinx source code
+ * Copyright (c) 1994-1997 Janus B. Wisniewski and L.K. Avalon
+ */
+
+#include "cge2/hero.h"
+#include "cge2/text.h"
+#include "cge2/map.h"
+
+namespace CGE2 {
+
+Hero::Hero(CGE2Engine *vm) : Sprite(vm), _contact(nullptr), _dir(kNoDir),
+ _curDim(0), _tracePtr(-1), _ignoreMap(false), _maxDist(0) {
+
+ for (int i = 0; i < kDimMax; i++)
+ _dim[i] = nullptr;
+
+ _reachStart = _reachCycle = _sayStart = _funStart = 0;
+ _funDel0 = _funDel = 0;
+}
+
+Hero::~Hero() {
+ contract();
+}
+
+Sprite *Hero::expand() {
+ if (_ext)
+ return this;
+
+ char fname[kMaxPath];
+ _vm->mergeExt(fname, _file, kSprExt);
+
+ if (_ext != nullptr)
+ delete _ext;
+
+ _ext = new SprExt(_vm);
+
+ if (!*_file)
+ return this;
+
+ for (int i = 0; i < kDimMax; i++) {
+ if (_dim[i] != nullptr) {
+ delete[] _dim[i];
+ _dim[i] = nullptr;
+ }
+ }
+ for (int i = 0; i < kDimMax; i++) {
+ _dim[i] = new Bitmap[_shpCnt];
+ for (int j = 0; j < _shpCnt; j++)
+ _dim[i][j].setVM(_vm);
+ }
+
+ int cnt[kActions];
+
+ for (int i = 0; i < kActions; i++)
+ cnt[i] = 0;
+
+ for (int i = 0; i < kActions; i++) {
+ byte n = _actionCtrl[i]._cnt;
+ if (n)
+ _ext->_actions[i] = new CommandHandler::Command[n];
+ else
+ _ext->_actions[i] = nullptr;
+ }
+
+ Seq *curSeq = nullptr;
+ if (_seqCnt)
+ curSeq = new Seq[_seqCnt];
+
+ if (_vm->_resman->exist(fname)) { // sprite description file exist
+ EncryptedStream sprf(_vm, fname);
+ if (sprf.err())
+ error("Bad SPR [%s]", fname);
+
+ ID section = kIdPhase;
+ ID id;
+ Common::String line;
+ char tmpStr[kLineMax + 1];
+ int shpcnt = 0;
+ int seqcnt = 0;
+ int maxnow = 0;
+ int maxnxt = 0;
+
+ for (line = sprf.readLine(); !sprf.eos(); line = sprf.readLine()) {
+ if (line.empty())
+ continue;
+ Common::strlcpy(tmpStr, line.c_str(), sizeof(tmpStr));
+
+ char *p = _vm->token(tmpStr);
+
+ id = _vm->ident(p);
+ switch (id) {
+ case kIdNear:
+ case kIdMTake:
+ case kIdFTake:
+ case kIdPhase:
+ case kIdSeq:
+ section = id;
+ break;
+ case kIdName:
+ Common::strlcpy(tmpStr, line.c_str(), sizeof(tmpStr));
+ for (p = tmpStr; *p != '='; p++) // We search for the =
+ ;
+ setName(_vm->tail(p));
+ break;
+ default:
+ if (id >= kIdNear)
+ break;
+ Seq *s;
+ switch (section) {
+ case kIdNear:
+ case kIdMTake:
+ case kIdFTake:
+ id = (ID)_vm->_commandHandler->getComId(p);
+ if (_actionCtrl[section]._cnt) {
+ CommandHandler::Command *c = &_ext->_actions[section][cnt[section]++];
+ c->_commandType = CommandType(id);
+ c->_ref = _vm->number(nullptr);
+ c->_val = _vm->number(nullptr);
+ c->_spritePtr = nullptr;
+ }
+ break;
+ case kIdSeq:
+ s = &curSeq[seqcnt++];
+ s->_now = atoi(p);
+ if (s->_now > maxnow)
+ maxnow = s->_now;
+ s->_next = _vm->number(nullptr);
+ switch (s->_next) {
+ case 0xFF:
+ s->_next = seqcnt;
+ break;
+ case 0xFE:
+ s->_next = seqcnt - 1;
+ break;
+ }
+ if (s->_next > maxnxt)
+ maxnxt = s->_next;
+ s->_dx = _vm->number(nullptr);
+ s->_dy = _vm->number(nullptr);
+ s->_dz = _vm->number(nullptr);
+ s->_dly = _vm->number(nullptr);
+ break;
+ case kIdPhase:
+ for (int i = 0; i < kDimMax; i++) {
+ char *q = p;
+ q[1] = '0' + i;
+ Bitmap b(_vm, q);
+ _dim[i][shpcnt] = b;
+ if (!shpcnt)
+ _hig[i] = b._h;
+ }
+ ++shpcnt;
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+ if (curSeq) {
+ if (maxnow >= shpcnt)
+ error("Bad PHASE in SEQ %s", fname);
+ if (maxnxt >= seqcnt)
+ error("Bad JUMP in SEQ %s", fname);
+ setSeq(curSeq);
+ } else
+ setSeq(_stdSeq8);
+
+ setShapeList(_dim[0], shpcnt);
+ }
+
+ char *tempStr = _vm->_text->getText(_ref + 100);
+ char *text = new char[strlen(tempStr) + 1];
+ strcpy(text, tempStr);
+ _reachStart = atoi(_vm->token(text));
+ _reachCycle = atoi(_vm->token(nullptr));
+ _sayStart = atoi(_vm->token(nullptr));
+ _funStart = atoi(_vm->token(nullptr));
+ _funDel = _funDel0 = (72 / _ext->_seq[0]._dly) * atoi(_vm->token(nullptr));
+ delete[] text;
+
+ int i = stepSize() / 2;
+ _maxDist = (int)sqrt(double(i * i * 2));
+ setCurrent();
+
+ return this;
+}
+
+Sprite *Hero::contract() {
+ for (int i = 0; i < kDimMax; i++) {
+ if (_dim[i] != nullptr) {
+ delete[] _dim[i];
+ if (_ext->_shpList == _dim[i])
+ _ext->_shpList = nullptr;
+ _dim[i] = nullptr;
+ }
+ }
+ Sprite::contract();
+ return this;
+}
+
+void Hero::setCurrent() {
+ FXP m = _vm->_eye->_z / (_pos3D._z - _vm->_eye->_z);
+ FXP tmp = m * _siz.y;
+ int h = -(tmp.trunc());
+
+ int i = 0;
+ for (; i < kDimMax - 1; i++) {
+ if (h >= (_hig[i] + _hig[i + 1]) / 2)
+ break;
+ }
+
+ _ext->_shpList = _dim[_curDim = i];
+}
+
+void Hero::hStep() {
+ if (!_ignoreMap && _ext) {
+ Seq *seq = _ext->_seq;
+ int ptr = seq[_seqPtr]._next;
+ seq += ptr;
+ if (seq->_dx | seq->_dz) {
+ V2D p0(_vm, _pos3D._x.round(), _pos3D._z.round());
+ V2D p1(_vm, p0.x + seq->_dx, p0.y + seq->_dz);
+ if (mapCross(p0, p1)) {
+ park();
+ return;
+ }
+ }
+ }
+ step();
+}
+
+Sprite *Hero::setContact() {
+ Sprite *spr;
+ int md = _maxDist << 1;
+ for (spr = _vm->_vga->_showQ->first(); spr; spr = spr->_next) {
+ if (spr->_actionCtrl[kNear]._cnt && ((spr->_ref & 255) != 255) && (distance(spr) <= md)) {
+ if (spr == _contact)
+ return nullptr;
+ else
+ break;
+ }
+ }
+ return (_contact = spr);
+}
+
+void Hero::tick() {
+ int z = _pos3D._z.trunc();
+ //-- maybe not exactly wid/2, but wid/3 ?
+ int d = ((_siz.x / 2) * _vm->_eye->_z.trunc()) / (_vm->_eye->_z.trunc() - z);
+
+ if (_dir != kNoDir) { // just walking...
+ if (_flags._hold || _tracePtr < 0)
+ park();
+ else {
+ Sprite *spr = setContact();
+ if (spr)
+ _vm->feedSnail(spr, kNear, this);
+ }
+ }
+ //---------------------------------------------------------------
+ if (_tracePtr >= 0) {
+ if (distance(_trace[_tracePtr]) <= _maxDist)
+ --_tracePtr;
+
+ if (_tracePtr < 0)
+ park();
+ else {
+ int stp = stepSize() / 2;
+ int dx = _trace[_tracePtr]._x.round() - _pos3D._x.round();
+ int dz = _trace[_tracePtr]._z.round() - _pos3D._z.round();
+ Dir dir = (dx > stp) ? kEE : ((-dx > stp) ? kWW : ((dz > stp) ? kNN : kSS));
+ turn(dir);
+ }
+ }
+
+ //---------------------------------------------------------------
+ hStep();
+ setCurrent();
+ switch (_dir) {
+ case kSS:
+ if (_pos3D._z < stepSize() / 2)
+ park();
+ break;
+ case kWW:
+ if (_pos2D.x <= d)
+ park();
+ break;
+ case kNN:
+ if (_pos3D._z > kScrDepth)
+ park();
+ break;
+ case kEE:
+ if (_pos2D.x >= kScrWidth - 1 - d)
+ park();
+ break;
+ default:
+ break;
+ }
+ if (_flags._trim)
+ gotoxyz_(_pos2D);
+
+ if (_pos3D._z.trunc() != z)
+ _flags._zmov = true;
+
+ if (--_funDel == 0)
+ fun();
+}
+
+int Hero::distance(V3D pos) {
+ V3D di = _pos3D - pos;
+ int x = di._x.round();
+ int z = di._z.round();
+ int retval = (int)sqrt((double)x * x + z * z);
+ return retval;
+}
+
+int Hero::distance(Sprite *spr) {
+ V3D pos = spr->_pos3D;
+ int mdx = (spr->_siz.x >> 1) + (_siz.x >> 1);
+ int dx = (_pos3D._x - spr->_pos3D._x).round();
+ if (dx < 0) {
+ mdx = -mdx;
+ if (dx > mdx)
+ pos._x = _pos3D._x;
+ else
+ pos._x += mdx;
+ } else if (dx < mdx)
+ pos._x = _pos3D._x;
+ else
+ pos._x += mdx;
+
+ return distance(pos);
+}
+
+void Hero::turn(Dir d) {
+ Dir dir = (_dir == kNoDir) ? kSS : _dir;
+ if (d != _dir) {
+ step((d == dir) ? 57 : (8 + 4 * dir + d));
+ _dir = d;
+ }
+ resetFun();
+}
+
+void Hero::park() {
+ if (_dir != kNoDir) {
+ step(8 + 5 * _dir);
+ _dir = kNoDir;
+ _trace[0] = _pos3D;
+ _tracePtr = -1;
+ setCurrent();
+ _flags._zmov = true;
+ }
+ _ignoreMap = false;
+ if (_time == 0)
+ ++_time;
+}
+
+bool Hero::lower(Sprite * spr) {
+ return (spr->_pos3D._y + (spr->_siz.y >> 2) < 10);
+}
+
+void Hero::reach(int mode) {
+ Sprite *spr = nullptr;
+ if (mode >= 4) {
+ spr = _vm->_vga->_showQ->locate(mode);
+ if (spr) {
+ mode = !spr->_flags._east; // 0-1
+ if (lower(spr)) // 2-3
+ mode += 2;
+ }
+ }
+ // note: insert SNAIL commands in reverse order
+ _vm->_commandHandler->insertCommand(kCmdPause, -1, 24, nullptr);
+ _vm->_commandHandler->insertCommand(kCmdSeq, -1, _reachStart + _reachCycle * mode, this);
+ if (spr) {
+ _vm->_commandHandler->insertCommand(kCmdWait, -1, -1, this);
+ _vm->_commandHandler->insertCommand(kCmdWalk, -1, spr->_ref, this);
+ }
+ // sequence is not finished,
+ // now it is just at sprite appear (disappear) point
+ resetFun();
+}
+
+void Hero::fun() {
+ if (_vm->_commandHandler->idle()) {
+ park();
+ _vm->_commandHandler->addCommand(kCmdWait, -1, -1, this);
+ _vm->_commandHandler->addCommand(kCmdSeq, -1, _funStart, this);
+ }
+ _funDel = _funDel0 >> 2;
+}
+
+int Hero::len(V2D v) {
+ return (int)sqrt(double(v.x * v.x + v.y * v.y));
+}
+
+bool Hero::findWay(){
+ V2D p0(_vm, _pos3D._x.round(), _pos3D._z.round());
+ V2D p1(_vm, _trace[_tracePtr]._x.round(), _trace[_tracePtr]._z.round());
+ V2D ph(_vm, p1.x, p0.y);
+ V2D pv(_vm, p0.x, p1.y);
+ bool pvOk = (!mapCross(p0, pv) && !mapCross(pv, p1));
+ bool phOk = (!mapCross(p0, ph) && !mapCross(ph, p1));
+ int md = (_maxDist >> 1);
+ if (pvOk && (len(ph - p0) <= md || len(p1 - ph) <= md))
+ return true;
+
+ if (phOk && (len(pv - p0) <= md || len(p1 - pv) <= md))
+ return true;
+
+ if (pvOk) {
+ _trace[++_tracePtr] = V3D(pv.x, 0, pv.y);
+ return true;
+ }
+
+ if (phOk) {
+ _trace[++_tracePtr] = V3D(ph.x, 0, ph.y);
+ return true;
+ }
+
+ return false;
+}
+
+int Hero::snap(int p, int q, int grid) {
+ int d = abs(q - p) % grid;
+ if (d > (grid >> 1))
+ d -= grid;
+ return (q >= p) ? (q - d) : (q + d);
+}
+
+void Hero::walkTo(V3D pos) {
+ if (distance(pos) <= _maxDist)
+ return;
+
+ int stp = stepSize();
+ pos._x = snap(_pos3D._x.round(), pos._x.round(), stp);
+ pos._y = 0;
+ pos._z = snap(_pos3D._z.round(), pos._z.round(), stp);
+
+ V2D p0(_vm, _pos3D._x.round(), _pos3D._z.round());
+ V2D p1(_vm, pos._x.round(), pos._z.round());
+ resetFun();
+ int cnt = mapCross(p0, p1);
+ if ((cnt & 1) == 0) { // even == way exists
+ _trace[_tracePtr = 0] = pos;
+ if (!findWay()) {
+ int i;
+ ++_tracePtr;
+ for (i = stp; i < kMaxTry; i += stp) {
+ _trace[_tracePtr] = pos + V3D(i, 0, 0);
+ if (!mapCross(_trace[_tracePtr - 1], _trace[_tracePtr]) && findWay())
+ break;
+
+ _trace[_tracePtr] = pos + V3D(-i, 0, 0);
+ if (!mapCross(_trace[_tracePtr - 1], _trace[_tracePtr]) && findWay())
+ break;
+
+ _trace[_tracePtr] = pos + V3D(0, 0, i);
+ if (!mapCross(_trace[_tracePtr - 1], _trace[_tracePtr]) && findWay())
+ break;
+
+ _trace[_tracePtr] = pos + V3D(0, 0, -i);
+ if (!mapCross(_trace[_tracePtr - 1], _trace[_tracePtr]) && findWay())
+ break;
+ }
+ if (i >= kMaxTry)
+ _trace[_tracePtr] = V3D(_pos3D._x, 0, pos._z); // not found
+ }
+ }
+}
+
+void Hero::walkTo(Sprite *spr) {
+ int mdx = _siz.x >> 1;
+ int stp = (stepSize() + 1) / 2;
+ if (!spr->_flags._east)
+ mdx = -mdx;
+ walkTo(spr->_pos3D + V3D(mdx, 0, (!spr->_flags._frnt || spr->_pos3D._z < 8) ? stp : -stp));
+}
+
+V3D Hero::screenToGround(V2D pos) {
+ FXP z = _vm->_eye->_z + (_vm->_eye->_y * _vm->_eye->_z) / (FXP(pos.y) - _vm->_eye->_y);
+ FXP x = _vm->_eye->_x - ((FXP(pos.x) - _vm->_eye->_x) * (z - _vm->_eye->_z)) / _vm->_eye->_z;
+ return V3D(x.round(), 0, z.round());
+}
+
+int Hero::cross(const V2D &a, const V2D &b) {
+ int x = _pos3D._x.trunc();
+ int z = _pos3D._z.trunc();
+ int r = ((_siz.x / 3) * _vm->_eye->_z.trunc()) / (_vm->_eye->_z.trunc() - z);
+ return _vm->cross(a, b, V2D(_vm, x - r, z), V2D(_vm, x + r, z)) << 1;
+}
+
+bool CGE2Engine::cross(const V2D &a, const V2D &b, const V2D &c, const V2D &d) {
+ if (contain(a, b, c) || contain(a, b, d) || contain(c, d, a) || contain(c, d, b))
+ return true;
+
+ return sgn(det(a, b, c)) != sgn(det(a, b, d)) && sgn(det(c, d, a)) != sgn(det(c, d, b));
+}
+
+bool CGE2Engine::contain(const V2D &a, const V2D &b, const V2D &p) {
+ if (det(a, b, p))
+ return false;
+
+ return ((long)(a.x - p.x) * (p.x - b.x) >= 0 && (long)(a.y - p.y) * (p.y - b.y) >= 0);
+}
+
+long CGE2Engine::det(const V2D &a, const V2D &b, const V2D &c) {
+ return ((long)a.x * b.y + (long)b.x * c.y + (long)c.x * a.y) - ((long)c.x * b.y + (long)b.x * a.y + (long)a.x * c.y);
+}
+
+int CGE2Engine::sgn(long n) {
+ return (n == 0) ? 0 : ((n > 0) ? 1 : -1);
+}
+
+int Hero::mapCross(const V2D &a, const V2D &b) {
+ Hero *o = other();
+ int n = (o->_scene == _scene) ? o->cross(a, b) : 0;
+ if (!_ignoreMap)
+ n += _vm->mapCross(a, b);
+
+ return n;
+}
+
+int Hero::mapCross(const V3D &a, const V3D &b) {
+ return mapCross(V2D(_vm, a._x.round(), a._z.round()), V2D(_vm, b._x.round(), b._z.round()));
+}
+
+int CGE2Engine::mapCross(const V2D &a, const V2D &b) {
+ int cnt = 0;
+ V2D *n0 = nullptr;
+ V2D *p = nullptr;
+ for (int i = 0; i < _map->size(); i++) {
+ V2D *n = _map->getCoord(i);
+ if (p) {
+ if (cross(a, b, *n0, *n))
+ ++cnt;
+
+ if (*n == *p)
+ p = nullptr;
+ } else {
+ p = n;
+ }
+ n0 = n;
+ }
+ return cnt;
+}
+
+void Hero::setScene(int c) {
+ Sprite::setScene(c);
+ resetFun();
+}
+
+void Hero::operator++() {
+ if (_curDim > 0)
+ _ext->_shpList = _dim[--_curDim];
+}
+
+void Hero::operator--() {
+ if (_curDim < kDimMax - 1)
+ _ext->_shpList = _dim[++_curDim];
+}
+
+bool Sprite::works(Sprite *spr) {
+ if (!spr || !spr->_ext)
+ return false;
+
+ bool ok = false;
+
+ Action a = _vm->_heroTab[_vm->_sex]->_ptr->action();
+ CommandHandler::Command *ct = spr->_ext->_actions[a];
+ if (ct) {
+ int i = spr->_actionCtrl[a]._ptr;
+ int n = spr->_actionCtrl[a]._cnt;
+ while (i < n && !ok) {
+ CommandHandler::Command *c = &ct[i++];
+ if (c->_commandType != kCmdUse)
+ break;
+ ok = (c->_ref == _ref);
+ if (c->_val > 255) {
+ if (ok) {
+ int p = spr->labVal(a, c->_val >> 8);
+ if (p >= 0)
+ spr->_actionCtrl[a]._ptr = p;
+ else
+ ok = false;
+ }
+ } else {
+ if (c->_val && c->_val != _vm->_now)
+ ok = false;
+ break;
+ }
+ }
+ }
+
+ return ok;
+}
+
+} // End of namespace CGE2
diff --git a/engines/cge2/hero.h b/engines/cge2/hero.h
new file mode 100644
index 0000000000..3b5329e12c
--- /dev/null
+++ b/engines/cge2/hero.h
@@ -0,0 +1,114 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+/*
+ * This code is based on original Sfinx source code
+ * Copyright (c) 1994-1997 Janus B. Wisniewski and L.K. Avalon
+ */
+
+#ifndef CGE2_HERO_H
+#define CGE2_HERO_H
+
+#include "cge2/cge2.h"
+#include "cge2/vga13h.h"
+#include "cge2/snail.h"
+
+namespace CGE2 {
+
+#define kMaxTry 400
+
+class Hero;
+
+struct HeroTab {
+ Hero *_ptr;
+ Sprite *_face;
+ Sprite *_pocket[kPocketMax + 1];
+ int _downPocketId[kPocketMax + 1];
+ int _pocPtr;
+ V2D *_posTab[kSceneMax];
+ HeroTab(CGE2Engine *vm) {
+ _ptr = nullptr;
+ _face = nullptr;
+ for (int i = 0; i < kPocketMax + 1; i++) {
+ _pocket[i] = nullptr;
+ _downPocketId[i] = -1;
+ }
+ _pocPtr = 0;
+ for (int i = 0; i < kSceneMax; i++)
+ _posTab[i] = nullptr;
+ }
+ ~HeroTab() {
+ for (int i = 0; i < kSceneMax; i++)
+ delete _posTab[i];
+ }
+};
+
+class Hero : public Sprite {
+ int _hig[kDimMax];
+ Sprite *_contact;
+public:
+ BitmapPtr _dim[kDimMax];
+ V3D _trace[kWayMax];
+ enum Dir { kNoDir = -1, kSS, kWW, kNN, kEE } _dir;
+ int _curDim;
+ int _tracePtr;
+ int _reachStart, _reachCycle, _sayStart, _funStart;
+ int _funDel0, _funDel;
+ int _maxDist;
+ bool _ignoreMap;
+ Hero(CGE2Engine *vm);
+ ~Hero();
+ void tick();
+ Sprite *expand();
+ Sprite *contract();
+ Sprite *setContact();
+ int stepSize() { return _ext->_seq[7]._dx; }
+ int distance(V3D pos);
+ int distance(Sprite * spr);
+ void turn(Dir d);
+ void park();
+ int len(V2D v);
+ bool findWay();
+ static int snap(int p, int q, int grid);
+ void walkTo(V3D pos);
+ void walkTo(V2D pos) { walkTo(screenToGround(pos)); }
+ V3D screenToGround(V2D pos);
+ void walkTo(Sprite *spr);
+ void say() { step(_sayStart); }
+ void fun();
+ void resetFun() { _funDel = _funDel0; }
+ void hStep();
+ bool lower(Sprite * spr);
+ int cross(const V2D &a, const V2D &b);
+ int mapCross(const V2D &a, const V2D &b);
+ int mapCross(const V3D &a, const V3D &b);
+ Hero *other() { return _vm->_heroTab[!(_ref & 1)]->_ptr;}
+ Action action() { return (Action)(_ref % 10); }
+ void reach(int mode);
+ void setCurrent();
+ void setScene(int c);
+ void operator++();
+ void operator--();
+};
+
+} // End of namespace CGE2
+
+#endif // CGE2_HERO_H
diff --git a/engines/cge2/inventory.cpp b/engines/cge2/inventory.cpp
new file mode 100644
index 0000000000..e62aa01e99
--- /dev/null
+++ b/engines/cge2/inventory.cpp
@@ -0,0 +1,104 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+/*
+ * This code is based on original Sfinx source code
+ * Copyright (c) 1994-1997 Janus B. Wisniewski and L.K. Avalon
+ */
+
+#include "cge2/cge2.h"
+#include "cge2/hero.h"
+
+namespace CGE2 {
+
+int CGE2Engine::findActivePocket(int ref) {
+ for (int i = 0; i < kPocketMax; i++) {
+ Sprite *spr = _heroTab[_sex]->_pocket[i];
+ if (ref >= 0) {
+ if (spr && (spr->_ref == ref))
+ return i;
+ } else if (!spr)
+ return i;
+ }
+ return -1;
+}
+
+void CGE2Engine::selectPocket(int n) {
+ Sprite **p = _heroTab[_sex]->_pocket;
+ int &pp = _heroTab[_sex]->_pocPtr;
+ if ((n < 0) || (pp == n)) {
+ n = findActivePocket(-1);
+ if (n >= 0)
+ pp = n;
+ } else if (p[n])
+ pp = n;
+}
+
+void CGE2Engine::pocFul() {
+ Hero *h = _heroTab[_sex]->_ptr;
+ h->park();
+ _commandHandler->addCommand(kCmdWait, -1, -1, h);
+ _commandHandler->addCommand(kCmdSound, -1, 2, h);
+ _commandHandler->addCommand(kCmdSay, -1, kPocketFull + _sex, h);
+}
+
+void CGE2Engine::releasePocket(Sprite *spr) {
+ for (int i = 0; i < 2; i++) {
+ for (int j = 0; j < kPocketMax; j++) {
+ Sprite *&poc = _heroTab[i]->_pocket[j];
+ if (poc == spr) {
+ spr->_flags._kept = false;
+ poc = nullptr;
+ return;
+ }
+ }
+ }
+}
+
+int CGE2Engine::freePockets(int sx) {
+ int n = 0;
+ for (int i = 0; i < kPocketMax; i++){
+ if (_heroTab[sx]->_pocket[i] == nullptr)
+ ++n;
+ }
+ return n;
+}
+
+void CGE2Engine::openPocket() {
+ for (int i = 0; i < 2; i++) {
+ for (int j = 0; j < kPocketMax + 1; j++) {
+ int ref = (int)_heroTab[i]->_downPocketId[j];
+ _heroTab[i]->_pocket[j] = (ref == -1) ? nullptr : _vga->_showQ->locate(ref);
+ }
+ }
+}
+
+void CGE2Engine::closePocket() {
+ for (int i = 0; i < 2; i++) {
+ for (int j = 0; j < kPocketMax + 1; j++) {
+ Sprite *spr = _heroTab[i]->_pocket[j];
+ _heroTab[i]->_downPocketId[j] = (spr) ? spr->_ref : -1;
+ }
+ }
+}
+
+} // End of namespace CGE2
diff --git a/engines/cge2/map.cpp b/engines/cge2/map.cpp
new file mode 100644
index 0000000000..275e15f55a
--- /dev/null
+++ b/engines/cge2/map.cpp
@@ -0,0 +1,92 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+/*
+ * This code is based on original Sfinx source code
+ * Copyright (c) 1994-1997 Janus B. Wisniewski and L.K. Avalon
+ */
+
+#include "cge2/map.h"
+
+namespace CGE2 {
+
+Map::Map(CGE2Engine *vm) :_vm(vm) {}
+
+Map::~Map() {
+ _container.clear();
+}
+
+void Map::clear() {
+ _container.clear();
+}
+
+void Map::load(int scene) {
+ clear();
+
+ const char *fname = "%.2d.MAP";
+ Common::String fileName = Common::String::format(fname, scene);
+ if (!_vm->_resman->exist(fileName.c_str()))
+ return;
+
+ EncryptedStream file(_vm, fileName.c_str());
+
+ Common::String line;
+ for (line = file.readLine(); !file.eos(); line = file.readLine()) {
+ if (line.empty())
+ continue;
+
+ char tmpStr[kLineMax + 1];
+ Common::strlcpy(tmpStr, line.c_str(), sizeof(tmpStr));
+
+ char *currPos = tmpStr;
+ int x = nextNum(currPos);
+ while (true) {
+ int y = nextNum(nullptr);
+ _container.push_back(V2D(_vm, convertCoord(x), convertCoord(y)));
+ x = nextNum(nullptr);
+ if (x == -1) // We stop if there are no more data left to process in the current line.
+ break;
+ }
+ }
+}
+
+int Map::nextNum(char *currPos) {
+ currPos = strtok(currPos, " (),");
+ if (currPos == nullptr)
+ return -1;
+ int num = atoi(currPos);
+ return num;
+}
+
+int Map::convertCoord(int coord) {
+ return (coord + (kMapGrid >> 1)) & kMapMask;
+}
+
+int Map::size() {
+ return _container.size();
+}
+
+V2D *Map::getCoord(int idx) {
+ return &_container[idx];
+}
+
+} // End of namespace CGE2
diff --git a/engines/cge2/map.h b/engines/cge2/map.h
new file mode 100644
index 0000000000..206479b929
--- /dev/null
+++ b/engines/cge2/map.h
@@ -0,0 +1,55 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+/*
+ * This code is based on original Sfinx source code
+ * Copyright (c) 1994-1997 Janus B. Wisniewski and L.K. Avalon
+ */
+
+#ifndef CGE2_MAP_H
+#define CGE2_MAP_H
+
+#include "cge2/vga13h.h"
+
+namespace CGE2 {
+
+#define kMapGrid 4
+#define kMapMask (~(kMapGrid - 1))
+
+class Map {
+ CGE2Engine *_vm;
+ Common::Array<V2D> _container;
+
+ int convertCoord(int coord);
+ int nextNum(char *currPos);
+public:
+ Map(CGE2Engine *vm);
+ ~Map();
+ void clear();
+ void load(int scene);
+ int size();
+ V2D *getCoord(int idx);
+};
+
+} // End of namespace CGE2
+
+#endif // CGE2_MAP_H
diff --git a/engines/cge2/module.mk b/engines/cge2/module.mk
new file mode 100644
index 0000000000..4b321d88a8
--- /dev/null
+++ b/engines/cge2/module.mk
@@ -0,0 +1,30 @@
+MODULE := engines/cge2
+
+MODULE_OBJS = \
+ cge2.o \
+ detection.o \
+ fileio.o \
+ vga13h.o \
+ bitmap.o \
+ sound.o \
+ cge2_main.o \
+ text.o \
+ hero.o \
+ snail.o \
+ spare.o \
+ talk.o \
+ events.o \
+ map.o \
+ vmenu.o \
+ saveload.o \
+ toolbar.o \
+ inventory.o \
+ console.o
+
+# This module can be built as a plugin
+ifeq ($(ENABLE_CGE2), DYNAMIC_PLUGIN)
+PLUGIN := 1
+endif
+
+# Include common rules
+include $(srcdir)/rules.mk
diff --git a/engines/cge2/saveload.cpp b/engines/cge2/saveload.cpp
new file mode 100644
index 0000000000..7735c077a6
--- /dev/null
+++ b/engines/cge2/saveload.cpp
@@ -0,0 +1,279 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+/*
+ * This code is based on original Sfinx source code
+ * Copyright (c) 1994-1997 Janus B. Wisniewski and L.K. Avalon
+ */
+
+#include "common/config-manager.h"
+#include "common/savefile.h"
+#include "common/system.h"
+#include "graphics/thumbnail.h"
+#include "graphics/surface.h"
+#include "graphics/palette.h"
+#include "graphics/scaler.h"
+#include "cge2/events.h"
+#include "cge2/snail.h"
+#include "cge2/hero.h"
+#include "cge2/text.h"
+#include "cge2/sound.h"
+#include "cge2/cge2_main.h"
+
+namespace CGE2 {
+
+#define kSavegameCheckSum (1997 + _now + _sex + kWorldHeight)
+#define kBadSVG 99
+
+bool CGE2Engine::canSaveGameStateCurrently() {
+ return (_gamePhase == kPhaseInGame) && _mouse->_active &&
+ _commandHandler->idle() && (_soundStat._wait == nullptr);
+}
+
+Common::Error CGE2Engine::saveGameState(int slot, const Common::String &desc) {
+ storeHeroPos();
+ saveGame(slot, desc);
+ sceneUp(_now);
+ return Common::kNoError;
+}
+
+void CGE2Engine::saveGame(int slotNumber, const Common::String &desc) {
+ // Set up the serializer
+ Common::String slotName = generateSaveName(slotNumber);
+ Common::OutSaveFile *saveFile = g_system->getSavefileManager()->openForSaving(slotName);
+
+ // Write out the ScummVM savegame header
+ SavegameHeader header;
+ header.saveName = desc;
+ header.version = kSavegameVersion;
+ writeSavegameHeader(saveFile, header);
+
+ // Write out the data of the savegame
+ sceneDown();
+ syncGame(nullptr, saveFile);
+
+ // Finish writing out game data
+ saveFile->finalize();
+ delete saveFile;
+}
+
+bool CGE2Engine::canLoadGameStateCurrently() {
+ return (_gamePhase == kPhaseInGame) && _mouse->_active;
+}
+
+Common::Error CGE2Engine::loadGameState(int slot) {
+ _commandHandler->clear();
+ _commandHandlerTurbo->clear();
+ sceneDown();
+ if (!loadGame(slot))
+ return Common::kReadingFailed;
+ sceneUp(_now);
+ initToolbar();
+ return Common::kNoError;
+}
+
+bool CGE2Engine::loadGame(int slotNumber) {
+ Common::MemoryReadStream *readStream;
+
+ // Open up the savegame file
+ Common::String slotName = generateSaveName(slotNumber);
+ Common::InSaveFile *saveFile = g_system->getSavefileManager()->openForLoading(slotName);
+
+ // Read the data into a data buffer
+ int size = saveFile->size();
+ byte *dataBuffer = (byte *)malloc(size);
+ saveFile->read(dataBuffer, size);
+ readStream = new Common::MemoryReadStream(dataBuffer, size, DisposeAfterUse::YES);
+ delete saveFile;
+
+ // Check to see if it's a ScummVM savegame or not
+ char buffer[kSavegameStrSize + 1];
+ readStream->read(buffer, kSavegameStrSize + 1);
+
+ if (strncmp(buffer, kSavegameStr, kSavegameStrSize + 1) != 0) {
+ delete readStream;
+ return false;
+ } else {
+ SavegameHeader saveHeader;
+
+ if (!readSavegameHeader(readStream, saveHeader)) {
+ delete readStream;
+ return false;
+ }
+
+ // Delete the thumbnail
+ saveHeader.thumbnail->free();
+ delete saveHeader.thumbnail;
+ }
+
+ resetGame();
+
+ // Get in the savegame
+ syncGame(readStream, nullptr);
+ delete readStream;
+
+ loadHeroes();
+
+ return true;
+}
+
+void CGE2Engine::resetGame() {
+ _busyPtr = nullptr;
+ busy(false);
+ _spare->clear();
+ _vga->_showQ->clear();
+ loadScript("CGE.INI", true);
+ delete _infoLine;
+ _infoLine = new InfoLine(this, kInfoW);
+}
+
+void CGE2Engine::writeSavegameHeader(Common::OutSaveFile *out, SavegameHeader &header) {
+ // Write out a savegame header
+ out->write(kSavegameStr, kSavegameStrSize + 1);
+
+ out->writeByte(kSavegameVersion);
+
+ // Write savegame name
+ out->write(header.saveName.c_str(), header.saveName.size() + 1);
+
+ // Get the active palette
+ uint8 thumbPalette[256 * 3];
+ g_system->getPaletteManager()->grabPalette(thumbPalette, 0, 256);
+
+ // Stop the heroes from moving and redraw them before taking the picture.
+ for (int i = 0; i < 2; i++)
+ _heroTab[i]->_ptr->park();
+ _vga->show();
+
+ // Create a thumbnail and save it
+ Graphics::Surface *thumb = new Graphics::Surface();
+ Graphics::Surface *s = _vga->_page[0];
+ ::createThumbnail(thumb, (const byte *)s->getPixels(), kScrWidth, kScrHeight, thumbPalette);
+ Graphics::saveThumbnail(*out, *thumb);
+ thumb->free();
+ delete thumb;
+
+ // Write out the save date/time
+ TimeDate td;
+ g_system->getTimeAndDate(td);
+ out->writeSint16LE(td.tm_year + 1900);
+ out->writeSint16LE(td.tm_mon + 1);
+ out->writeSint16LE(td.tm_mday);
+ out->writeSint16LE(td.tm_hour);
+ out->writeSint16LE(td.tm_min);
+}
+
+bool CGE2Engine::readSavegameHeader(Common::InSaveFile *in, SavegameHeader &header) {
+ header.thumbnail = nullptr;
+
+ // Get the savegame version
+ header.version = in->readByte();
+ if (header.version > kSavegameVersion)
+ return false;
+
+ // Read in the string
+ header.saveName.clear();
+ char ch;
+ while ((ch = (char)in->readByte()) != '\0')
+ header.saveName += ch;
+
+ // Get the thumbnail
+ header.thumbnail = Graphics::loadThumbnail(*in);
+ if (!header.thumbnail)
+ return false;
+
+ // Read in save date/time
+ header.saveYear = in->readSint16LE();
+ header.saveMonth = in->readSint16LE();
+ header.saveDay = in->readSint16LE();
+ header.saveHour = in->readSint16LE();
+ header.saveMinutes = in->readSint16LE();
+
+ return true;
+}
+
+void CGE2Engine::syncGame(Common::SeekableReadStream *readStream, Common::WriteStream *writeStream) {
+ Common::Serializer s(readStream, writeStream);
+
+ // Synchronise header data
+ syncHeader(s);
+
+ // Synchronise _spare
+ _spare->sync(s);
+
+ if (s.isSaving()) {
+ // Save the references of the items in the heroes pockets:
+ for (int i = 0; i < 2; i++) {
+ for (int j = 0; j < kPocketMax; j++) {
+ int ref = _heroTab[i]->_downPocketId[j];
+ s.syncAsSint16LE(ref);
+ }
+ }
+ } else {
+ // Load items to the pockets
+ for (int i = 0; i < 2; i++) {
+ for (int j = 0; j < kPocketMax; j++) {
+ int ref = 0;
+ s.syncAsSint16LE(ref);
+ _heroTab[i]->_downPocketId[j] = ref;
+ }
+ }
+ }
+
+ // Heroes' _posTabs
+ for (int i = 0; i < 2; i++) {
+ for (int j = 0; j < kSceneMax; j++) {
+ s.syncAsSint16LE(_heroTab[i]->_posTab[j]->x);
+ s.syncAsSint16LE(_heroTab[i]->_posTab[j]->y);
+ }
+ }
+}
+
+void CGE2Engine::syncHeader(Common::Serializer &s) {
+ s.syncAsUint16LE(_now);
+ s.syncAsUint16LE(_sex);
+ s.syncAsUint16LE(_vga->_rot._len);
+ s.syncAsUint16LE(_waitSeq);
+ s.syncAsUint16LE(_waitRef);
+
+ if (s.isSaving()) {
+ // Write checksum
+ int checksum = kSavegameCheckSum;
+ s.syncAsUint16LE(checksum);
+ } else {
+ // Read checksum and validate it
+ uint16 checksum = 0;
+ s.syncAsUint16LE(checksum);
+ if (checksum != kSavegameCheckSum)
+ error("%s", _text->getText(kBadSVG));
+ }
+}
+
+/**
+* Support method that generates a savegame name
+* @param slot Slot number
+*/
+Common::String CGE2Engine::generateSaveName(int slot) {
+ return Common::String::format("%s.%03d", _targetName.c_str(), slot);
+}
+
+} // End of namespace CGE2
diff --git a/engines/cge2/snail.cpp b/engines/cge2/snail.cpp
new file mode 100644
index 0000000000..7580ef4425
--- /dev/null
+++ b/engines/cge2/snail.cpp
@@ -0,0 +1,865 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+/*
+ * This code is based on original Sfinx source code
+ * Copyright (c) 1994-1997 Janus B. Wisniewski and L.K. Avalon
+ */
+
+#include "cge2/snail.h"
+#include "cge2/fileio.h"
+#include "cge2/hero.h"
+#include "cge2/text.h"
+#include "cge2/sound.h"
+#include "cge2/events.h"
+
+namespace CGE2 {
+
+const char *CommandHandler::_commandText[] = {
+ "NOP", "USE", "PAUSE", "INF", "CAVE", "SETX", "SETY", "SETZ", "ADD",
+ "FLASH", "CYCLE", "CLEAR", "MOUSE", "MAP", "MIDI", ".DUMMY.", "WAIT",
+ "HIDE", "ROOM", "SAY", "SOUND", "KILL", "RSEQ", "SEQ", "SEND", "SWAP",
+ "KEEP", "GIVE", "GETPOS", "GOTO", "PORT", "NEXT", "NNEXT", "MTNEXT",
+ "FTNEXT", "RNNEXT", "RMTNEXT", "RFTNEXT", "RMNEAR", "RMMTAKE", "RMFTAKE",
+ "SETREF", "WALKTO", "REACH", "COVER", "UNCOVER", "EXEC", "GHOST",
+ nullptr };
+
+CommandHandler::CommandHandler(CGE2Engine *vm, bool turbo)
+ : _turbo(turbo), _textDelay(false), _timerExpiry(0), _talkEnable(true),
+ _head(0), _tail(0), _commandList((Command *)malloc(sizeof(Command)* 256)),
+ _vm(vm) {
+}
+
+CommandHandler::~CommandHandler() {
+ free(_commandList);
+}
+
+void CommandHandler::runCommand() {
+ if (!_turbo && _vm->_soundStat._wait) {
+ if (*(_vm->_soundStat._wait))
+ return;
+
+ ++_vm->_soundStat._ref[0];
+ if (_vm->_fx->exist(_vm->_soundStat._ref[1], _vm->_soundStat._ref[0])) {
+ int16 oldRepeat = _vm->_sound->getRepeat();
+ _vm->_sound->setRepeat(1);
+ _vm->_sound->play(Audio::Mixer::kSpeechSoundType, _vm->_fx->load(_vm->_soundStat._ref[1], _vm->_soundStat._ref[0]), _vm->_sound->_smpinf._span);
+ _vm->_sound->setRepeat(oldRepeat);
+ return;
+ }
+ _vm->_soundStat._wait = nullptr;
+ }
+
+ uint8 tmpHead = _head;
+ while (_tail != tmpHead) {
+ Command tailCmd = _commandList[_tail];
+
+ if (!_turbo) { // only for the slower one
+ if (_vm->_waitRef)
+ break;
+
+ if (_timerExpiry) {
+ // Delay in progress
+ if (_timerExpiry > g_system->getMillis())
+ // Delay not yet ended
+ break;
+
+ // Delay is finished
+ _timerExpiry = 0;
+ } else if (_textDelay) {
+ if (_vm->_talk) {
+ _vm->snKill((Sprite *)_vm->_talk);
+ _vm->_talk = nullptr;
+ }
+ _textDelay = false;
+ }
+
+ if (_vm->_talk && tailCmd._commandType != kCmdPause)
+ break;
+ }
+ ++_tail;
+ _vm->_taken = false;
+ Sprite *spr = nullptr;
+ if (tailCmd._commandType > kCmdSpr)
+ spr = (tailCmd._ref < 0) ? ((Sprite *)tailCmd._spritePtr) : _vm->locate(tailCmd._ref);
+
+ Common::String sprStr;
+ if (spr && *spr->_file && (tailCmd._commandType != kCmdGhost))
+ // In case of kCmdGhost _spritePtr stores a pointer to a Bitmap, not to a Sprite...
+ sprStr = Common::String(spr->_file);
+ else
+ sprStr = "None";
+
+ if (sprStr.empty())
+ sprStr = "None";
+ debugC(1, kCGE2DebugOpcode, "Command: %s; Ref: %d; Val: %d; Sprite: %s;", getComStr(tailCmd._commandType), tailCmd._ref, tailCmd._val, sprStr.c_str());
+
+ switch (tailCmd._commandType) {
+ case kCmdUse:
+ break;
+ case kCmdPause:
+ _timerExpiry = g_system->getMillis() + tailCmd._val * kCommandFrameDelay;
+ if (_vm->_talk)
+ _textDelay = true;
+ break;
+ case kCmdWait:
+ if (spr && spr->active() && (spr->_scene == _vm->_now || spr->_scene == 0)) {
+ _vm->_waitSeq = tailCmd._val;
+ _vm->_waitRef = spr->_ref;
+ }
+ break;
+ case kCmdHide:
+ _vm->snHide(spr, tailCmd._val);
+ break;
+ case kCmdSay:
+ _vm->snSay(spr, tailCmd._val);
+ break;
+ case kCmdInf:
+ if (_talkEnable)
+ _vm->inf(((tailCmd._val) >= 0) ? _vm->_text->getText(tailCmd._val) : (const char *)tailCmd._spritePtr);
+ break;
+ case kCmdCave:
+ _vm->switchScene(tailCmd._val);
+ break;
+ case kCmdMidi:
+ _vm->snMidi(tailCmd._val);
+ break;
+ case kCmdKill:
+ _vm->snKill(spr);
+ break;
+ case kCmdSeq:
+ _vm->snSeq(spr, tailCmd._val);
+ break;
+ case kCmdRSeq:
+ _vm->snRSeq(spr, tailCmd._val);
+ break;
+ case kCmdSend:
+ _vm->snSend(spr, tailCmd._val);
+ break;
+ case kCmdSwap:
+ _vm->snSwap(spr, tailCmd._val);
+ break;
+ case kCmdCover:
+ _vm->snCover(spr, tailCmd._val);
+ break;
+ case kCmdUncover:
+ _vm->snUncover(spr, (tailCmd._val >= 0) ? _vm->locate(tailCmd._val) : ((Sprite *)tailCmd._spritePtr));
+ break;
+ case kCmdKeep:
+ _vm->snKeep(spr, tailCmd._val);
+ break;
+ case kCmdGive:
+ _vm->snGive(spr, tailCmd._val);
+ break;
+ case kCmdSetX:
+ _vm->_point[tailCmd._val]->_x = tailCmd._ref;
+ break;
+ case kCmdSetY:
+ _vm->_point[tailCmd._val]->_y = tailCmd._ref;
+ break;
+ case kCmdSetZ:
+ _vm->_point[tailCmd._val]->_z = tailCmd._ref;
+ break;
+ case kCmdAdd:
+ *(_vm->_point[tailCmd._ref]) = *(_vm->_point[tailCmd._ref]) + *(_vm->_point[tailCmd._val]);
+ break;
+ case kCmdGetPos:
+ if (spr)
+ *(_vm->_point[tailCmd._val]) = spr->_pos3D;
+ break;
+ case kCmdGoto:
+ _vm->snGoto(spr, tailCmd._val);
+ break;
+ case kCmdPort:
+ _vm->snPort(spr, tailCmd._val);
+ break;
+ case kCmdNext:
+ break;
+ case kCmdMouse:
+ _vm->snMouse(tailCmd._val != 0);
+ break;
+ case kCmdNNext:
+ _vm->snNNext(spr, kNear, tailCmd._val);
+ break;
+ case kCmdMTNext:
+ _vm->snNNext(spr, kMTake, tailCmd._val);
+ break;
+ case kCmdFTNext:
+ _vm->snNNext(spr, kFTake, tailCmd._val);
+ break;
+ case kCmdRNNext:
+ _vm->snRNNext(spr, tailCmd._val);
+ break;
+ case kCmdRMTNext:
+ _vm->snRMTNext(spr, tailCmd._val);
+ break;
+ case kCmdRFTNext:
+ _vm->snRFTNext(spr, tailCmd._val);
+ break;
+ case kCmdRMNear:
+ _vm->snRmNear(spr);
+ break;
+ case kCmdRMMTake:
+ _vm->snRmMTake(spr);
+ break;
+ case kCmdRMFTake:
+ _vm->snRmFTake(spr);
+ break;
+ case kCmdSetRef:
+ _vm->snSetRef(spr, tailCmd._val);
+ break;
+ case kCmdFlash:
+ _vm->snFlash(tailCmd._val != 0);
+ break;
+ case kCmdCycle:
+ _vm->snCycle(tailCmd._val);
+ break;
+ case kCmdWalk:
+ _vm->snWalk(spr, tailCmd._val);
+ break;
+ case kCmdReach:
+ _vm->snReach(spr, tailCmd._val);
+ break;
+ case kCmdSound:
+ _vm->snSound(spr, tailCmd._val);
+ _vm->_sound->setRepeat(1);
+ break;
+ case kCmdMap:
+ _vm->_heroTab[tailCmd._ref & 1]->_ptr->_ignoreMap = tailCmd._val == 0;
+ break;
+ case kCmdRoom:
+ _vm->snRoom(spr, tailCmd._val);
+ break;
+ case kCmdExec:
+ switch (tailCmd._cbType) {
+ case kQGame:
+ _vm->qGame();
+ break;
+ case kXScene:
+ _vm->xScene();
+ break;
+ default:
+ error("Unknown Callback Type in SNEXEC");
+ break;
+ }
+ break;
+ case kCmdGhost:
+ _vm->snGhost((Bitmap *)tailCmd._spritePtr);
+ break;
+ case kCmdNop: // Do nothing.
+ break;
+ default:
+ warning("Unhandled command");
+ break;
+ }
+
+ if (_vm->_taken && spr)
+ _vm->_spare->dispose(spr);
+
+ if (!_turbo)
+ break;
+ }
+}
+
+void CGE2Engine::snKill(Sprite *spr) {
+ if (spr) {
+ if (spr->_flags._kept)
+ releasePocket(spr);
+ Sprite *nx = spr->_next;
+ hide1(spr);
+ _vga->_showQ->remove(spr);
+ _eventManager->clearEvent(spr);
+ if (spr->_flags._kill) {
+ _spare->take(spr->_ref);
+ delete spr;
+ } else {
+ spr->setScene(-1);
+ _spare->dispose(spr);
+ }
+ if (nx && nx->_flags._slav)
+ snKill(nx);
+ }
+}
+
+void CGE2Engine::snHide(Sprite *spr, int val) {
+ if (spr) {
+ spr->_flags._hide = (val >= 0) ? (val != 0) : (!spr->_flags._hide);
+ if (spr->_flags._shad)
+ spr->_prev->_flags._hide = spr->_flags._hide;
+ }
+}
+
+void CGE2Engine::snMidi(int val) {
+ if (val < 0)
+ _midiPlayer->killMidi();
+ else if (_music)
+ _midiPlayer->loadMidi(val);
+}
+
+void CGE2Engine::snSeq(Sprite *spr, int val) {
+ if (spr) {
+ if (isHero(spr) && (val == 0))
+ ((Hero*)spr)->park();
+ else
+ spr->step(val);
+ }
+}
+
+void CGE2Engine::snRSeq(Sprite *spr, int val) {
+ if (spr)
+ snSeq(spr, spr->_seqPtr + val);
+}
+
+void CGE2Engine::snSend(Sprite *spr, int val) {
+ if (!spr)
+ return;
+
+ // Sending", spr->_file
+ // from scene", spr->_scene
+ // to scene", val
+ bool was1 = (_vga->_showQ->locate(spr->_ref) != nullptr);
+ bool val1 = (val == 0 || val == _now);
+ spr->_scene = val;
+ releasePocket(spr);
+ if (val1 != was1) {
+ if (was1) {
+ // deactivating
+ hide1(spr);
+ spr->_flags._slav = false;
+ if ((spr == _heroTab[_sex]->_ptr) && (_heroTab[!_sex]->_ptr->_scene == _now))
+ switchHero(!_sex);
+ _spare->dispose(spr);
+ } else {
+ // activating
+ if (byte(spr->_ref) == 0)
+ _bitmapPalette = _vga->_sysPal;
+ _vga->_showQ->insert(spr);
+ if (isHero(spr)) {
+ V2D p = *_heroTab[spr->_ref & 1]->_posTab[val];
+ spr->gotoxyz(V3D(p.x, 0, p.y));
+ ((Hero*)spr)->setCurrent();
+ }
+ _taken = false;
+ _bitmapPalette = nullptr;
+ }
+ }
+}
+
+void CGE2Engine::snSwap(Sprite *spr, int val) {
+ bool tak = _taken;
+ Sprite *xspr = locate(val);
+ if (spr && xspr) {
+ bool was1 = (_vga->_showQ->locate(spr->_ref) != nullptr);
+ bool xwas1 = (_vga->_showQ->locate(val) != nullptr);
+
+ int tmp = spr->_scene;
+ spr->setScene(xspr->_scene);
+ xspr->setScene(tmp);
+
+ SWAP(spr->_pos2D, xspr->_pos2D);
+ SWAP(spr->_pos3D, xspr->_pos3D);
+ if (spr->_flags._kept)
+ swapInPocket(spr, xspr);
+ if (xwas1 != was1) {
+ if (was1) {
+ hide1(spr);
+ _spare->dispose(spr);
+ } else
+ expandSprite(spr);
+ if (xwas1) {
+ hide1(xspr);
+ _spare->dispose(xspr);
+ } else {
+ expandSprite(xspr);
+ _taken = false;
+ }
+ }
+ }
+ if (_taken)
+ _spare->dispose(xspr);
+ _taken = tak;
+}
+
+void CGE2Engine::snCover(Sprite *spr, int val) {
+ bool tak = _taken;
+ Sprite *xspr = locate(val);
+ if (spr && xspr) {
+ spr->_flags._hide = true;
+ xspr->setScene(spr->_scene);
+ xspr->gotoxyz(spr->_pos3D);
+ expandSprite(xspr);
+ if ((xspr->_flags._shad = spr->_flags._shad) == true) {
+ _vga->_showQ->insert(_vga->_showQ->remove(spr->_prev), xspr);
+ spr->_flags._shad = false;
+ }
+ feedSnail(xspr, kNear, _heroTab[_sex]->_ptr);
+ _taken = false;
+ }
+ if (_taken)
+ _spare->dispose(xspr);
+ _taken = tak;
+}
+
+void CGE2Engine::snUncover(Sprite *spr, Sprite *spr2) {
+ if (spr && spr2) {
+ spr->_flags._hide = false;
+ spr->setScene(spr2->_scene);
+ if ((spr->_flags._shad = spr2->_flags._shad) == true) {
+ _vga->_showQ->insert(_vga->_showQ->remove(spr2->_prev), spr);
+ spr2->_flags._shad = false;
+ }
+ spr->gotoxyz(spr2->_pos3D);
+ snSend(spr2, -1);
+ if (spr->_time == 0)
+ ++spr->_time;
+ }
+}
+
+void CGE2Engine::snKeep(Sprite *spr, int stp) {
+ int sex = _sex;
+ if (stp > 127) {
+ _sex = stp & 1; // for another hero
+ stp = -1;
+ }
+ HeroTab *ht = _heroTab[_sex];
+ selectPocket(-1);
+ int pp = ht->_pocPtr;
+
+ if (spr && !spr->_flags._kept && ht->_pocket[pp] == nullptr) {
+ V3D pos(14, -10, -1);
+ int16 oldRepeat = _sound->getRepeat();
+ _sound->setRepeat(1);
+ snSound(ht->_ptr, 3);
+ _sound->setRepeat(oldRepeat);
+ if (_taken) {
+ _vga->_showQ->insert(spr);
+ _taken = false;
+ }
+ ht->_pocket[pp] = spr;
+ spr->setScene(0);
+ spr->_flags._kept = true;
+ if (!_sex)
+ pos._x += kScrWidth - 58;
+ if (pp & 1)
+ pos._x += 29;
+ if (pp >> 1)
+ pos._y -= 20;
+ pos._y -= (spr->_siz.y / 2);
+ spr->gotoxyz(pos);
+ if (stp >= 0)
+ spr->step(stp);
+ }
+ _sex = sex;
+ selectPocket(-1);
+}
+
+void CGE2Engine::snGive(Sprite *spr, int val) {
+ if (spr) {
+ int p = findActivePocket(spr->_ref);
+ if (p >= 0) {
+ releasePocket(spr);
+ spr->setScene(_now);
+ if (val >= 0)
+ spr->step(val);
+ }
+ }
+ selectPocket(-1);
+}
+
+void CGE2Engine::snGoto(Sprite *spr, int val) {
+ if (spr) {
+ V3D eye = *_eye;
+ if (spr->_scene > 0)
+ setEye(*_eyeTab[spr->_scene]);
+ spr->gotoxyz(*_point[val]);
+ setEye(eye);
+ }
+}
+
+void CGE2Engine::snPort(Sprite *spr, int port) {
+ if (spr)
+ spr->_flags._port = (port < 0) ? !spr->_flags._port : (port != 0);
+}
+
+void CGE2Engine::snMouse(bool on) {
+ if (on)
+ _mouse->on();
+ else
+ _mouse->off();
+}
+
+void CGE2Engine::snNNext(Sprite *spr, Action act, int val) {
+ if (spr) {
+ if (val > 255)
+ val = spr->labVal(act, val >> 8);
+ spr->_actionCtrl[act]._ptr = val;
+ }
+}
+
+void CGE2Engine::snRNNext(Sprite *spr, int val) {
+ if (spr)
+ spr->_actionCtrl[kNear]._ptr += val;
+}
+
+void CGE2Engine::snRMTNext(Sprite *spr, int val) {
+ if (spr)
+ spr->_actionCtrl[kMTake]._ptr += val;
+}
+
+void CGE2Engine::snRFTNext(Sprite * spr, int val) {
+ if (spr)
+ spr->_actionCtrl[kFTake]._ptr += val;
+}
+
+void CGE2Engine::snRmNear(Sprite *spr) {
+ if (spr)
+ spr->_actionCtrl[kNear]._cnt = 0;
+}
+
+void CGE2Engine::snRmMTake(Sprite *spr) {
+ if (spr)
+ spr->_actionCtrl[kMTake]._cnt = 0;
+}
+
+void CGE2Engine::snRmFTake(Sprite *spr) {
+ if (spr)
+ spr->_actionCtrl[kFTake]._cnt = 0;
+}
+
+void CGE2Engine::snSetRef(Sprite *spr, int val) {
+ if (spr)
+ spr->_ref = val;
+}
+
+void CGE2Engine::snFlash(bool on) {
+ if (on) {
+ Dac *pal = (Dac *)malloc(sizeof(Dac) * kPalCount);
+ if (pal) {
+ memcpy(pal, _vga->_sysPal, kPalSize);
+ for (int i = 0; i < kPalCount; i++) {
+ register int c;
+ c = pal[i]._r << 1;
+ pal[i]._r = (c < 64) ? c : 63;
+ c = pal[i]._g << 1;
+ pal[i]._g = (c < 64) ? c : 63;
+ c = pal[i]._b << 1;
+ pal[i]._b = (c < 64) ? c : 63;
+ }
+ _vga->setColors(pal, 64);
+ }
+
+ free(pal);
+ } else
+ _vga->setColors(_vga->_sysPal, 64);
+ _dark = false;
+}
+
+void CGE2Engine::snCycle(int cnt) {
+ _vga->_rot._len = cnt;
+}
+
+void CGE2Engine::snWalk(Sprite *spr, int val) {
+ if (isHero(spr)) {
+ if (val < kMaxPoint)
+ ((Hero *)spr)->walkTo(*_point[val]);
+ else {
+ Sprite *s = _vga->_showQ->locate(val);
+ if (s)
+ ((Hero *)spr)->walkTo(s);
+ }
+ ((Hero *)spr)->_time = 1;
+ }
+}
+
+void CGE2Engine::snReach(Sprite *spr, int val) {
+ if (isHero(spr))
+ ((Hero *)spr)->reach(val);
+}
+
+void CGE2Engine::snSound(Sprite *spr, int wav, Audio::Mixer::SoundType soundType) {
+ if (wav == -1)
+ _sound->stop();
+ else {
+ if (_sound->_smpinf._counter && wav < 20)
+ return;
+ if (_soundStat._wait && ((wav & 255) > 80))
+ return;
+
+ _soundStat._ref[1] = wav;
+ _soundStat._ref[0] = !_fx->exist(_soundStat._ref[1]);
+ _sound->play(soundType, _fx->load(_soundStat._ref[1], _soundStat._ref[0]),
+ (spr) ? (spr->_pos2D.x / (kScrWidth / 16)) : 8);
+ }
+}
+
+void CGE2Engine::snRoom(Sprite *spr, bool on) {
+ if (!isHero(spr))
+ return;
+
+ int sex = spr->_ref & 1;
+ Sprite **p = _heroTab[sex]->_pocket;
+ if (on) {
+ if (freePockets(sex) == 0 && p[kPocketMax] == nullptr) {
+ SWAP(p[kPocketMax], p[kPocketMax - 1]);
+ snHide(p[kPocketMax], 1);
+ }
+ } else if (p[kPocketMax]) {
+ for (int i = 0; i < kPocketMax; i++) {
+ if (p[i] == nullptr) {
+ snHide(p[kPocketMax], 0);
+ SWAP(p[kPocketMax], p[i]);
+ break;
+ }
+ }
+ }
+}
+
+void CGE2Engine::snGhost(Bitmap *bmp) {
+ V2D p(this, bmp->_map & 0xFFFF, bmp->_map >> 16);
+ bmp->hide(p);
+ bmp->release();
+ delete[] bmp->_b;
+ bmp->_b = nullptr;
+ delete bmp;
+ bmp = nullptr;
+}
+
+void CGE2Engine::snSay(Sprite *spr, int val) {
+ if (spr && spr->active() && _commandHandler->_talkEnable) {
+ //-- mouth animation
+ if (isHero(spr) && spr->seqTest(-1))
+ ((Hero *)spr)->say();
+ if (_sayCap)
+ _text->say(_text->getText(val), spr);
+ if (_sayVox) {
+ int i = val;
+ if (i < 256)
+ i -= 100;
+ int16 oldRepeat = _sound->getRepeat();
+ _sound->setRepeat(1);
+ snSound(spr, i, Audio::Mixer::kSpeechSoundType);
+ _sound->setRepeat(oldRepeat);
+ _soundStat._wait = &_sound->_smpinf._counter;
+ }
+ }
+}
+
+void CGE2Engine::hide1(Sprite *spr) {
+ _commandHandlerTurbo->addCommand(kCmdGhost, -1, 0, spr->ghost());
+}
+
+void CGE2Engine::swapInPocket(Sprite *spr, Sprite *xspr) {
+ for (int i = 0; i < 2; i++) {
+ for (int j = 0; j < kPocketMax; j++) {
+ Sprite *&poc = _heroTab[i]->_pocket[j];
+ if (poc == spr) {
+ spr->_flags._kept = false;
+ poc = xspr;
+ xspr->_flags._kept = true;
+ xspr->_flags._port = false;
+ return;
+ }
+ }
+ }
+}
+
+Sprite *CGE2Engine::expandSprite(Sprite *spr) {
+ if (spr)
+ _vga->_showQ->insert(spr);
+ return spr;
+}
+
+void CGE2Engine::qGame() {
+ // Write out the user's progress
+ saveGame(0, Common::String("Automatic Savegame"));
+
+ busy(false);
+ _vga->sunset();
+ _endGame = true;
+}
+
+void CGE2Engine::xScene() {
+ sceneDown();
+ sceneUp(_req);
+}
+
+void CommandHandler::addCommand(CommandType com, int ref, int val, void *ptr) {
+ if (ref == -2)
+ ref = 142 - _vm->_sex;
+ Command *headCmd = &_commandList[_head++];
+ headCmd->_commandType = com;
+ headCmd->_ref = ref;
+ headCmd->_val = val;
+ headCmd->_spritePtr = ptr;
+ headCmd->_cbType = kNullCB;
+ if (headCmd->_commandType == kCmdClear) {
+ clear();
+ }
+}
+
+void CommandHandler::addCallback(CommandType com, int ref, int val, CallbackType cbType) {
+ Command *headCmd = &_commandList[_head++];
+ headCmd->_commandType = com;
+ headCmd->_ref = ref;
+ headCmd->_val = val;
+ headCmd->_spritePtr = nullptr;
+ headCmd->_cbType = cbType;
+ if (headCmd->_commandType == kCmdClear) {
+ _tail = _head;
+ _vm->killText();
+ _timerExpiry = 0;
+ }
+}
+
+void CommandHandler::insertCommand(CommandType com, int ref, int val, void *ptr) {
+ if (ref == -2)
+ ref = 142 - _vm->_sex;
+ --_tail;
+ Command *tailCmd = &_commandList[_tail];
+ tailCmd->_commandType = com;
+ tailCmd->_ref = ref;
+ tailCmd->_val = val;
+ tailCmd->_spritePtr = ptr;
+ tailCmd->_cbType = kNullCB;
+ if (com == kCmdClear) {
+ _tail = _head;
+ _vm->killText();
+ _timerExpiry = 0;
+ }
+}
+
+bool CommandHandler::idle() {
+ return (!_vm->_waitRef && _head == _tail);
+}
+
+void CommandHandler::clear() {
+ _tail = _head;
+ _vm->killText();
+ _timerExpiry = 0;
+}
+
+int CommandHandler::getComId(const char *com) {
+ int i = _vm->takeEnum(_commandText, com);
+ return (i < 0) ? i : i + kCmdCom0 + 1;
+}
+
+const char *CommandHandler::getComStr(CommandType cmdType) {
+ return _commandText[cmdType - kCmdNop];
+}
+
+void CGE2Engine::feedSnail(Sprite *spr, Action snq, Hero *hero) {
+ if (!spr || !spr->active())
+ return;
+
+ int cnt = spr->_actionCtrl[snq]._cnt;
+ if (cnt) {
+ byte ptr = spr->_actionCtrl[snq]._ptr;
+ CommandHandler::Command *comtab = spr->snList(snq);
+ CommandHandler::Command *c = &comtab[ptr];
+ CommandHandler::Command *q = &comtab[cnt];
+
+ if (hero != nullptr) {
+ int pocFre = freePockets(hero->_ref & 1);
+ int pocReq = 0;
+ CommandHandler::Command *p = c;
+ for (; p < q && p->_commandType != kCmdNext; p++) { // scan commands
+ // drop from pocket?
+ if ((p->_commandType == kCmdSend && p->_val != _now)
+ || p->_commandType == kCmdGive) {
+ int ref = p->_ref;
+ if (ref < 0)
+ ref = spr->_ref;
+ if (findActivePocket(ref) >= 0)
+ --pocReq;
+ }
+ // make/dispose additional room?
+ if (p->_commandType == kCmdRoom) {
+ if (p->_val == 0)
+ ++pocReq;
+ else
+ --pocReq;
+ }
+ // put into pocket?
+ if (p->_commandType == kCmdKeep)
+ ++pocReq;
+ // overloaded?
+ if (pocReq > pocFre) {
+ pocFul();
+ return;
+ }
+ }
+ }
+
+ while (c < q) {
+ if ((c->_val == -1) && (c->_commandType == kCmdWalk || c->_commandType == kCmdReach))
+ c->_val = spr->_ref;
+
+ if (c->_commandType == kCmdNext) {
+ Sprite *s;
+
+ switch (c->_ref) {
+ case -2:
+ s = hero;
+ break;
+ case -1:
+ s = spr;
+ break;
+ default:
+ s = _vga->_showQ->locate(c->_ref);
+ break;
+ }
+
+ if (s && s->_actionCtrl[snq]._cnt) {
+ int v;
+ switch (c->_val) {
+ case -1:
+ v = int(c - comtab + 1);
+ break;
+ case -2:
+ v = int(c - comtab);
+ break;
+ case -3:
+ v = -1;
+ break;
+ default:
+ v = c->_val;
+ if ((v > 255) && s)
+ v = s->labVal(snq, v >> 8);
+ break;
+ }
+ if (v >= 0)
+ s->_actionCtrl[snq]._ptr = v;
+ }
+
+ if (s == spr)
+ break;
+ }
+
+ _commandHandler->addCommand(c->_commandType, c->_ref, c->_val, spr);
+
+ ++c;
+ }
+ }
+
+}
+
+} // End of namespace CGE2.
diff --git a/engines/cge2/snail.h b/engines/cge2/snail.h
new file mode 100644
index 0000000000..7e618daac8
--- /dev/null
+++ b/engines/cge2/snail.h
@@ -0,0 +1,129 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+/*
+ * This code is based on original Sfinx source code
+ * Copyright (c) 1994-1997 Janus B. Wisniewski and L.K. Avalon
+ */
+
+#ifndef CGE2_SNAIL_H
+#define CGE2_SNAIL_H
+
+#include "cge2/cge2.h"
+
+namespace CGE2 {
+
+#define kCommandFrameRate 80
+#define kCommandFrameDelay (1000 / kCommandFrameRate)
+#define kNoByte -1 // Recheck this! We have no proof for it's original value.
+
+
+enum CommandType {
+ kCmdCom0 = 128,
+ kCmdNop, // NOP :: do nothing
+ kCmdUse, // USE <spr> <cav>|<lab> :: hint for using
+ kCmdPause, // PAUSE -1 <dly> :: delay <dly>/72 seconds
+ kCmdInf, // INF -1 <ref> :: show text referrenced by <ref>
+ kCmdCave, // CAVE -1 <cav> :: go to board <cav>
+ kCmdSetX, // SETX <x> <idx> :: set sprite shift in x axis
+ kCmdSetY, // SETX <y> <idx> :: set sprite shift in y axis
+ kCmdSetZ, // SETX <z> <idx> :: set sprite shift in z axis
+ kCmdAdd, // ADD <idx1> <idx2> :: sum vectors
+ kCmdFlash, // FLASH -1 0|1 :: lighten whole image (on/off)
+ kCmdCycle, // CYCLE <cnt> :: rotate <cnt> colors from 1
+ kCmdClear, // CLEAR -1 0 :: clear kCmdAIL queue
+ kCmdMouse, // MOUSE -1 0|1 :: enable mouse (on/off)
+ kCmdMap, // MAP 0|1 0 :: temporarily turn off map for hero
+ kCmdMidi, // MIDI -1 <midi> :: play MIDI referenced by <midi> (-1 = off)
+
+ kCmdSpr,
+
+ kCmdWait, // WAIT <spr> <seq>|-1 :: wait for SEQ <seq> (-1 = freeze)
+ kCmdHide, // HIDE <spr> 0|1 :: visibility of sprite
+ kCmdRoom, // ROOM <hero> 0|1 :: additional room in pocket (no/yes)
+ kCmdSay, // SAY <spr> <ref> :: say text referenced by <ref>
+ kCmdSound, // SOUND <spr> <ref> :: play sound effect referenced by <ref>
+ kCmdKill, // KILL <spr> 0 :: remove sprite
+ kCmdRSeq, // RSEQ <spr> <nr> :: relative jump SEQ <nr> lines
+ kCmdSeq, // SEQ <spr> <seq> :: jump to certain SEQ
+ kCmdSend, // SEND <spr> <cav> :: move sprite to board <cav>
+ kCmdSwap, // SWAP <spr1> spr2> :: sprite exchange
+ kCmdKeep, // KEEP <spr> <seq> :: take sprite into pocket and jump to <seq>
+ kCmdGive, // GIVE <spr> <seq> :: remove sprite from pocket and jump to <seq>
+ kCmdGetPos, // GETPOS <spr> <idx> :: take sprite's position
+ kCmdGoto, // GOTO <spr> <idx> :: move sprite to position
+ kCmdPort, // PORT <spr> 0|1 :: clear/set "takeability" of sprite
+ kCmdNext, // NEXT <spr> <nr> :: jump to <nr> - NEAR or TAKE
+ kCmdNNext, // NNEXT <spr> <nr> :: jump to <nr> - NEAR
+ kCmdMTNext, // MTNEXT <spr> <nr> :: jump to <nr> - TAKE
+ kCmdFTNext, // FTNEXT <spr> <nr> :: jump to <nr> - TAKE
+ kCmdRNNext, // RNNEXT <spr> <nr> :: relative jump to <nr> - NEAR
+ kCmdRMTNext, // RMTNEXT <spr> <nr> :: relative jump to <nr> - TAKE
+ kCmdRFTNext, // RFTNEXT <spr> <nr> :: relative jump to <nr> - TAKE
+ kCmdRMNear, // RMNEAR <spr> 0 :: remove NEAR list
+ kCmdRMMTake, // RMMTAKE <spr> 0 :: remove TAKE list
+ kCmdRMFTake, // RMFTAKE <spr> 0 :: remove TAKE list
+ kCmdSetRef, // SETREF <spr> <ref> :: change reference of sprite <spr> to <ref>
+ kCmdWalk, // WALKTO <hero> <ref>|<point> :: go close to the sprite or point
+ kCmdReach, // REACH <hero> <ref>|<m> :: reach the sprite or point with <m> method
+ kCmdCover, // COVER <sp1> <sp2> :: cover sprite <sp1> with sprite <sp2>
+ kCmdUncover, // UNCOVER <sp1> <sp2> :: restore the state before COVER
+
+ kCmdExec,
+ kCmdGhost
+};
+
+class CommandHandler {
+public:
+ struct Command {
+ CommandType _commandType;
+ byte _lab;
+ int _ref;
+ int _val;
+ void *_spritePtr;
+ CallbackType _cbType;
+ } *_commandList;
+ static const char *_commandText[];
+ bool _talkEnable;
+
+ CommandHandler(CGE2Engine *vm, bool turbo);
+ ~CommandHandler();
+ void runCommand();
+ void addCommand(CommandType com, int ref, int val, void *ptr);
+ void addCallback(CommandType com, int ref, int val, CallbackType cbType);
+ void insertCommand(CommandType com, int ref, int val, void *ptr);
+ bool idle();
+ void clear();
+ int getComId(const char *com);
+ const char *getComStr(CommandType cmdType);
+private:
+ CGE2Engine *_vm;
+ bool _turbo;
+ uint8 _head;
+ uint8 _tail;
+ bool _textDelay;
+ uint32 _timerExpiry; // "pause" in the original.
+};
+
+} // End of namespace CGE2
+
+#endif
diff --git a/engines/cge2/sound.cpp b/engines/cge2/sound.cpp
new file mode 100644
index 0000000000..57ec5983e8
--- /dev/null
+++ b/engines/cge2/sound.cpp
@@ -0,0 +1,273 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+/*
+ * This code is based on original Sfinx source code
+ * Copyright (c) 1994-1997 Janus B. Wisniewski and L.K. Avalon
+ */
+
+#include "cge2/sound.h"
+#include "common/config-manager.h"
+#include "common/memstream.h"
+#include "audio/decoders/raw.h"
+#include "audio/audiostream.h"
+#include "cge2/cge2.h"
+
+namespace CGE2 {
+
+DataCk::DataCk(byte *buf, int bufSize) {
+ _buf = buf;
+ _ckSize = bufSize;
+}
+
+DataCk::~DataCk() {
+ free(_buf);
+}
+
+Sound::Sound(CGE2Engine *vm) : _vm(vm) {
+ _audioStream = nullptr;
+ _soundRepeatCount = 1;
+ open();
+}
+
+Sound::~Sound() {
+ close();
+}
+
+void Sound::close() {
+ _vm->_midiPlayer->killMidi();
+}
+
+void Sound::open() {
+ setRepeat(1);
+ if (_vm->_commandHandlerTurbo != nullptr)
+ _vm->switchSay();
+ play(Audio::Mixer::kSFXSoundType, _vm->_fx->load(99, 99));
+}
+
+void Sound::setRepeat(int16 count) {
+ _soundRepeatCount = count;
+}
+
+int16 Sound::getRepeat() {
+ return _soundRepeatCount;
+}
+
+void Sound::play(Audio::Mixer::SoundType soundType, DataCk *wav, int pan) {
+ if (wav) {
+ stop();
+ _smpinf._saddr = &*(wav->addr());
+ _smpinf._slen = (uint16)wav->size();
+ _smpinf._span = pan;
+ _smpinf._counter = getRepeat();
+ sndDigiStart(&_smpinf, soundType);
+ }
+}
+
+void Sound::sndDigiStart(SmpInfo *PSmpInfo, Audio::Mixer::SoundType soundType) {
+ // Create an audio stream wrapper for sound
+ Common::MemoryReadStream *stream = new Common::MemoryReadStream(PSmpInfo->_saddr,
+ PSmpInfo->_slen, DisposeAfterUse::NO);
+ _audioStream = Audio::makeWAVStream(stream, DisposeAfterUse::YES);
+
+ // Decide which handle to use
+ Audio::SoundHandle *handle = nullptr;
+ switch (soundType) {
+ case Audio::Mixer::kSFXSoundType:
+ handle = &_sfxHandle;
+ break;
+ case Audio::Mixer::kSpeechSoundType:
+ handle = &_speechHandle;
+ break;
+ default:
+ error("Wrong sound type passed to sndDigiStart()");
+ }
+
+ // Start the new sound
+ _vm->_mixer->playStream(soundType, handle,
+ Audio::makeLoopingAudioStream(_audioStream, (uint)PSmpInfo->_counter));
+
+ // CGE pan:
+ // 8 = Center
+ // Less = Left
+ // More = Right
+ _vm->_mixer->setChannelBalance(*handle, (int8)CLIP(((PSmpInfo->_span - 8) * 16), -127, 127));
+}
+
+void Sound::stop() {
+ sndDigiStop(_sfxHandle);
+ sndDigiStop(_speechHandle);
+ _audioStream = nullptr;
+}
+
+void Sound::checkSoundHandles() {
+ if (!_vm->_mixer->isSoundHandleActive(_speechHandle) && !_vm->_mixer->isSoundHandleActive(_sfxHandle))
+ _smpinf._counter = 0;
+}
+
+void Sound::sndDigiStop(Audio::SoundHandle &handle) {
+ if (_vm->_mixer->isSoundHandleActive(handle))
+ _vm->_mixer->stopHandle(handle);
+}
+
+Fx::Fx(CGE2Engine *vm, int size) : _current(nullptr), _vm(vm) {
+}
+
+Fx::~Fx() {
+ clear();
+}
+
+void Fx::clear() {
+ if (_current)
+ delete _current;
+ _current = nullptr;
+}
+
+Common::String Fx::name(int ref, int sub) {
+ const char *fxname = "%.2dfx%.2d.WAV";
+ const char *subName = "%.2dfx%.2d?.WAV";
+ const char *p = (sub) ? subName : fxname;
+ Common::String filename = Common::String::format(p, ref >> 8, ref & 0xFF);
+ if (sub)
+ filename.setChar('@' + sub, 6);
+ return filename;
+}
+
+bool Fx::exist(int ref, int sub) {
+ return _vm->_resman->exist(name(ref, sub).c_str());
+}
+
+DataCk *Fx::load(int ref, int sub) {
+ Common::String filename = name(ref, sub);
+ EncryptedStream file(_vm, filename.c_str());
+ clear();
+ return (_current = loadWave(&file));
+}
+
+DataCk *Fx::loadWave(EncryptedStream *file) {
+ byte *data = (byte *)malloc(file->size());
+
+ if (!data)
+ return 0;
+
+ file->read(data, file->size());
+
+ return new DataCk(data, file->size());
+}
+
+MusicPlayer::MusicPlayer(CGE2Engine *vm) : _vm(vm) {
+ _data = nullptr;
+ _isGM = false;
+
+ MidiPlayer::createDriver();
+
+ int ret = _driver->open();
+ if (ret == 0) {
+ if (_nativeMT32)
+ _driver->sendMT32Reset();
+ else
+ _driver->sendGMReset();
+
+ // TODO: Load cmf.ins with the instrument table. It seems that an
+ // interface for such an operation is supported for AdLib. Maybe for
+ // this card, setting instruments is necessary.
+
+ _driver->setTimerCallback(this, &timerCallback);
+ }
+ _dataSize = -1;
+}
+
+MusicPlayer::~MusicPlayer() {
+ killMidi();
+}
+
+void MusicPlayer::killMidi() {
+ Audio::MidiPlayer::stop();
+
+ free(_data);
+ _data = nullptr;
+}
+
+void MusicPlayer::loadMidi(int ref) {
+ if (_vm->_midiNotify != nullptr)
+ (_vm->*_vm->_midiNotify)();
+
+ // Work out the filename and check the given MIDI file exists
+ Common::String filename = Common::String::format("%.2dSG%.2d.MID", ref >> 8, ref & 0xFF);
+ if (!_vm->_resman->exist(filename.c_str()))
+ return;
+
+ // Stop any currently playing MIDI file
+ killMidi();
+
+ // Read in the data for the file
+ EncryptedStream mid(_vm, filename.c_str());
+ _dataSize = mid.size();
+ _data = (byte *)malloc(_dataSize);
+ mid.read(_data, _dataSize);
+
+ // Start playing the music
+ sndMidiStart();
+}
+
+void MusicPlayer::sndMidiStart() {
+ _isGM = true;
+
+ MidiParser *parser = MidiParser::createParser_SMF();
+ if (parser->loadMusic(_data, _dataSize)) {
+ parser->setTrack(0);
+ parser->setMidiDriver(this);
+ parser->setTimerRate(_driver->getBaseTempo());
+ parser->property(MidiParser::mpCenterPitchWheelOnUnload, 1);
+
+ _parser = parser;
+
+ syncVolume();
+
+ // Al the tracks are supposed to loop
+ _isLooping = true;
+ _isPlaying = true;
+ }
+}
+
+void MusicPlayer::send(uint32 b) {
+ if (((b & 0xF0) == 0xC0) && !_isGM && !_nativeMT32) {
+ b = (b & 0xFFFF00FF) | MidiDriver::_mt32ToGm[(b >> 8) & 0xFF] << 8;
+ }
+
+ Audio::MidiPlayer::send(b);
+}
+
+void MusicPlayer::sendToChannel(byte channel, uint32 b) {
+ if (!_channelsTable[channel]) {
+ _channelsTable[channel] = (channel == 9) ? _driver->getPercussionChannel() : _driver->allocateChannel();
+ // If a new channel is allocated during the playback, make sure
+ // its volume is correctly initialized.
+ if (_channelsTable[channel])
+ _channelsTable[channel]->volume(_channelsVolume[channel] * _masterVolume / 255);
+ }
+
+ if (_channelsTable[channel])
+ _channelsTable[channel]->send(b);
+}
+
+} // End of namespace CGE2
diff --git a/engines/cge2/sound.h b/engines/cge2/sound.h
new file mode 100644
index 0000000000..6673b67b7a
--- /dev/null
+++ b/engines/cge2/sound.h
@@ -0,0 +1,131 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+/*
+ * This code is based on original Sfinx source code
+ * Copyright (c) 1994-1997 Janus B. Wisniewski and L.K. Avalon
+ */
+
+#ifndef CGE2_SOUND_H
+#define CGE2_SOUND_H
+
+#include "cge2/fileio.h"
+#include "audio/audiostream.h"
+#include "audio/decoders/wave.h"
+#include "audio/fmopl.h"
+#include "audio/mididrv.h"
+#include "audio/midiparser.h"
+#include "audio/midiplayer.h"
+#include "audio/mixer.h"
+#include "common/memstream.h"
+
+namespace CGE2 {
+
+class CGE2Engine;
+
+// sample info
+struct SmpInfo {
+ const uint8 *_saddr; // address
+ uint16 _slen; // length
+ uint16 _span; // left/right pan (0-15)
+ int _counter; // number of time the sample should be played
+};
+
+class DataCk {
+ byte *_buf;
+ int _ckSize;
+public:
+ DataCk(byte *buf, int bufSize);
+ ~DataCk();
+ inline const byte *addr() {
+ return _buf;
+ }
+ inline int size() {
+ return _ckSize;
+ }
+};
+
+class Sound {
+public:
+ SmpInfo _smpinf;
+
+ Sound(CGE2Engine *vm);
+ ~Sound();
+ void open();
+ void close();
+ void play(Audio::Mixer::SoundType soundType, DataCk *wav, int pan = 8);
+ int16 getRepeat();
+ void setRepeat(int16 count);
+ void stop();
+ void checkSoundHandles();
+private:
+ int _soundRepeatCount;
+ CGE2Engine *_vm;
+ Audio::SoundHandle _sfxHandle;
+ Audio::SoundHandle _speechHandle;
+ Audio::RewindableAudioStream *_audioStream;
+
+ void sndDigiStart(SmpInfo *PSmpInfo, Audio::Mixer::SoundType soundType);
+ void sndDigiStop(Audio::SoundHandle &handle);
+};
+
+class Fx {
+ CGE2Engine *_vm;
+
+ DataCk *loadWave(EncryptedStream *file);
+ Common::String name(int ref, int sub);
+public:
+ DataCk *_current;
+
+ Fx(CGE2Engine *vm, int size);
+ ~Fx();
+ void clear();
+ bool exist(int ref, int sub = 0);
+ DataCk *load(int ref, int sub = 0);
+};
+
+class MusicPlayer: public Audio::MidiPlayer {
+private:
+ CGE2Engine *_vm;
+ byte *_data;
+ int _dataSize;
+ bool _isGM;
+
+ // Start MIDI File
+ void sndMidiStart();
+
+ // Stop MIDI File
+ void sndMidiStop();
+public:
+ MusicPlayer(CGE2Engine *vm);
+ ~MusicPlayer();
+
+ void loadMidi(int ref);
+ void killMidi();
+
+ virtual void send(uint32 b);
+ virtual void sendToChannel(byte channel, uint32 b);
+};
+
+} // End of namespace CGE2
+
+#endif // CGE2_SOUND_H
diff --git a/engines/cge2/spare.cpp b/engines/cge2/spare.cpp
new file mode 100644
index 0000000000..76bdbfa7ef
--- /dev/null
+++ b/engines/cge2/spare.cpp
@@ -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.
+ *
+ */
+
+/*
+ * This code is based on original Sfinx source code
+ * Copyright (c) 1994-1997 Janus B. Wisniewski and L.K. Avalon
+ */
+
+#include "cge2/spare.h"
+
+namespace CGE2 {
+
+void Spare::sync(Common::Serializer &s) {
+ int size = 0;
+ if (s.isSaving()) {
+ for (uint i = 0; i < _container.size(); i++)
+ if (_container[i]->_ref >= 141)
+ size++;
+ s.syncAsSint16LE(size);
+
+ for (uint i = 0; i < _container.size(); i++) {
+ if (_container[i]->_ref >= 141)
+ _container[i]->sync(s);
+ }
+ } else {
+ s.syncAsSint16LE(size);
+
+ for (int i = 0; i < size; i++) {
+ Sprite *sprite = new Sprite(_vm);
+ sprite->sync(s);
+ update(sprite);
+ }
+ }
+}
+
+void Spare::clear() {
+ for (uint i = 0; i < _container.size(); i++)
+ delete _container[i];
+
+ _container.clear();
+}
+
+Sprite *Spare::locate(int ref) {
+ for (uint i = 0; i < _container.size(); ++i) {
+ if (_container[i]->_ref == ref)
+ return _container[i];
+ }
+ return nullptr;
+}
+
+Sprite *Spare::take(int ref) {
+ Sprite *spr = nullptr;
+ if ((spr = locate(ref)) != nullptr) {
+ for (uint i = 0; i < _container.size(); ++i) {
+ if (spr == _container[i]) {
+ _container.remove_at(i);
+ break;
+ }
+ }
+ }
+ return spr;
+}
+
+void Spare::takeScene(int cav) {
+ int bakRef = cav << 8;
+ Common::Array<Sprite*> tempCont = _container;
+ for (uint i = 0; i < tempCont.size(); ++i) {
+ Sprite *spr = tempCont[i];
+ int c = spr->_scene;
+ if ((c == _vm->_now || c == 0) && spr->_ref != bakRef) {
+ spr = locate(spr->_ref);
+ _vm->_vga->_showQ->insert(spr);
+ }
+ }
+}
+
+void Spare::store(Sprite *spr) {
+ _container.push_back(spr);
+}
+
+void Spare::update(Sprite *spr) {
+ Sprite *sp = locate(spr->_ref);
+ if (sp == nullptr)
+ store(spr);
+ else {
+ sp->contract();
+ *sp = *spr;
+ }
+}
+
+void Spare::dispose(Sprite *spr) {
+ if (spr) {
+ _vm->_vga->_showQ->remove(spr);
+ update(spr->contract());
+ }
+}
+
+void Spare::dispose(int ref) {
+ dispose(_vm->_vga->_showQ->locate(ref));
+}
+
+void Spare::dispose() {
+ for (uint i = 0; i < _container.size(); ++i) {
+ if (_container[i]->_ref > 255)
+ dispose(_container[i]);
+ }
+}
+
+} // End of namespace CGE2
diff --git a/engines/cge2/spare.h b/engines/cge2/spare.h
new file mode 100644
index 0000000000..24a97712ff
--- /dev/null
+++ b/engines/cge2/spare.h
@@ -0,0 +1,56 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+/*
+ * This code is based on original Sfinx source code
+ * Copyright (c) 1994-1997 Janus B. Wisniewski and L.K. Avalon
+ */
+
+#ifndef CGE2_SPARE_H
+#define CGE2_SPARE_H
+
+#include "cge2/vga13h.h"
+
+namespace CGE2 {
+
+class Spare {
+ CGE2Engine *_vm;
+ Common::Array<Sprite*> _container;
+public:
+ Spare(CGE2Engine *vm) : _vm(vm) {}
+ ~Spare() { clear(); }
+ void store(Sprite *spr);
+ Sprite *locate(int ref);
+ Sprite *take(int ref);
+ void takeScene(int cav);
+ void update(Sprite *spr);
+ void dispose(Sprite *spr);
+ void dispose(int ref);
+ void dispose();
+ void sync(Common::Serializer &s);
+ uint16 count() { return _container.size(); }
+ void clear();
+};
+
+} // End of namespace CGE2
+
+#endif // CGE2_SPARE_H
diff --git a/engines/cge2/talk.cpp b/engines/cge2/talk.cpp
new file mode 100644
index 0000000000..8e6be6cac2
--- /dev/null
+++ b/engines/cge2/talk.cpp
@@ -0,0 +1,312 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+/*
+ * This code is based on original Sfinx source code
+ * Copyright (c) 1994-1997 Janus B. Wisniewski and L.K. Avalon
+ */
+
+#include "cge2/general.h"
+#include "cge2/talk.h"
+
+namespace CGE2 {
+
+void CGE2Engine::setAutoColors() {
+ Dac def[4] = {
+ { 0, 0, 0 },
+ { 220 >> 2, 220 >> 2, 220 >> 2 },
+ { 190 >> 2, 190 >> 2, 190 >> 2 },
+ { 160 >> 2, 160 >> 2, 160 >> 2 },
+ };
+ Dac pal[kPalCount];
+ _vga->getColors(pal);
+ for (int i = 0; i < 4; i++)
+ _font->_colorSet[kCBRel][i] = _vga->closest(pal, def[i]);
+}
+
+Font::Font(CGE2Engine *vm) : _vm(vm) {
+ _map = new uint8[kMapSize];
+ _pos = new uint16[kPosSize];
+ _widthArr = new uint8[kWidSize];
+
+ load();
+}
+
+Font::~Font() {
+ delete[] _map;
+ delete[] _pos;
+ delete[] _widthArr;
+}
+
+void Font::load() {
+ char path[10];
+ strcpy(path, "CGE.CFT");
+ if (!_vm->_resman->exist(path))
+ error("Missing Font file! %s", path);
+
+ EncryptedStream fontFile(_vm, path);
+ assert(!fontFile.err());
+
+ fontFile.read(_widthArr, kWidSize);
+ assert(!fontFile.err());
+
+ uint16 p = 0;
+ for (uint16 i = 0; i < kPosSize; i++) {
+ _pos[i] = p;
+ p += _widthArr[i];
+ }
+ fontFile.read(_map, p);
+
+ strcpy(path, "CGE.TXC");
+ if (!_vm->_resman->exist(path))
+ error("Missing Color file! %s", path);
+
+ // Reading in _colorSet:
+ EncryptedStream colorFile(_vm, path);
+ assert(!colorFile.err());
+
+ char tmpStr[kLineMax + 1];
+ int n = 0;
+
+ for (Common::String line = colorFile.readLine(); !colorFile.eos(); line = colorFile.readLine()){
+ if (line.empty())
+ continue;
+ Common::strlcpy(tmpStr, line.c_str(), sizeof(tmpStr));
+ _colorSet[n][0] = _vm->number(tmpStr);
+
+ for (int i = 1; i < 4; i++)
+ _colorSet[n][i] = _vm->number(nullptr);
+
+ n++;
+ }
+}
+
+uint16 Font::width(const char *text) {
+ uint16 w = 0;
+ if (!text)
+ return 0;
+ while (*text)
+ w += _widthArr[(unsigned char)*(text++)];
+ return w;
+}
+
+Talk::Talk(CGE2Engine *vm, const char *text, TextBoxStyle mode, ColorBank color, bool wideSpace)
+ : Sprite(vm), _mode(mode), _created(false), _wideSpace(wideSpace), _vm(vm) {
+ _color = _vm->_font->_colorSet[color];
+
+ if (color == kCBRel)
+ _vm->setAutoColors();
+ update(text);
+}
+
+Talk::Talk(CGE2Engine *vm, ColorBank color)
+ : Sprite(vm), _mode(kTBPure), _created(false), _wideSpace(false), _vm(vm) {
+ _color = _vm->_font->_colorSet[color];
+
+ if (color == kCBRel)
+ _vm->setAutoColors();
+}
+
+uint8 *Talk::box(V2D siz) {
+ uint16 n, r = (_mode == kTBRound) ? kTextRoundCorner : 0;
+ const byte lt = _color[1], bg = _color[2], dk = _color[3];
+
+ if (siz.x < 8)
+ siz.x = 8;
+ if (siz.y < 8)
+ siz.y = 8;
+ uint8 *b = new uint8[n = siz.area()];
+ memset(b, bg, n);
+
+ if (_mode) {
+ uint8 *p = b;
+ uint8 *q = b + n - siz.x;
+ memset(p, lt, siz.x);
+ memset(q, dk, siz.x);
+ while (p < q) {
+ p += siz.x;
+ *(p - 1) = dk;
+ *p = lt;
+ }
+ p = b;
+ for (int i = 0; i < r; i++) {
+ int j = 0;
+ for (; j < r - i; j++) {
+ p[j] = kPixelTransp;
+ p[siz.x - j - 1] = kPixelTransp;
+ q[j] = kPixelTransp;
+ q[siz.x - j - 1] = kPixelTransp;
+ }
+ p[j] = lt;
+ p[siz.x - j - 1] = dk;
+ q[j] = lt;
+ q[siz.x - j - 1] = dk;
+ p += siz.x;
+ q -= siz.x;
+ }
+ }
+ return b;
+}
+
+void Talk::update(const char *text) {
+ const uint16 vmarg = (_mode) ? kTextVMargin : 0;
+ const uint16 hmarg = (_mode) ? kTextHMargin : 0;
+ uint16 mw;
+ uint16 mh;
+ uint16 ln = vmarg;
+ uint8 *m;
+ uint8 *map;
+ uint8 fg = _color[0];
+
+ if (_created) {
+ mw = _ext->_shpList->_w;
+ mh = _ext->_shpList->_h;
+ delete _ext->_shpList;
+ } else {
+ uint16 k = 2 * hmarg;
+ mh = 2 * vmarg + kFontHigh;
+ mw = 0;
+ for (const char *p = text; *p; p++) {
+ if ((*p == '|') || (*p == '\n')) {
+ mh += kFontHigh + kTextLineSpace;
+ if (k > mw)
+ mw = k;
+ k = 2 * hmarg;
+ } else if ((*p == 0x20) && (_vm->_font->_widthArr[(unsigned char)*p] > 4) && (!_wideSpace))
+ k += _vm->_font->_widthArr[(unsigned char)*p] - 2;
+ else
+ k += _vm->_font->_widthArr[(unsigned char)*p];
+ }
+ if (k > mw)
+ mw = k;
+
+ _created = true;
+ }
+
+ V2D sz(_vm, mw, mh);
+ map = box(sz);
+
+ m = map + ln * mw + hmarg;
+
+ while (*text) {
+ if ((*text == '|') || (*text == '\n'))
+ m = map + (ln += kFontHigh + kTextLineSpace) * mw + hmarg;
+ else {
+ int cw = _vm->_font->_widthArr[(unsigned char)*text];
+ uint8 *f = _vm->_font->_map + _vm->_font->_pos[(unsigned char)*text];
+
+ // Handle properly space size, after it was enlarged to display properly
+ // 'F1' text.
+ int8 fontStart = 0;
+ if ((*text == 0x20) && (cw > 4) && (!_wideSpace))
+ fontStart = 2;
+
+ for (int i = fontStart; i < cw; i++) {
+ uint8 *pp = m;
+ uint16 n;
+ uint16 b = *(f++);
+ for (n = 0; n < kFontHigh; n++) {
+ if (b & 1)
+ *pp = fg;
+ b >>= 1;
+ pp += mw;
+ }
+ m++;
+ }
+ }
+ text++;
+ }
+ BitmapPtr b = new Bitmap[1];
+ b[0] = Bitmap(_vm, sz.x, sz.y, map);
+ delete[] map;
+ setShapeList(b, 1);
+}
+
+InfoLine::InfoLine(CGE2Engine *vm, uint16 w, ColorBank color)
+: Talk(vm), _oldText(nullptr), _newText(nullptr), _realTime(false), _vm(vm) {
+ _wideSpace = false;
+ BitmapPtr b = new Bitmap[1];
+ if (color == kCBRel)
+ _vm->setAutoColors();
+ _color = _vm->_font->_colorSet[color];
+ V2D siz = V2D(_vm, w, kFontHigh);
+ b[0] = Bitmap(_vm, siz.x, siz.y, _color[2]);
+ setShapeList(b, 1);
+}
+
+void InfoLine::update(const char *text) {
+ if (!_realTime && (text == _oldText))
+ return;
+
+ _oldText = text;
+
+ uint16 w = _ext->_shpList->_w;
+ uint16 h = _ext->_shpList->_h;
+ uint8 *v = _ext->_shpList->_v;
+ uint16 dsiz = w >> 2; // data size (1 plane line size)
+ uint16 lsiz = 2 + dsiz + 2; // uint16 for line header, uint16 for gap
+ uint16 psiz = h * lsiz; // - last gape, but + plane trailer
+ uint16 size = 4 * psiz; // whole map size
+ uint8 fg = _color[0];
+ uint8 bg = _color[2];
+
+ // clear whole rectangle
+ memset(v + 2, bg, dsiz); // data bytes
+ for (byte *pDest = v + lsiz; pDest < (v + psiz); pDest += lsiz) {
+ Common::copy(v, v + lsiz, pDest);
+ }
+ *(uint16 *)(v + psiz - 2) = TO_LE_16(kBmpEOI); // plane trailer uint16
+ for (byte *pDest = v + psiz; pDest < (v + 4 * psiz); pDest += psiz) {
+ Common::copy(v, v + psiz, pDest);
+ }
+
+ // paint text line
+ if (_newText) {
+ uint8 *p = v + 2, *q = p + size;
+
+ while (*text) {
+ uint16 cw = _vm->_font->_widthArr[(unsigned char)*text];
+ uint8 *fp = _vm->_font->_map + _vm->_font->_pos[(unsigned char)*text];
+
+ // Handle properly space size, after it was enlarged to display properly
+ // 'F1' text.
+ int8 fontStart = 0;
+ if ((*text == 0x20) && (cw > 4) && (!_wideSpace))
+ fontStart = 2;
+
+ for (int i = fontStart; i < cw; i++) {
+ uint16 b = fp[i];
+ for (uint16 n = 0; n < kFontHigh; n++) {
+ if (b & 1)
+ *p = fg;
+ b >>= 1;
+ p += lsiz;
+ }
+ if (p >= q)
+ p = p - size + 1;
+ }
+ text++;
+ }
+ }
+}
+
+} // End of namespace CGE2
diff --git a/engines/cge2/talk.h b/engines/cge2/talk.h
new file mode 100644
index 0000000000..d7484655cc
--- /dev/null
+++ b/engines/cge2/talk.h
@@ -0,0 +1,94 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+/*
+ * This code is based on original Sfinx source code
+ * Copyright (c) 1994-1997 Janus B. Wisniewski and L.K. Avalon
+ */
+
+#ifndef CGE2_TALK_H
+#define CGE2_TALK_H
+
+#include "cge2/general.h"
+#include "cge2/vga13h.h"
+
+namespace CGE2 {
+
+#define kTextHMargin (6&~1) // EVEN horizontal margins!
+#define kTextVMargin 5 // vertical margins
+#define kTextLineSpace 2 // line spacing
+#define kTextRoundCorner 3 // rounded corners
+#define kWidSize 256
+#define kPosSize 256
+#define kMapSize (256*8)
+#define kFontHigh 8
+#define kCaptionSide 24
+#define kInfName 101
+#define kSayName 102
+
+class Font {
+ void load();
+ CGE2Engine *_vm;
+public:
+ uint8 *_widthArr;
+ uint16 *_pos;
+ uint8 *_map;
+ uint8 _colorSet[kColorNum][4];
+ Font(CGE2Engine *vm);
+ ~Font();
+ uint16 width(const char *text);
+};
+
+enum TextBoxStyle { kTBPure, kTBRect, kTBRound };
+
+class Talk : public Sprite {
+protected:
+ TextBoxStyle _mode;
+ bool _created;
+ uint8 *box(V2D siz);
+ bool _wideSpace;
+public:
+ uint8 *_color;
+
+ Talk(CGE2Engine *vm, const char *text, TextBoxStyle mode = kTBPure, ColorBank color = kCBStd, bool wideSpace = false);
+ Talk(CGE2Engine *vm, ColorBank color = kCBStd);
+
+ void update(const char *text);
+private:
+ CGE2Engine *_vm;
+};
+
+class InfoLine : public Talk {
+ const char *_oldText, *_newText;
+public:
+ bool _realTime;
+ InfoLine(CGE2Engine *vm, uint16 wid, ColorBank color = kCBStd);
+ void update(const char *text);
+ void update() { update(_newText); }
+ void setText(const char *txt) { _newText = txt; }
+private:
+ CGE2Engine *_vm;
+};
+
+} // End of namespace CGE2
+
+#endif // CGE2_TALK_H
diff --git a/engines/cge2/text.cpp b/engines/cge2/text.cpp
new file mode 100644
index 0000000000..d51c04843d
--- /dev/null
+++ b/engines/cge2/text.cpp
@@ -0,0 +1,197 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+/*
+ * This code is based on original Sfinx source code
+ * Copyright (c) 1994-1997 Janus B. Wisniewski and L.K. Avalon
+ */
+
+#include "cge2/text.h"
+#include "common/str.h"
+
+namespace CGE2 {
+
+Text::Text(CGE2Engine *vm, const char *fname) : _vm(vm) {
+ _vm->mergeExt(_fileName, fname, kSayExt);
+ if (!_vm->_resman->exist(_fileName))
+ error("No talk (%s)", _fileName);
+ _txtCount = count();
+ if (_txtCount == -1)
+ error("Unable to read dialog file %s", _fileName);
+
+ _txtCount += 2;
+ _cache = new Handler[_txtCount];
+ for (_size = 0; _size < _txtCount; _size++) {
+ _cache[_size]._ref = 0;
+ _cache[_size]._text = nullptr;
+ }
+ load();
+
+ _cache[_txtCount - 1]._ref = -1;
+ _cache[_txtCount - 1]._text = new char[3];
+ strcpy(_cache[_txtCount - 1]._text, "");
+}
+
+Text::~Text() {
+ clear();
+ delete[] _cache;
+}
+
+int16 Text::count() {
+ EncryptedStream tf(_vm, _fileName);
+ if (tf.err())
+ return -1;
+
+ Common::String line;
+ char tmpStr[kLineMax + 1];
+
+ int counter = 0;
+
+ for (line = tf.readLine(); !tf.eos(); line = tf.readLine()) {
+ char *s;
+ assert(line.size() <= 513);
+ Common::strlcpy(tmpStr, line.c_str(), sizeof(tmpStr));
+ if ((s = strtok(tmpStr, " =,;/\t\n")) == nullptr)
+ continue;
+ if (!Common::isDigit(*s))
+ continue;
+
+ counter++;
+ }
+ return counter;
+}
+
+void Text::clear() {
+ for (int i = 0; i < _txtCount; i++) {
+ if (_cache[i]._ref) {
+ _cache[i]._ref = 0;
+ delete[] _cache[i]._text;
+ _cache[i]._text = nullptr;
+ }
+ }
+}
+
+void Text::load() {
+ EncryptedStream tf(_vm, _fileName);
+ assert(!tf.err());
+
+ Common::String line;
+ char tmpStr[kLineMax + 1];
+ int idx;
+
+ for (idx = 0, line = tf.readLine(); !tf.eos(); line = tf.readLine()) {
+ int n = line.size();
+ char *s;
+ Common::strlcpy(tmpStr, line.c_str(), sizeof(tmpStr));
+ if ((s = strtok(tmpStr, " =,;/\t\n")) == nullptr)
+ continue;
+ if (!Common::isDigit(*s))
+ continue;
+
+ int r = _vm->number(s);
+
+ s += strlen(s);
+ if (s < tmpStr + n)
+ ++s;
+
+ _cache[idx]._ref = r;
+ _cache[idx]._text = new char[strlen(s) + 1];
+ strcpy(_cache[idx]._text, s);
+ idx++;
+ }
+}
+
+char *Text::getText(int ref) {
+ int i;
+ for (i = 0; (i < _size) && (_cache[i]._ref != ref); i++)
+ ;
+
+ if (i < _size)
+ return _cache[i]._text;
+
+ warning("getText: Unable to find ref %d:%d", ref / 256, ref % 256);
+ return nullptr;
+}
+
+void Text::say(const char *text, Sprite *spr) {
+ _vm->killText();
+
+ _vm->_talk = new Talk(_vm, text, kTBRound, kCBSay);
+
+ Speaker *speaker = new Speaker(_vm);
+
+ bool east = spr->_flags._east;
+ V2D d(_vm, 20, spr->_siz.y - 2);
+ if (!east)
+ d.x = -d.x;
+ if (_vm->isHero(spr))
+ d = d.scale(spr->_pos3D._z.trunc());
+ V2D pos = spr->_pos2D + d;
+ uint16 sw = (speaker->_siz.x >> 1);
+ if (!east)
+ sw = -sw;
+
+ if (east) {
+ if (pos.x + sw + kTextRoundCorner + kCaptionSide >= kScrWidth)
+ east = false;
+ } else if (pos.x <= kCaptionSide + kTextRoundCorner - sw)
+ east = true;
+
+ if (east != (d.x > 0)) {
+ d.x = -d.x;
+ sw = -sw;
+ }
+ pos.x = spr->_pos2D.x + d.x + sw;
+
+ _vm->_talk->_flags._kill = true;
+ _vm->_talk->setName(getText(kSayName));
+ _vm->_talk->gotoxyz(pos.x, pos.y + speaker->_siz.y - 1, 0);
+
+ speaker->gotoxyz(pos.x, _vm->_talk->_pos3D._y.trunc() - speaker->_siz.y + 1, 0);
+ speaker->_flags._slav = true;
+ speaker->_flags._kill = true;
+ speaker->setName(getText(kSayName));
+ speaker->step(east);
+
+ _vm->_vga->_showQ->append(_vm->_talk);
+ _vm->_vga->_showQ->append(speaker);
+}
+
+void CGE2Engine::inf(const char *text, ColorBank col) {
+ killText();
+ _talk = new Talk(this, text, kTBRect, col, true);
+ _talk->_flags._kill = true;
+ _talk->setName(_text->getText(kInfName));
+ _talk->center();
+ _vga->_showQ->append(_talk);
+}
+
+void Text::sayTime(Sprite *spr) {
+ TimeDate curTime;
+ _vm->_system->getTimeAndDate(curTime);
+
+ char t[6];
+ snprintf(t, 6, "%d:%02d", curTime.tm_hour, curTime.tm_min);
+ say(t, spr);
+}
+
+} // End of namespace CGE2
diff --git a/engines/cge2/text.h b/engines/cge2/text.h
new file mode 100644
index 0000000000..88ed501158
--- /dev/null
+++ b/engines/cge2/text.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.
+ *
+ */
+
+/*
+ * This code is based on original Sfinx source code
+ * Copyright (c) 1994-1997 Janus B. Wisniewski and L.K. Avalon
+ */
+
+#ifndef CGE2_TEXT_H
+#define CGE2_TEXT_H
+
+#include "cge2/talk.h"
+#include "cge2/cge2.h"
+
+namespace CGE2 {
+
+#define kSayExt ".SAY"
+#define kSysTextMax 1000
+#define kTextNoMouse 95
+#define kInfName 101
+#define kSayName 102
+#define kInfRef 301
+#define kSayRef 302
+
+
+class Text {
+ struct Handler {
+ int _ref;
+ char *_text;
+ } *_cache;
+ int _size;
+ int16 _txtCount;
+ char _fileName[kPathMax];
+ void load();
+ int16 count();
+public:
+ Text(CGE2Engine *vm, const char *fname);
+ ~Text();
+ void clear();
+ char *getText(int ref);
+ void say(const char *text, Sprite *spr);
+ void sayTime(Sprite *spr);
+private:
+ CGE2Engine *_vm;
+};
+
+} // End of namespace CGE2
+
+#endif // CGE2_TEXT_H
diff --git a/engines/cge2/toolbar.cpp b/engines/cge2/toolbar.cpp
new file mode 100644
index 0000000000..0cd220c984
--- /dev/null
+++ b/engines/cge2/toolbar.cpp
@@ -0,0 +1,224 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+/*
+ * This code is based on original Sfinx source code
+ * Copyright (c) 1994-1997 Janus B. Wisniewski and L.K. Avalon
+ */
+
+#include "sound.h"
+#include "common/config-manager.h"
+#include "cge2/cge2.h"
+#include "cge2/events.h"
+#include "cge2/vmenu.h"
+#include "cge2/text.h"
+#include "cge2/cge2_main.h"
+
+namespace CGE2 {
+
+#define kSoundNumToStateRate 25.7
+// == 257 / 10; where 10 equals to the volume switches' number of states [0..9]
+// and ScummVM has a scale of 257 different values for setting sounds.
+
+#define kSoundStateToNumRate 28.45
+// == 256 / 9 + 0.1; where 256 is the positive range of numbers we can set the volume to
+// and the 10 states of a switch cut this range up to 9 equally big parts.
+// We don't take into account 0 regarding the 256 different values (it would be the 257th),
+// since 0 * x == 0.
+// 0.1 is only for correct rounding at the 10th state.
+
+void CGE2Engine::optionTouch(int opt, uint16 mask) {
+ bool notMuted = !ConfMan.getBool("mute");
+ switch (opt) {
+ case 1:
+ if (mask & kMouseLeftUp)
+ switchColorMode();
+ break;
+ case 2:
+ if ((mask & kMouseLeftUp) && notMuted)
+ switchMusic();
+ break;
+ case 3:
+ if (mask & kMouseLeftUp)
+ quit();
+ break;
+ case 4:
+ if ((mask & (kMouseLeftUp | kMouseRightUp)) && notMuted)
+ setVolume(opt - 4, (mask & kMouseLeftUp) ? 1 : -1);
+ break;
+ case 5:
+ if ((mask & (kMouseLeftUp | kMouseRightUp)) && notMuted)
+ setVolume(opt - 4, (mask & kMouseLeftUp) ? 1 : -1);
+ break;
+ case 8:
+ if ((mask & kMouseLeftUp) && notMuted)
+ switchCap();
+ break;
+ case 9:
+ if ((mask & kMouseLeftUp) && notMuted)
+ switchVox();
+ break;
+ default:
+ break;
+ }
+}
+
+void CGE2Engine::switchColorMode() {
+ _commandHandlerTurbo->addCommand(kCmdSeq, 121, _vga->_mono = !_vga->_mono, nullptr);
+ ConfMan.setBool("enable_color_blind", _vga->_mono);
+ ConfMan.flushToDisk();
+ keyClick();
+ _vga->setColors(_vga->_sysPal, 64);
+}
+
+void CGE2Engine::switchMusic() {
+ _music = !_music;
+ _mixer->muteSoundType(Audio::Mixer::kMusicSoundType, !_music);
+ _commandHandlerTurbo->addCommand(kCmdSeq, kMusicRef, _music, nullptr);
+ keyClick();
+ _commandHandlerTurbo->addCommand(kCmdMidi, -1, _music ? (_now << 8) : -1, nullptr);
+}
+
+void CGE2Engine::quit() {
+ if (_commandHandler->idle()) {
+ if (VMenu::_addr) {
+ _commandHandlerTurbo->addCommand(kCmdKill, -1, 0, VMenu::_addr);
+ ReturnToGameChoice rqsChoice(this);
+ rqsChoice.proc();
+ } else {
+ Common::Array<Choice *> quitMenu; // Deleted in VMenu's destructor.
+ quitMenu.push_back(new ExitGameChoice(this));
+ quitMenu.push_back(new ReturnToGameChoice(this));
+ (new VMenu(this, quitMenu, V2D(this, -1, -1), kCBMnu))->setName(_text->getText(kQuitTitle));
+ _commandHandlerTurbo->addCommand(kCmdSeq, kPowerRef, 0, nullptr);
+ keyClick();
+ }
+ }
+}
+
+void CGE2Engine::setVolume(int idx, int cnt) {
+ if (cnt && _vol[idx]) {
+ int p = _vol[idx]->_seqPtr + cnt;
+ if ((p >= 0) && (p < _vol[idx]->_seqCnt)) {
+ _vol[idx]->step(p);
+ int newVolume = (int)(p * kSoundStateToNumRate);
+ switch (idx) {
+ case 0:
+ _oldSfxVolume = ConfMan.getInt("sfx_volume");
+ ConfMan.setInt("sfx_volume", newVolume);
+ break;
+ case 1:
+ _oldMusicVolume = ConfMan.getInt("music_volume");
+ ConfMan.setInt("music_volume", newVolume);
+ break;
+ default:
+ break;
+ }
+ }
+ }
+}
+
+void CGE2Engine::checkVolumeSwitches() {
+ int musicVolume = ConfMan.getInt("music_volume");
+ if (musicVolume != _oldMusicVolume)
+ _vol[1]->step((int)(musicVolume / kSoundNumToStateRate));
+
+ int sfxVolume = ConfMan.getInt("sfx_volume");
+ if (sfxVolume != _oldSfxVolume)
+ _vol[0]->step((int)(sfxVolume / kSoundNumToStateRate));
+}
+
+void CGE2Engine::switchCap() {
+ _sayCap = !_sayCap;
+ if (!_sayCap)
+ _sayVox = true;
+ keyClick();
+ switchSay();
+}
+
+void CGE2Engine::switchVox() {
+ _sayVox = !_sayVox;
+ _mixer->muteSoundType(Audio::Mixer::kSpeechSoundType, _sayVox);
+ if (!_sayVox)
+ _sayCap = true;
+ keyClick();
+ switchSay();
+}
+
+void CGE2Engine::switchSay() {
+ _commandHandlerTurbo->addCommand(kCmdSeq, 129, _sayVox, nullptr);
+ _commandHandlerTurbo->addCommand(kCmdSeq, 128, _sayCap, nullptr);
+}
+
+void CGE2Engine::initToolbar() {
+ selectPocket(-1);
+
+ _commandHandlerTurbo->addCommand(kCmdSeq, kMusicRef, _music, nullptr);
+ if (!_music)
+ _midiPlayer->killMidi();
+
+ switchSay();
+
+ _infoLine->gotoxyz(V3D(kInfoX, kInfoY, 0));
+ _infoLine->setText(nullptr);
+ _vga->_showQ->insert(_infoLine);
+
+ _gamePhase = kPhaseInGame;
+ _mouse->center();
+ _mouse->off();
+ _mouse->on();
+
+ _keyboard->setClient(_sys);
+ _commandHandler->addCommand(kCmdSeq, kPowerRef, 1, nullptr);
+
+ _busyPtr = _vga->_showQ->locate(kBusyRef);
+
+ _vol[0] = _vga->_showQ->locate(kDvolRef);
+ _vol[1] = _vga->_showQ->locate(kMvolRef);
+
+ if (_vol[0]) {
+ int val = ConfMan.getInt("sfx_volume");
+ initVolumeSwitch(_vol[0], val);
+ }
+
+ if (_vol[1]) {
+ int val = ConfMan.getInt("music_volume");
+ initVolumeSwitch(_vol[1], val);
+ }
+}
+
+void CGE2Engine::initVolumeSwitch(Sprite *volSwitch, int val) {
+ int state = 0;
+ state = (int)(val / kSoundNumToStateRate);
+ volSwitch->step(state);
+}
+
+void CGE2Engine::checkMute() {
+ bool mute = ConfMan.getBool("mute");
+ if (mute != _muteAll) {
+ switchMusic();
+ switchVox();
+ _muteAll = mute;
+ }
+}
+
+} // End of namespace CGE2
diff --git a/engines/cge2/vga13h.cpp b/engines/cge2/vga13h.cpp
new file mode 100644
index 0000000000..f4064f3565
--- /dev/null
+++ b/engines/cge2/vga13h.cpp
@@ -0,0 +1,1219 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+/*
+ * This code is based on original Sfinx source code
+ * Copyright (c) 1994-1997 Janus B. Wisniewski and L.K. Avalon
+ */
+
+#include "common/array.h"
+#include "common/config-manager.h"
+#include "common/rect.h"
+#include "graphics/palette.h"
+#include "cge2/general.h"
+#include "cge2/vga13h.h"
+#include "cge2/bitmap.h"
+#include "cge2/text.h"
+#include "cge2/cge2_main.h"
+#include "cge2/cge2.h"
+#include "cge2/vga13h.h"
+
+namespace CGE2 {
+
+void V3D::sync(Common::Serializer &s) {
+ _x.sync(s);
+ _y.sync(s);
+ _z.sync(s);
+}
+
+FXP FXP::operator*(const FXP& x) const {
+ FXP y;
+ int32 t1 = (v >> 8) * x.v;
+ int32 t2 = ((v & 0xFF) * x.v) >> 8;
+
+ y.v = t1 + t2;
+ return y;
+}
+
+FXP FXP::operator/(const FXP& x) const {
+ FXP y;
+ if (x.v != 0) {
+ int32 v1 = this->v;
+ int32 v2 = x.v;
+ bool negFlag = false;
+
+ if (v1 < 0) {
+ v1 = -v1;
+ negFlag = true;
+ }
+ if (v2 < 0) {
+ v2 = -v2;
+ negFlag ^= true;
+ }
+
+ int32 v3 = v1 / v2;
+ v1 -= v3 * v2;
+ v3 <<= 8;
+
+ if (v1 < 0xFFFFFF)
+ v1 <<= 8;
+ else
+ v2 >>= 8;
+
+ v3 += v1 / v2;
+
+ if (negFlag)
+ v3 = -v3;
+
+ y.v = v3;
+ }
+
+ return y;
+}
+
+void FXP::sync(Common::Serializer &s) {
+ s.syncAsSint32LE(v);
+}
+
+Seq *getConstantSeq(bool seqFlag) {
+ const Seq seq1[] = { { 0, 0, 0, 0, 0, 0 } };
+ const Seq seq2[] = { { 0, 1, 0, 0, 0, 0 }, { 1, 0, 0, 0, 0, 0 } };
+
+ Seq *seq;
+ if (seqFlag) {
+ seq = (Seq *)malloc(1 * sizeof(Seq));
+ *seq = seq1[0];
+ } else {
+ seq = (Seq *)malloc(2 * sizeof(Seq));
+ seq[0] = seq2[0];
+ seq[1] = seq2[1];
+ }
+
+ return seq;
+}
+
+byte Sprite::_constY = 0;
+byte Sprite::_follow = 0;
+
+Seq Sprite::_stdSeq8[] =
+{ { 0, 0, 0, 0, 0, 0 },
+ { 1, 1, 0, 0, 0, 0 },
+ { 2, 2, 0, 0, 0, 0 },
+ { 3, 3, 0, 0, 0, 0 },
+ { 4, 4, 0, 0, 0, 0 },
+ { 5, 5, 0, 0, 0, 0 },
+ { 6, 6, 0, 0, 0, 0 },
+ { 7, 7, 0, 0, 0, 0 },
+};
+
+SprExt::SprExt(CGE2Engine *vm)
+ : _p0(vm, 0, 0), _p1(vm, 0, 0),
+ _b0(nullptr), _b1(nullptr), _shpList(nullptr),
+ _location(0), _seq(nullptr), _name(nullptr) {
+ for (int i = 0; i < kActions; i++)
+ _actions[i] = nullptr;
+}
+
+Sprite::Sprite(CGE2Engine *vm)
+ : _siz(_vm, 0, 0), _seqPtr(kNoSeq), _seqCnt(0), _shpCnt(0),
+ _next(nullptr), _prev(nullptr), _time(0),
+ _ext(nullptr), _ref(-1), _scene(0), _vm(vm),
+ _pos2D(_vm, kScrWidth >> 1, 0), _pos3D(kScrWidth >> 1, 0, 0) {
+ memset(_actionCtrl, 0, sizeof(_actionCtrl));
+ memset(_file, 0, sizeof(_file));
+ memset(&_flags, 0, sizeof(_flags));
+ _flags._frnt = 1;
+}
+
+Sprite::Sprite(CGE2Engine *vm, BitmapPtr shpP, int cnt)
+ : _siz(_vm, 0, 0), _seqPtr(kNoSeq), _seqCnt(0), _shpCnt(0),
+ _next(nullptr), _prev(nullptr), _time(0),
+ _ext(nullptr), _ref(-1), _scene(0), _vm(vm),
+ _pos2D(_vm, kScrWidth >> 1, 0), _pos3D(kScrWidth >> 1, 0, 0) {
+ memset(_actionCtrl, 0, sizeof(_actionCtrl));
+ memset(_file, 0, sizeof(_file));
+ memset(&_flags, 0, sizeof(_flags));
+ _flags._frnt = 1;
+
+ setShapeList(shpP, cnt);
+}
+
+Sprite::~Sprite() {
+ contract();
+}
+
+BitmapPtr Sprite::getShp() {
+ SprExt *e = _ext;
+ if (!e || !e->_seq)
+ return nullptr;
+
+ int i = e->_seq[_seqPtr]._now;
+ if (i >= _shpCnt)
+ error("Invalid PHASE in SPRITE::Shp() %s - %d", _file, i);
+ return e->_shpList + i;
+}
+
+void Sprite::setShapeList(BitmapPtr shp, int cnt) {
+ _shpCnt = cnt;
+ _siz.x = 0;
+ _siz.y = 0;
+
+ if (shp) {
+ for (int i = 0; i < cnt; i++) {
+ BitmapPtr p = shp + i;
+ if (p->_w > _siz.x)
+ _siz.x = p->_w;
+ if (p->_h > _siz.y)
+ _siz.y = p->_h;
+ }
+ expand();
+ _ext->_shpList = shp;
+ if (!_ext->_seq) {
+ setSeq(_stdSeq8);
+ _seqCnt = (cnt < ARRAYSIZE(_stdSeq8)) ? cnt : ARRAYSIZE(_stdSeq8);
+ }
+ }
+}
+
+Seq *Sprite::setSeq(Seq *seq) {
+ expand();
+
+ Seq *s = _ext->_seq;
+ _ext->_seq = seq;
+ if (_seqPtr == kNoSeq)
+ step(0);
+ else if (_time == 0)
+ step(_seqPtr);
+ return s;
+}
+
+bool Sprite::seqTest(int n) {
+ if (n >= 0)
+ return (_seqPtr == n);
+ if (_ext)
+ return (_ext->_seq[_seqPtr]._next == _seqPtr);
+ return true;
+}
+
+void Sprite::setName(char *newName) {
+ if (!_ext)
+ return;
+
+ if (_ext->_name) {
+ delete[] _ext->_name;
+ _ext->_name = nullptr;
+ }
+ if (newName) {
+ _ext->_name = new char[strlen(newName) + 1];
+ strcpy(_ext->_name, newName);
+ }
+}
+
+int Sprite::labVal(Action snq, int lab) {
+ int lv = -1;
+ if (active()) {
+ int count = _actionCtrl[snq]._cnt;
+ CommandHandler::Command *com = snList(snq);
+
+ int i = 0;
+ for (; i < count; i++) {
+ if (com[i]._lab == lab)
+ break;
+ }
+
+ if (i < count)
+ return i;
+ } else {
+ char tmpStr[kLineMax + 1];
+ _vm->mergeExt(tmpStr, _file, kSprExt);
+
+ if (_vm->_resman->exist(tmpStr)) { // sprite description file exist
+ EncryptedStream sprf(_vm, tmpStr);
+ if (sprf.err())
+ error("Bad SPR [%s]", tmpStr);
+
+ int cnt = 0;
+ ID section = kIdPhase;
+ ID id;
+ Common::String line;
+
+ while (lv == -1 && !sprf.eos()) {
+ line = sprf.readLine();
+ if (line.empty())
+ continue;
+
+ Common::strlcpy(tmpStr, line.c_str(), sizeof(tmpStr));
+
+ char *p;
+ p = _vm->token(tmpStr);
+
+ if (*p == '@') {
+ if ((int)section == (int)snq && atoi(p + 1) == lab)
+ lv = cnt;
+ } else {
+ id = _vm->ident(p);
+ switch (id) {
+ case kIdMTake:
+ case kIdFTake:
+ case kIdNear:
+ case kIdPhase:
+ case kIdSeq:
+ section = id;
+ break;
+ default:
+ if (id < 0 && (int)section == (int)snq)
+ ++cnt;
+ break;
+ }
+ }
+ }
+ }
+ }
+ return lv;
+}
+
+CommandHandler::Command *Sprite::snList(Action type) {
+ SprExt *e = _ext;
+ return (e) ? e->_actions[type] : nullptr;
+}
+
+Sprite *Sprite::expand() {
+ if (_ext)
+ return this;
+
+ if (_vm->_spriteNotify != nullptr)
+ (_vm->*_vm->_spriteNotify)();
+
+ char fname[kPathMax];
+ _vm->mergeExt(fname, _file, kSprExt);
+
+ if (_ext != nullptr)
+ delete _ext;
+ _ext = new SprExt(_vm);
+
+ if (!*_file)
+ return this;
+
+ BitmapPtr shplist = new Bitmap[_shpCnt];
+
+ int cnt[kActions],
+ shpcnt = 0,
+ seqcnt = 0,
+ maxnow = 0,
+ maxnxt = 0;
+
+ for (int i = 0; i < kActions; i++)
+ cnt[i] = 0;
+
+ for (int i = 0; i < kActions; i++){
+ byte n = _actionCtrl[i]._cnt;
+ if (n)
+ _ext->_actions[i] = new CommandHandler::Command[n];
+ else
+ _ext->_actions[i] = nullptr;
+ }
+
+ Seq *curSeq = nullptr;
+ if (_seqCnt)
+ curSeq = new Seq[_seqCnt];
+
+ if (_vm->_resman->exist(fname)) { // sprite description file exist
+ EncryptedStream sprf(_vm, fname);
+ if (sprf.err())
+ error("Bad SPR [%s]", fname);
+
+ int label = kNoByte;
+ ID section = kIdPhase;
+ ID id;
+ Common::String line;
+ char tmpStr[kLineMax + 1];
+
+ for (line = sprf.readLine(); !sprf.eos(); line = sprf.readLine()) {
+ if (line.empty())
+ continue;
+ Common::strlcpy(tmpStr, line.c_str(), sizeof(tmpStr));
+
+ char *p = _vm->token(tmpStr);
+ if (*p == '@') {
+ label = atoi(p + 1);
+ continue;
+ }
+
+ id = _vm->ident(p);
+ switch (id) {
+ case kIdType:
+ break;
+ case kIdNear:
+ case kIdMTake:
+ case kIdFTake:
+ case kIdPhase:
+ case kIdSeq:
+ section = id;
+ break;
+ case kIdName:
+ Common::strlcpy(tmpStr, line.c_str(), sizeof(tmpStr));
+ for (p = tmpStr; *p != '='; p++) // We search for the =
+ ;
+ setName(_vm->tail(p));
+ break;
+ default:
+ if (id >= kIdNear)
+ break;
+ Seq *s;
+ switch (section) {
+ case kIdNear:
+ case kIdMTake:
+ case kIdFTake:
+ id = (ID)_vm->_commandHandler->getComId(p);
+ if (_actionCtrl[section]._cnt) {
+ CommandHandler::Command *c = &_ext->_actions[section][cnt[section]++];
+ c->_commandType = CommandType(id);
+ c->_lab = label;
+ c->_ref = _vm->number(nullptr);
+ c->_val = _vm->number(nullptr);
+ c->_spritePtr = nullptr;
+ }
+ break;
+ case kIdSeq:
+ s = &curSeq[seqcnt++];
+ s->_now = atoi(p);
+ if (s->_now > maxnow)
+ maxnow = s->_now;
+ s->_next = _vm->number(nullptr);
+ switch (s->_next) {
+ case 0xFF:
+ s->_next = seqcnt;
+ break;
+ case 0xFE:
+ s->_next = seqcnt - 1;
+ break;
+ }
+ if (s->_next > maxnxt)
+ maxnxt = s->_next;
+ s->_dx = _vm->number(nullptr);
+ s->_dy = _vm->number(nullptr);
+ s->_dz = _vm->number(nullptr);
+ s->_dly = _vm->number(nullptr);
+ break;
+ case kIdPhase:
+ shplist[shpcnt] = Bitmap(_vm, p);
+ shpcnt++;
+ break;
+ default:
+ break;
+ }
+ break;
+ }
+ label = kNoByte;
+ }
+
+ if (!shpcnt)
+ error("No shapes - %s", fname);
+ } else // no sprite description: try to read immediately from .BMP
+ shplist[shpcnt++] = Bitmap(_vm, _file);
+
+ if (curSeq) {
+ if (maxnow >= shpcnt)
+ error("Bad PHASE in SEQ %s", fname);
+ if (maxnxt && (maxnxt >= seqcnt))
+ error("Bad JUMP in SEQ %s", fname);
+ setSeq(curSeq);
+ } else {
+ setSeq(_stdSeq8);
+ _seqCnt = (shpcnt < ARRAYSIZE(_stdSeq8)) ? shpcnt : ARRAYSIZE(_stdSeq8);
+ }
+
+ setShapeList(shplist, shpcnt);
+
+ if (_file[2] == '~') { // FLY-type sprite
+ Seq *nextSeq = _ext->_seq;
+ int x = (nextSeq + 1)->_dx, y = (nextSeq + 1)->_dy, z = (nextSeq + 1)->_dz;
+ // random position
+ nextSeq->_dx = _vm->newRandom(x + x) - x;
+ nextSeq->_dy = _vm->newRandom(y + y) - y;
+ nextSeq->_dz = _vm->newRandom(z + z) - z;
+ gotoxyz(_pos3D + V3D(nextSeq->_dx, nextSeq->_dy, nextSeq->_dz));
+ }
+
+ return this;
+}
+
+Sprite *Sprite::contract() {
+ SprExt *e = _ext;
+ if (!e)
+ return this;
+
+ if (_file[2] == '~') { // FLY-type sprite
+ Seq *curSeq = _ext->_seq;
+ // return to middle
+ gotoxyz(_pos3D - V3D(curSeq->_dx, curSeq->_dy, curSeq->_dz));
+ curSeq->_dx = curSeq->_dy = curSeq->_dz = 0;
+ }
+
+ if (_vm->_spriteNotify != nullptr)
+ (_vm->*_vm->_spriteNotify)();
+
+ if (e->_name) {
+ delete[] e->_name;
+ e->_name = nullptr;
+ }
+
+ if (e->_shpList) {
+ for (int i = 0; i < _shpCnt; i++)
+ e->_shpList[i].release();
+ delete[] e->_shpList;
+ e->_shpList = nullptr;
+ }
+
+ if (e->_seq) {
+ if (e->_seq == _stdSeq8)
+ _seqCnt = 0;
+ else {
+ delete[] e->_seq;
+ e->_seq = nullptr;
+ }
+ }
+
+ for (int i = 0; i < kActions; i++) {
+ if (e->_actions[i]) {
+ delete[] e->_actions[i];
+ e->_actions[i] = nullptr;
+ }
+ }
+
+ delete _ext;
+ _ext = nullptr;
+
+ return this;
+}
+
+void Sprite::backShow() {
+ expand();
+ show(2);
+ show(1);
+ _vm->_spare->dispose(this);
+}
+
+void Sprite::step(int nr) {
+ if (nr >= 0)
+ _seqPtr = nr;
+
+ if (_ext && _ext->_seq) {
+ V3D p = _pos3D;
+ Seq *seq = nullptr;
+
+ if (nr < 0)
+ _seqPtr = _ext->_seq[_seqPtr]._next;
+
+ if (_file[2] == '~') { // FLY-type sprite
+ seq = _ext->_seq;
+ // return to middle
+ p._x -= seq->_dx;
+ p._y -= seq->_dy;
+ p._z -= seq->_dz;
+ // generate motion
+ if (_vm->newRandom(10) < 5) {
+ if ((seq + 1)->_dx)
+ seq->_dx += _vm->newRandom(3) - 1;
+ if ((seq + 1)->_dy)
+ seq->_dy += _vm->newRandom(3) - 1;
+ if ((seq + 1)->_dz)
+ seq->_dz += _vm->newRandom(3) - 1;
+ }
+ if (seq->_dx < -(seq + 1)->_dx)
+ seq->_dx += 2;
+ if (seq->_dx >= (seq + 1)->_dx)
+ seq->_dx -= 2;
+ if (seq->_dy < -(seq + 1)->_dy)
+ seq->_dy += 2;
+ if (seq->_dy >= (seq + 1)->_dy)
+ seq->_dy -= 2;
+ if (seq->_dz < -(seq + 1)->_dz)
+ seq->_dz += 2;
+ if (seq->_dz >= (seq + 1)->_dz)
+ seq->_dz -= 2;
+ p._x += seq->_dx;
+ p._y += seq->_dy;
+ p._z += seq->_dz;
+ gotoxyz(p);
+ } else {
+ seq = _ext->_seq + _seqPtr;
+ if (seq) {
+ if (seq->_dz == 127 && seq->_dx != 0) {
+ _vm->_commandHandlerTurbo->addCommand(kCmdSound, -1, 256 * seq->_dy + seq->_dx, this);
+ } else {
+ p._x += seq->_dx;
+ p._y += seq->_dy;
+ p._z += seq->_dz;
+ gotoxyz(p);
+ }
+ }
+ }
+ if (seq && (seq->_dly >= 0))
+ _time = seq->_dly;
+ } else if (_vm->_waitRef && _vm->_waitRef == _ref)
+ _vm->_waitRef = 0;
+}
+
+void Sprite::tick() {
+ step();
+}
+
+void Sprite::setScene(int c) {
+ _scene = c;
+}
+
+void Sprite::gotoxyz(int x, int y, int z) {
+ gotoxyz(V3D(x, y, z));
+}
+
+void Sprite::gotoxyz() {
+ gotoxyz(_pos3D);
+}
+
+void Sprite::gotoxyz(V2D pos) {
+ V2D o = _pos2D;
+ int ctr = _siz.x >> 1;
+ int rem = _siz.x - ctr;
+ byte trim = 0;
+
+ if (_ref / 10 == 14) { // HERO
+ int z = _pos3D._z.trunc();
+ ctr = (ctr * _vm->_eye->_z.trunc()) / (_vm->_eye->_z.trunc() - z);
+ rem = (rem * _vm->_eye->_z.trunc()) / (_vm->_eye->_z.trunc() - z);
+ ctr = (ctr * 3) / 4;
+ rem = (rem * 3) / 4;
+ }
+
+ if (pos.x - ctr < 0) {
+ pos.x = ctr;
+ ++trim;
+ }
+ if (pos.x + rem > kScrWidth) {
+ pos.x = kScrWidth - rem;
+ ++trim;
+ }
+ _pos2D.x = pos.x;
+
+ if (pos.y < -kPanHeight) {
+ pos.y = -kPanHeight;
+ ++trim;
+ }
+ if (pos.y + _siz.y > kWorldHeight) {
+ pos.y = kWorldHeight - _siz.y;
+ ++trim;
+ }
+ _pos2D.y = pos.y;
+
+ _flags._trim = (trim != 0);
+
+ if (!_follow) {
+ FXP m = _vm->_eye->_z / (_pos3D._z - _vm->_eye->_z);
+ _pos3D._x = (_vm->_eye->_x + (_vm->_eye->_x - _pos2D.x) / m);
+ _pos3D._x.round();
+
+ if (!_constY) {
+ _pos3D._y = _vm->_eye->_y + (_vm->_eye->_y - _pos2D.y) / m;
+ _pos3D._y.round();
+ }
+ }
+
+ if (_next && _next->_flags._slav)
+ _next->gotoxyz(_next->_pos2D - o + _pos2D);
+
+ if (_flags._shad)
+ _prev->gotoxyz(_prev->_pos2D - o + _pos2D);
+}
+
+void Sprite::gotoxyz_(V2D pos) {
+ _constY++;
+ gotoxyz(pos);
+ --_constY;
+}
+
+void Sprite::gotoxyz(V3D pos) {
+ _follow++;
+ if (pos._z != _pos3D._z)
+ _flags._zmov = true;
+ gotoxyz(V2D(_vm, _pos3D = pos));
+ --_follow;
+}
+
+void Sprite::center() {
+ gotoxyz(kScrWidth >> 1, (kWorldHeight - _siz.y) >> 1, 0);
+}
+
+void Sprite::show() {
+ SprExt *e = _ext;
+ if (e) {
+ e->_p0 = e->_p1;
+ e->_b0 = e->_b1;
+ e->_p1 = _pos2D;
+ e->_b1 = getShp();
+
+ if (!_flags._hide)
+ e->_b1->show(e->_p1);
+ }
+}
+
+void Sprite::show(uint16 pg) {
+ assert(pg < 4);
+ Graphics::Surface *a = _vm->_vga->_page[1];
+ _vm->_vga->_page[1] = _vm->_vga->_page[pg];
+ getShp()->show(_pos2D);
+ _vm->_vga->_page[1] = a;
+}
+
+void Sprite::hide() {
+ SprExt *e = _ext;
+ if (e->_b0)
+ e->_b0->hide(e->_p0);
+}
+
+BitmapPtr Sprite::ghost() {
+ SprExt *e = _ext;
+ if (!e->_b1)
+ return nullptr;
+
+ BitmapPtr bmp = new Bitmap(_vm, 0, 0, (uint8 *)nullptr);
+ bmp->_w = e->_b1->_w;
+ bmp->_h = e->_b1->_h;
+ bmp->_b = new HideDesc[bmp->_h];
+ memcpy(bmp->_b, e->_b1->_b, sizeof(HideDesc)* bmp->_h);
+ uint8 *v = new uint8[1];
+ *v = (e->_p1.y << 16) + e->_p1.x;
+ bmp->_v = v;
+ bmp->_map = (e->_p1.y << 16) + e->_p1.x;
+
+ return bmp;
+}
+
+void Sprite::sync(Common::Serializer &s) {
+ s.syncAsUint16LE(_ref);
+ s.syncAsByte(_scene);
+
+ // bitfield in-memory storage is unpredictable, so to avoid
+ // any issues, pack/unpack everything manually
+ uint16 flags = 0;
+ if (s.isLoading()) {
+ s.syncAsUint16LE(flags);
+ _flags._hide = flags & 0x0001;
+ _flags._drag = flags & 0x0002;
+ _flags._hold = flags & 0x0004;
+ _flags._trim = flags & 0x0008;
+ _flags._slav = flags & 0x0010;
+ _flags._kill = flags & 0x0020;
+ _flags._xlat = flags & 0x0040;
+ _flags._port = flags & 0x0080;
+ _flags._kept = flags & 0x0100;
+ _flags._frnt = flags & 0x0200;
+ _flags._east = flags & 0x0400;
+ _flags._near = flags & 0x0800;
+ _flags._shad = flags & 0x1000;
+ _flags._back = flags & 0x2000;
+ _flags._zmov = flags & 0x4000;
+ _flags._tran = flags & 0x8000;
+ } else {
+ flags = (flags << 1) | (_flags._tran ? 1 : 0);
+ flags = (flags << 1) | (_flags._zmov ? 1 : 0);
+ flags = (flags << 1) | (_flags._back ? 1 : 0);
+ flags = (flags << 1) | (_flags._shad ? 1 : 0);
+ flags = (flags << 1) | (_flags._near ? 1 : 0);
+ flags = (flags << 1) | (_flags._east ? 1 : 0);
+ flags = (flags << 1) | (_flags._frnt ? 1 : 0);
+ flags = (flags << 1) | (_flags._kept ? 1 : 0);
+ flags = (flags << 1) | (_flags._port ? 1 : 0);
+ flags = (flags << 1) | (_flags._xlat ? 1 : 0);
+ flags = (flags << 1) | (_flags._kill ? 1 : 0);
+ flags = (flags << 1) | (_flags._slav ? 1 : 0);
+ flags = (flags << 1) | (_flags._trim ? 1 : 0);
+ flags = (flags << 1) | (_flags._hold ? 1 : 0);
+ flags = (flags << 1) | (_flags._drag ? 1 : 0);
+ flags = (flags << 1) | (_flags._hide ? 1 : 0);
+ s.syncAsUint16LE(flags);
+ }
+
+ s.syncAsSint16LE(_pos2D.x);
+ s.syncAsSint16LE(_pos2D.y);
+
+ _pos3D.sync(s);
+
+ s.syncAsSint16LE(_siz.x);
+ s.syncAsSint16LE(_siz.y);
+
+ s.syncAsUint16LE(_time);
+ for (int i = 0; i < kActions; i++){
+ s.syncAsByte(_actionCtrl[i]._ptr);
+ s.syncAsByte(_actionCtrl[i]._cnt);
+ }
+ s.syncAsSint16LE(_seqPtr);
+ s.syncAsSint16LE(_seqCnt);
+ s.syncAsUint16LE(_shpCnt);
+ s.syncBytes((byte *)&_file[0], 9);
+ _file[8] = '\0';
+}
+
+Queue::Queue(bool show) : _head(nullptr), _tail(nullptr) {
+}
+
+void Queue::append(Sprite *spr) {
+ if (spr->_flags._back)
+ spr->backShow();
+ else {
+ spr->expand();
+ if (_tail) {
+ spr->_prev = _tail;
+ _tail->_next = spr;
+ } else
+ _head = spr;
+
+ _tail = spr;
+ }
+}
+
+void Queue::insert(Sprite *spr, Sprite *nxt) {
+ if (spr->_flags._back)
+ spr->backShow();
+ else {
+ spr->expand();
+ if (nxt == _head) {
+ spr->_next = _head;
+ _head = spr;
+ if (!_tail)
+ _tail = spr;
+ } else {
+ spr->_next = nxt;
+ spr->_prev = nxt->_prev;
+ if (spr->_prev)
+ spr->_prev->_next = spr;
+ }
+ if (spr->_next)
+ spr->_next->_prev = spr;
+ }
+}
+
+void Queue::insert(Sprite *spr) {
+ if (locate(spr))
+ return; // We only queue it if it's not already queued.
+
+ Sprite *s;
+ for (s = _head; s; s = s->_next) {
+ if (s->_pos3D._z < spr->_pos3D._z)
+ break;
+ }
+
+ if (s)
+ insert(spr, s);
+ else
+ append(spr);
+}
+
+Sprite *Queue::remove(Sprite *spr) {
+ if (spr == _head)
+ _head = spr->_next;
+
+ if (spr == _tail)
+ _tail = spr->_prev;
+
+ if (spr->_next)
+ spr->_next->_prev = spr->_prev;
+
+ if (spr->_prev)
+ spr->_prev->_next = spr->_next;
+
+ spr->_prev = nullptr;
+ spr->_next = nullptr;
+ return spr;
+}
+
+Sprite *Queue::locate(int ref) {
+ for (Sprite *spr = _head; spr; spr = spr->_next) {
+ if (spr->_ref == ref)
+ return spr;
+ }
+ return nullptr;
+}
+
+bool Queue::locate(Sprite *spr) {
+ Sprite *s;
+ for (s = _head; s; s = s->_next) {
+ if (s == spr)
+ return true;
+ }
+
+ return false;
+}
+
+Vga::Vga(CGE2Engine *vm) : _frmCnt(0), _msg(nullptr), _name(nullptr), _setPal(false), _vm(vm) {
+ _rot._org = 1;
+ _rot._len = 0;
+ _rot._cnt = 0;
+ _rot._dly = 1;
+
+ _oldColors = nullptr;
+ _newColors = nullptr;
+ _showQ = new Queue(true);
+ _sysPal = new Dac[kPalCount];
+
+ for (int idx = 0; idx < 4; idx++) {
+ _page[idx] = new Graphics::Surface();
+ _page[idx]->create(kScrWidth, kScrHeight, Graphics::PixelFormat::createFormatCLUT8());
+ }
+
+ _mono = ConfMan.getBool("enable_color_blind");
+
+ _oldColors = (Dac *)malloc(sizeof(Dac) * kPalCount);
+ _newColors = (Dac *)malloc(sizeof(Dac) * kPalCount);
+ getColors(_oldColors);
+ sunset();
+ setColors();
+ clear(0);
+}
+
+Vga::~Vga() {
+ Common::String buffer = "";
+
+ free(_oldColors);
+ free(_newColors);
+ if (_msg)
+ buffer = Common::String(_msg);
+
+ if (_name)
+ buffer = buffer + " [" + _name + "]";
+
+ debugN("%s", buffer.c_str());
+
+ delete _showQ;
+ delete[] _sysPal;
+
+ for (int idx = 0; idx < 4; idx++) {
+ _page[idx]->free();
+ delete _page[idx];
+ }
+}
+
+void Vga::waitVR() {
+ // Since some of the game parts rely on using vertical sync as a delay mechanism,
+ // we're introducing a short delay to simulate it
+ g_system->delayMillis(5);
+}
+
+void Vga::getColors(Dac *tab) {
+ byte palData[kPalSize];
+ g_system->getPaletteManager()->grabPalette(palData, 0, kPalCount);
+ palToDac(palData, tab);
+}
+
+uint8 Vga::closest(Dac *pal, const uint8 colR, const uint8 colG, const uint8 colB) {
+#define f(col, lum) ((((uint16)(col)) << 8) / lum)
+ uint16 i, dif = 0xFFFF, found = 0;
+ uint16 L = colR + colG + colB;
+ if (!L)
+ L++;
+ uint16 R = f(colR, L), G = f(colG, L), B = f(colB, L);
+ for (i = 0; i < 256; i++) {
+ uint16 l = pal[i]._r + pal[i]._g + pal[i]._b;
+ if (!l)
+ l++;
+ int r = f(pal[i]._r, l), g = f(pal[i]._g, l), b = f(pal[i]._b, l);
+ uint16 D = ((r > R) ? (r - R) : (R - r)) +
+ ((g > G) ? (g - G) : (G - g)) +
+ ((b > B) ? (b - B) : (B - b)) +
+ ((l > L) ? (l - L) : (L - l)) * 10 ;
+
+ if (D < dif) {
+ found = i;
+ dif = D;
+ if (D == 0)
+ break; // exact!
+ }
+ }
+ return found;
+#undef f
+}
+
+uint8 Vga::closest(Dac *pal, Dac x) {
+ int exp = (sizeof(long) * 8 - 1);
+ long D = (1 << exp) - 1; // Maximum value of long.
+ long R = x._r;
+ long G = x._g;
+ long B = x._b;
+ int idx = 255;
+ for (int n = 0; n < 256; n++) {
+ long dR = R - pal[n]._r;
+ long dG = G - pal[n]._g;
+ long dB = B - pal[n]._b,
+ d = dR * dR + dG * dG + dB * dB;
+ if (d < D) {
+ idx = n;
+ D = d;
+ if (!d)
+ break;
+ }
+ }
+ return idx;
+}
+
+uint8 *Vga::glass(Dac *pal, const uint8 colR, const uint8 colG, const uint8 colB) {
+ uint8 *x = (uint8 *)malloc(256);
+ if (x) {
+ for (uint16 i = 0; i < 256; i++) {
+ x[i] = closest(pal, ((uint16)(pal[i]._r) * colR) / 255,
+ ((uint16)(pal[i]._g) * colG) / 255,
+ ((uint16)(pal[i]._b) * colB) / 255);
+ }
+ }
+ return x;
+}
+
+void Vga::palToDac(const byte *palData, Dac *tab) {
+ const byte *colP = palData;
+ for (int idx = 0; idx < kPalCount; idx++, colP += 3) {
+ tab[idx]._r = *colP >> 2;
+ tab[idx]._g = *(colP + 1) >> 2;
+ tab[idx]._b = *(colP + 2) >> 2;
+ }
+}
+
+void Vga::dacToPal(const Dac *tab, byte *palData) {
+ for (int idx = 0; idx < kPalCount; idx++, palData += 3) {
+ *palData = tab[idx]._r << 2;
+ *(palData + 1) = tab[idx]._g << 2;
+ *(palData + 2) = tab[idx]._b << 2;
+ }
+}
+
+void Vga::setColors(Dac *tab, int lum) {
+ Dac *palP = tab, *destP = _newColors;
+ for (int idx = 0; idx < kPalCount; idx++, palP++, destP++) {
+ destP->_r = (palP->_r * lum) >> 6;
+ destP->_g = (palP->_g * lum) >> 6;
+ destP->_b = (palP->_b * lum) >> 6;
+ }
+
+ if (_mono) {
+ destP = _newColors;
+ for (int idx = 0; idx < kPalCount; idx++, destP++) {
+ // Form a grayscale color from 30% R, 59% G, 11% B
+ uint8 intensity = (((int)destP->_r * 77) + ((int)destP->_g * 151) + ((int)destP->_b * 28)) >> 8;
+ destP->_r = intensity;
+ destP->_g = intensity;
+ destP->_b = intensity;
+ }
+ }
+
+ _setPal = true;
+}
+
+void Vga::setColors() {
+ memset(_newColors, 0, kPalSize);
+ updateColors();
+}
+
+void Vga::sunrise(Dac *tab) {
+ for (int i = 0; i <= 64; i += kFadeStep) {
+ setColors(tab, i);
+ waitVR();
+ updateColors();
+ g_system->updateScreen();
+ }
+}
+
+void Vga::sunset() {
+ Dac tab[256];
+ getColors(tab);
+ for (int i = 64; i >= 0; i -= kFadeStep) {
+ setColors(tab, i);
+ waitVR();
+ updateColors();
+ g_system->updateScreen();
+ }
+}
+
+void Vga::show() {
+ _vm->_infoLine->update();
+
+ for (Sprite *spr = _showQ->first(); spr; spr = spr->_next) {
+ spr->show();
+ }
+
+ _vm->_mouse->show();
+ update();
+ rotate();
+
+ for (Sprite *spr = _showQ->first(); spr; spr = spr->_next) {
+ spr->hide();
+ if (spr->_flags._zmov) {
+ Sprite *s = nullptr;
+ Sprite *p = spr->_prev;
+ Sprite *n = spr->_next;
+
+ if (spr->_flags._shad) {
+ s = p;
+ p = s->_prev;
+ }
+
+ if ((p && spr->_pos3D._z > p->_pos3D._z) ||
+ (n && spr->_pos3D._z < n->_pos3D._z)) {
+ _showQ->insert(_showQ->remove(spr));
+ }
+ spr->_flags._zmov = false;
+ }
+ }
+ _vm->_mouse->hide();
+}
+
+void Vga::updateColors() {
+ byte palData[kPalSize];
+ dacToPal(_newColors, palData);
+ g_system->getPaletteManager()->setPalette(palData, 0, 256);
+}
+
+void Vga::update() {
+ SWAP(Vga::_page[0], Vga::_page[1]);
+
+ if (_setPal) {
+ updateColors();
+ _setPal = false;
+ }
+
+ g_system->copyRectToScreen(Vga::_page[0]->getPixels(), kScrWidth, 0, 0, kScrWidth, kScrHeight);
+ g_system->updateScreen();
+}
+
+void Vga::rotate() {
+ if (_rot._len) {
+ Dac c;
+ getColors(_newColors);
+ c = _newColors[_rot._org];
+ memmove(_newColors + _rot._org, _newColors + _rot._org + 1, (_rot._len - 1) * sizeof(Dac));
+ _newColors[_rot._org + _rot._len - 1] = c;
+ _setPal = true;
+ }
+}
+
+void Vga::clear(uint8 color) {
+ for (int paneNum = 0; paneNum < 4; paneNum++)
+ _page[paneNum]->fillRect(Common::Rect(0, 0, kScrWidth, kScrHeight), color);
+}
+
+void Vga::copyPage(uint16 d, uint16 s) {
+ _page[d]->copyFrom(*_page[s]);
+}
+
+void Bitmap::show(V2D pos) {
+ xLatPos(pos);
+
+ const byte *srcP = (const byte *)_v;
+ byte *screenStartP = (byte *)_vm->_vga->_page[1]->getPixels();
+ byte *screenEndP = (byte *)_vm->_vga->_page[1]->getBasePtr(0, kScrHeight);
+
+ // Loop through processing data for each plane. The game originally ran in plane mapped mode, where a
+ // given plane holds each fourth pixel sequentially. So to handle an entire picture, each plane's data
+ // must be decompressed and inserted into the surface
+ for (int planeCtr = 0; planeCtr < 4; planeCtr++) {
+ byte *destP = (byte *)_vm->_vga->_page[1]->getBasePtr(pos.x + planeCtr, pos.y);
+
+ for (;;) {
+ uint16 v = READ_LE_UINT16(srcP);
+ srcP += 2;
+ int cmd = v >> 14;
+ int count = v & 0x3FFF;
+
+ if (cmd == 0) {
+ // End of image
+ break;
+ }
+
+ // Handle a set of pixels
+ while (count-- > 0) {
+ // Transfer operation
+ switch (cmd) {
+ case 1:
+ // SKIP
+ break;
+ case 2:
+ // REPEAT
+ if (destP >= screenStartP && destP < screenEndP)
+ *destP = *srcP;
+ break;
+ case 3:
+ // COPY
+ if (destP >= screenStartP && destP < screenEndP)
+ *destP = *srcP;
+ srcP++;
+ break;
+ }
+
+ // Move to next dest position
+ destP += 4;
+ }
+
+ if (cmd == 2)
+ srcP++;
+ }
+ }
+}
+
+void Bitmap::hide(V2D pos) {
+ xLatPos(pos);
+
+ // Perform clipping to screen
+ int w = MIN<int>(_w, kScrWidth - pos.x);
+ int h = MIN<int>(_h, kScrHeight - pos.y);
+ if (pos.x < 0) {
+ w -= -pos.x;
+ pos.x = 0;
+ if (w < 0)
+ return;
+ }
+ if (pos.y < 0) {
+ h -= -pos.y;
+ pos.y = 0;
+ if (h < 0)
+ return;
+ }
+
+ // Perform copying of screen section
+ for (int yp = pos.y; yp < pos.y + h; yp++) {
+ if (yp >= 0 && yp < kScrHeight) {
+ const byte *srcP = (const byte *)_vm->_vga->_page[2]->getBasePtr(pos.x, yp);
+ byte *destP = (byte *)_vm->_vga->_page[1]->getBasePtr(pos.x, yp);
+
+ Common::copy(srcP, srcP + w, destP);
+ }
+ }
+}
+
+Speaker::Speaker(CGE2Engine *vm): Sprite(vm), _vm(vm) {
+ // Set the sprite list
+ BitmapPtr SP = new Bitmap[2];
+ uint8 *map = Bitmap::makeSpeechBubbleTail(0, _vm->_font->_colorSet);
+ SP[0] = Bitmap(_vm, 15, 16, map);
+ delete[] map;
+ map = Bitmap::makeSpeechBubbleTail(1, _vm->_font->_colorSet);
+ SP[1] = Bitmap(_vm, 15, 16, map);
+ delete[] map;
+ setShapeList(SP, 2);
+}
+
+} // End of namespace CGE2
diff --git a/engines/cge2/vga13h.h b/engines/cge2/vga13h.h
new file mode 100644
index 0000000000..553f183de4
--- /dev/null
+++ b/engines/cge2/vga13h.h
@@ -0,0 +1,308 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+/*
+ * This code is based on original Sfinx source code
+ * Copyright (c) 1994-1997 Janus B. Wisniewski and L.K. Avalon
+ */
+
+#ifndef CGE2_VGA13H_H
+#define CGE2_VGA13H_H
+
+#include "common/serializer.h"
+#include "common/events.h"
+#include "graphics/surface.h"
+#include "cge2/general.h"
+#include "cge2/bitmap.h"
+#include "cge2/snail.h"
+#include "cge2/spare.h"
+#include "cge2/cge2.h"
+
+namespace CGE2 {
+
+#define kFadeStep 2
+#define kVgaColDark 207
+#define kVgaColDarkGray 225 /*219*/
+#define kVgaColGray 231
+#define kVgaColLightGray 237
+#define kPixelTransp 0xFE
+#define kNoSeq (-1)
+#define kNoPtr ((uint8)-1)
+#define kSprExt ".SPR"
+#define kPalCount 256
+#define kPalSize (kPalCount * 3)
+
+class FXP {
+ int32 v;
+public:
+ FXP(void) : v(0) {}
+ FXP (int i0, int f0 = 0) : v((i0 * 256) + ((i0 < 0) ? -f0 : f0)) {}
+ FXP &operator=(const int &x) { v = x << 8; return *this; }
+ FXP operator+(const FXP &x) const { FXP y; y.v = v + x.v; return y; }
+ FXP operator-(const FXP &x) const { FXP y; y.v = v - x.v; return y; }
+ FXP operator*(const FXP &x) const;
+ FXP operator/(const FXP &x) const;
+
+ friend int &operator+=(int &a, const FXP &b) { return a += b.trunc(); }
+ friend int &operator-=(int &a, const FXP &b) { return a -= b.trunc(); }
+ friend FXP &operator+=(FXP &a, const int &b) { a.v += b << 8; return a; }
+ friend FXP &operator-=(FXP &a, const int &b) { a.v -= b << 8; return a; }
+ friend bool operator==(const FXP &a, const FXP &b) { return a.v == b.v; }
+ friend bool operator!=(const FXP &a, const FXP &b) { return a.v != b.v; }
+ friend bool operator<(const FXP &a, const FXP &b) { return a.v < b.v; }
+ friend bool operator>(const FXP &a, const FXP &b) { return a.v > b.v; }
+ int trunc(void) const { return v >> 8; }
+ int round(void) const { return (v + 0x80) >> 8; }
+ bool empty() const { return v == 0; }
+ void sync(Common::Serializer &s);
+};
+
+class V3D {
+public:
+ FXP _x, _y, _z;
+ V3D() { }
+ V3D(FXP x, FXP y, FXP z = 0) : _x(x), _y(y), _z(z) { }
+ V3D(const V3D &p) : _x(p._x), _y(p._y), _z(p._z) { }
+ V3D operator+(const V3D &p) const { return V3D(_x + p._x, _y + p._y, _z + p._z); }
+ V3D operator-(const V3D &p) const { return V3D(_x - p._x, _y - p._y, _z - p._z); }
+ V3D operator*(long n) const { return V3D(_x * n, _y * n, _z * n); }
+ V3D operator/ (long n) const { return V3D(_x / n, _y / n, _z / n); }
+ bool operator==(const V3D &p) const { return _x == p._x && _y == p._y && _z == p._z; }
+ bool operator!=(const V3D &p) const { return _x != p._x || _y != p._y || _z != p._z; }
+ V3D& operator+=(const V3D &x) { return *this = *this + x; }
+ V3D& operator-=(const V3D &x) { return *this = *this - x; }
+ void sync(Common::Serializer &s);
+};
+
+class V2D : public Common::Point {
+ CGE2Engine *_vm;
+public:
+ V2D &operator=(const V3D &p3) {
+ FXP m = _vm->_eye->_z / (p3._z - _vm->_eye->_z);
+ FXP posx = _vm->_eye->_x + (_vm->_eye->_x - p3._x) * m;
+ x = posx.round();
+ FXP posy = _vm->_eye->_y + (_vm->_eye->_y - p3._y) * m;
+ y = posy.round();
+ return *this;
+ }
+ V2D(CGE2Engine *vm) : _vm(vm) { }
+ V2D(CGE2Engine *vm, const V3D &p3) : _vm(vm) { *this = p3; }
+ V2D(CGE2Engine *vm, int posx, int posy) : _vm(vm), Common::Point(posx, posy) { }
+ bool operator<(const V2D &p) const { return (x < p.x) && (y < p.y); }
+ bool operator<=(const V2D &p) const { return (x <= p.x) && (y <= p.y); }
+ bool operator>(const V2D &p) const { return (x > p.x) && (y > p.y); }
+ bool operator>=(const V2D &p) const { return (x >= p.x) && (y >= p.y); }
+ V2D operator+(const V2D &p) const { return V2D(_vm, x + p.x, y + p.y); }
+ V2D operator-(const V2D &p) const { return V2D(_vm, x - p.x, y - p.y); }
+ bool operator==(const V3D &p) const { V3D tmp(x, y); return tmp._x == p._x && tmp._y == p._y && tmp._z == p._z; }
+ bool operator!=(const V3D &p) const { V3D tmp(x, y); return tmp._x != p._x || tmp._y != p._y || tmp._z == p._z; }
+ bool operator==(const V2D &p) const { return x == p.x && y == p.y; }
+ uint16 area() { return x * y; }
+ bool limited(const V2D &p) {
+ return ((x < p.x) && (y < p.y));
+ }
+ V2D scale (int z) {
+ FXP m = _vm->_eye->_z / (_vm->_eye->_z - z);
+ FXP posx = m * x;
+ FXP posy = m * y;
+ return V2D(_vm, posx.trunc(), posy.trunc());
+ }
+};
+
+struct Seq {
+ uint8 _now;
+ uint8 _next;
+ int8 _dx;
+ int8 _dy;
+ int8 _dz;
+ int _dly;
+};
+
+class SprExt {
+public:
+ V2D _p0;
+ V2D _p1;
+ BitmapPtr _b0;
+ BitmapPtr _b1;
+ BitmapPtr _shpList;
+ int _location;
+ Seq *_seq;
+ char *_name;
+ CommandHandler::Command *_actions[kActions];
+ SprExt(CGE2Engine *vm);
+};
+
+class Sprite {
+protected:
+ SprExt *_ext;
+ CGE2Engine *_vm;
+public:
+ int _ref;
+ signed char _scene;
+ struct Flags {
+ bool _hide; // general visibility switch
+ bool _drag; // sprite is moveable
+ bool _hold; // sprite is held with mouse
+ bool _trim; // Trim flag
+ bool _slav; // slave object
+ bool _kill; // dispose memory after remove
+ bool _xlat; // 2nd way display: xlat table
+ bool _port; // portable
+ bool _kept; // kept in pocket
+ bool _frnt; // stay in front of sprite
+ bool _east; // talk to east (in opposite to west)
+ bool _near; // Near action lock
+ bool _shad; // shadow
+ bool _back; // 'send to background' request
+ bool _zmov; // sprite needs Z-update in queue
+ bool _tran; // transparent (untouchable)
+ } _flags;
+ V2D _pos2D;
+ V3D _pos3D;
+ V2D _siz;
+ uint16 _time;
+ struct { byte _ptr, _cnt; } _actionCtrl[kActions];
+ int _seqPtr;
+ int _seqCnt;
+ int _shpCnt;
+ char _file[kMaxFile];
+ // Following trailer is not saved with the game:
+ Sprite *_prev;
+ Sprite *_next;
+ static byte _constY;
+ static byte _follow;
+ static Seq _stdSeq8[];
+
+ bool works(Sprite *spr);
+ bool seqTest(int n);
+ inline bool active() {
+ return _ext != nullptr;
+ }
+ Sprite(CGE2Engine *vm);
+ Sprite(CGE2Engine *vm, BitmapPtr shp, int cnt);
+ virtual ~Sprite();
+ BitmapPtr getShp();
+ void setShapeList(BitmapPtr shp, int cnt);
+ void moveShapesHi();
+ void moveShapesLo();
+ int labVal(Action snq, int lab);
+ virtual Sprite *expand();
+ virtual Sprite *contract();
+ void backShow();
+ void setName(char *newName);
+ inline char *name() {
+ return (_ext) ? _ext->_name : nullptr;
+ }
+ void gotoxyz(int x, int y, int z = 0);
+ void gotoxyz();
+ void gotoxyz(V2D pos);
+ void gotoxyz_(V2D pos);
+ void gotoxyz(V3D pos);
+ void center();
+ void show(uint16 pg);
+ void hide(uint16 pg);
+ void show();
+ void hide();
+ BitmapPtr ghost();
+ void step(int nr = -1);
+ Seq *setSeq(Seq *seq);
+ CommandHandler::Command *snList(Action type);
+ virtual void touch(uint16 mask, V2D pos, Common::KeyCode keyCode);
+ virtual void tick();
+ virtual void setScene(int c);
+ void clrHide() { if (_ext) _ext->_b0 = nullptr; }
+
+ void sync(Common::Serializer &s);
+
+ static void (*notify) ();
+};
+
+class Queue {
+ Sprite *_head;
+ Sprite *_tail;
+public:
+ Queue(bool show);
+
+ void append(Sprite *spr);
+ void insert(Sprite *spr, Sprite *nxt);
+ void insert(Sprite *spr);
+ Sprite *remove(Sprite *spr);
+ Sprite *first() {
+ return _head;
+ }
+ Sprite *last() {
+ return _tail;
+ }
+ Sprite *locate(int ref);
+ bool locate(Sprite *spr);
+ void clear() { _head = _tail = nullptr; }
+};
+
+class Vga {
+ CGE2Engine *_vm;
+ bool _setPal;
+ Dac *_oldColors;
+ Dac *_newColors;
+ const char *_msg;
+ const char *_name;
+
+ void updateColors();
+ void setColors();
+ void waitVR();
+ uint8 closest(Dac *pal, const uint8 colR, const uint8 colG, const uint8 colB);
+
+public:
+ uint32 _frmCnt;
+ Queue *_showQ;
+ bool _mono;
+ Graphics::Surface *_page[4];
+ Dac *_sysPal;
+ struct { uint8 _org, _len, _cnt, _dly; } _rot;
+
+ Vga(CGE2Engine *vm);
+ ~Vga();
+
+ uint8 *glass(Dac *pal, const uint8 colR, const uint8 colG, const uint8 colB);
+ void getColors(Dac *tab);
+ void setColors(Dac *tab, int lum);
+ void clear(uint8 color);
+ void copyPage(uint16 d, uint16 s);
+ void sunrise(Dac *tab);
+ void sunset();
+ void show();
+ void update();
+ void rotate();
+ uint8 closest(Dac *pal, Dac x);
+
+ void palToDac(const byte *palData, Dac *tab);
+ void dacToPal(const Dac *tab, byte *palData);
+};
+
+class Speaker: public Sprite {
+ CGE2Engine *_vm;
+public:
+ Speaker(CGE2Engine *vm);
+};
+
+} // End of namespace CGE2
+
+#endif // CGE2_VGA13H_H
diff --git a/engines/cge2/vmenu.cpp b/engines/cge2/vmenu.cpp
new file mode 100644
index 0000000000..6afe5e9a61
--- /dev/null
+++ b/engines/cge2/vmenu.cpp
@@ -0,0 +1,162 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+/*
+ * This code is based on original Sfinx source code
+ * Copyright (c) 1994-1997 Janus B. Wisniewski and L.K. Avalon
+ */
+
+#include "cge2/text.h"
+#include "cge2/vmenu.h"
+#include "cge2/events.h"
+
+namespace CGE2 {
+
+Choice::Choice(CGE2Engine *vm) : _vm(vm), _text(nullptr) {}
+
+ExitGameChoice::ExitGameChoice(CGE2Engine *vm) : Choice(vm) {
+ _text = _vm->_text->getText(kQuitText);
+}
+
+void ExitGameChoice::proc() {
+ _vm->switchScene(-1);
+}
+
+ReturnToGameChoice::ReturnToGameChoice(CGE2Engine *vm) : Choice(vm) {
+ _text = _vm->_text->getText(kNoQuitText);
+}
+
+void ReturnToGameChoice::proc() {
+ _vm->_commandHandlerTurbo->addCommand(kCmdSeq, kPowerRef, 1, nullptr);
+ _vm->keyClick();
+}
+
+MenuBar::MenuBar(CGE2Engine *vm, uint16 w, byte *c) : Talk(vm) {
+ _color = c;
+ int h = kFontHigh + 2 * kMenuBarVerticalMargin, i = (w += 2 * kMenuBarHorizontalMargin) * h;
+ uint8 *p = new uint8[i];
+ uint8 *p1;
+ uint8 *p2;
+ uint8 lt = _color[kLt];
+ uint8 rb = _color[kRb];
+ BitmapPtr b;
+
+ memset(p + w, kPixelTransp, i - 2 * w);
+ memset(p, lt, w);
+ memset(p + i - w, rb, w);
+ p1 = p;
+ p2 = p + i - 1;
+ for (i = 0; i < h; i++) {
+ *p1 = lt;
+ *p2 = rb;
+ p1 += w;
+ p2 -= w;
+ }
+ b = new Bitmap[1];
+ b[0] = Bitmap(vm, w, h, p);
+ delete[] p;
+ setShapeList(b, 1);
+ _flags._slav = true;
+ _flags._tran = true;
+ _flags._kill = true;
+}
+
+VMenu *VMenu::_addr = nullptr;
+
+VMenu::VMenu(CGE2Engine *vm, Common::Array<Choice *> list, V2D pos, ColorBank col)
+ : Talk(vm, vmGather(list), kTBRect, col), _menu(list), _bar(nullptr), _items(list.size()), _vm(vm) {
+ delete[] _vmgt; // Lefotver of vmGather.
+
+ _addr = this;
+ _recent = -1;
+ _flags._kill = true;
+
+ if (pos.x < 0 || pos.y < 0)
+ center();
+ else
+ gotoxyz(V2D(_vm, pos.x - _siz.x / 2, pos.y - (kTextVMargin + kFontHigh / 2)));
+
+ _vm->_vga->_showQ->append(this);
+ _bar = new MenuBar(_vm, _siz.x - 2 * kTextHMargin, _color);
+ _bar->gotoxyz(V2D(_vm, _pos2D.x, _pos2D.y + kTextVMargin - kMenuBarVerticalMargin));
+ _vm->_vga->_showQ->append(_bar);
+}
+
+char *VMenu::vmGather(Common::Array<Choice *> list) {
+ int len = 0;
+ int h = 0;
+
+ for (uint i = 0; i < list.size(); i++) {
+ len += strlen(list[i]->_text);
+ ++h;
+ }
+ _vmgt = new char[len + h];
+ *_vmgt = '\0';
+ for (uint i = 0; i < list.size(); i++) {
+ if (*_vmgt)
+ strcat(_vmgt, "|");
+ strcat(_vmgt, list[i]->_text);
+ ++h;
+ }
+
+ return _vmgt;
+}
+
+
+VMenu::~VMenu() {
+ _addr = nullptr;
+
+ for (uint i = 0; i < _menu.size(); i++) {
+ delete _menu[i];
+ }
+}
+
+void VMenu::touch(uint16 mask, V2D pos, Common::KeyCode keyCode) {
+ if (_items) {
+ Sprite::touch(mask, pos, keyCode);
+
+ int n = 0;
+ bool ok = false;
+ int h = kFontHigh + kTextLineSpace;
+ pos.y -= kTextVMargin - 1;
+ if (pos.y >= 0) {
+ if (pos.x < 0)
+ pos.x = -pos.x;
+ n = pos.y / h;
+ if (n < _items)
+ ok = (pos.x <= (_siz.x >> 1) - kTextHMargin);
+ else
+ n = _items - 1;
+ }
+
+ _bar->gotoxyz(V2D(_vm, _pos2D.x, _pos2D.y + kTextVMargin + n * h - kMenuBarVerticalMargin));
+ n = _items - 1 - n;
+
+ if (ok && (mask & kMouseLeftUp)) {
+ _items = 0;
+ _vm->_commandHandlerTurbo->addCommand(kCmdKill, -1, 0, this);
+ _menu[_recent = n]->proc();
+ }
+ }
+}
+
+} // End of namespace CGE2
diff --git a/engines/cge2/vmenu.h b/engines/cge2/vmenu.h
new file mode 100644
index 0000000000..f34812dcf4
--- /dev/null
+++ b/engines/cge2/vmenu.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.
+ *
+ */
+
+/*
+ * This code is based on original Sfinx source code
+ * Copyright (c) 1994-1997 Janus B. Wisniewski and L.K. Avalon
+ */
+
+#ifndef CGE2_VMENU_H
+#define CGE2_VMENU_H
+
+#define kMenuBarVerticalMargin 1
+#define kMenuBarHorizontalMargin 3
+#define kLt 3
+#define kRb 1
+
+#include "cge2/cge2.h"
+#include "cge2/talk.h"
+
+namespace CGE2 {
+
+class Choice {
+protected:
+ CGE2Engine *_vm;
+public:
+ char *_text;
+
+ virtual void proc() = 0;
+
+ Choice(CGE2Engine *vm);
+ virtual ~Choice() {};
+};
+
+class ExitGameChoice : public Choice {
+public:
+ ExitGameChoice(CGE2Engine *vm);
+ void proc();
+};
+
+class ReturnToGameChoice : public Choice {
+public:
+ ReturnToGameChoice(CGE2Engine *vm);
+ void proc();
+};
+
+class MenuBar : public Talk {
+public:
+ MenuBar(CGE2Engine *vm, uint16 w, byte *c);
+};
+
+class VMenu : public Talk {
+ CGE2Engine *_vm;
+
+ uint16 _items;
+ Common::Array<Choice *> _menu;
+public:
+ char *_vmgt;
+ static VMenu *_addr;
+ int _recent;
+ MenuBar *_bar;
+
+ VMenu(CGE2Engine *vm, Common::Array<Choice *> list, V2D pos, ColorBank col);
+ ~VMenu();
+ void touch(uint16 mask, V2D pos, Common::KeyCode keyCode);
+ char *vmGather(Common::Array<Choice *> list);
+};
+
+} // End of namespace CGE2
+
+#endif // CGE2_VMENU_H
diff --git a/engines/composer/composer.cpp b/engines/composer/composer.cpp
index 471a29030b..f070338978 100644
--- a/engines/composer/composer.cpp
+++ b/engines/composer/composer.cpp
@@ -135,7 +135,7 @@ Common::Error ComposerEngine::run() {
else
loadLibrary(_pendingPageChanges[i]._pageId);
- lastDrawTime = _system->getMillis();
+ lastDrawTime = 0;
}
_pendingPageChanges.clear();
@@ -168,9 +168,10 @@ Common::Error ComposerEngine::run() {
else
lastDrawTime += frameTime;
+ tickOldScripts();
+
redraw();
- tickOldScripts();
processAnimFrame();
} else if (_needsUpdate) {
redraw();
diff --git a/engines/composer/scripting.cpp b/engines/composer/scripting.cpp
index 94ca2c1bc8..cd78202ecd 100644
--- a/engines/composer/scripting.cpp
+++ b/engines/composer/scripting.cpp
@@ -746,6 +746,7 @@ void ComposerEngine::stopOldScript(uint16 id) {
for (Common::List<OldScript *>::iterator i = _oldScripts.begin(); i != _oldScripts.end(); i++) {
if ((*i)->_id == id) {
+ removeSprite(0, id);
delete *i;
i = _oldScripts.reverse_erase(i);
}
diff --git a/engines/drascula/drascula.cpp b/engines/drascula/drascula.cpp
index 797b6d94b0..c72d77c281 100644
--- a/engines/drascula/drascula.cpp
+++ b/engines/drascula/drascula.cpp
@@ -41,20 +41,6 @@
namespace Drascula {
-struct GameSettings {
- const char *gameid;
- const char *description;
- byte id;
- uint32 features;
- const char *detectname;
-};
-
-static const GameSettings drasculaSettings[] = {
- {"drascula", "Drascula game", 0, 0, 0},
-
- {NULL, NULL, 0, 0, NULL}
-};
-
DrasculaEngine::DrasculaEngine(OSystem *syst, const DrasculaGameDescription *gameDesc) : Engine(syst), _gameDescription(gameDesc) {
_charMap = 0;
_itemLocations = 0;
diff --git a/engines/dreamweb/POTFILES b/engines/dreamweb/POTFILES
index d05d239bb7..64fb20db67 100644
--- a/engines/dreamweb/POTFILES
+++ b/engines/dreamweb/POTFILES
@@ -1 +1,3 @@
engines/dreamweb/detection.cpp
+engines/dreamweb/saveload.cpp
+
diff --git a/engines/fullpipe/fullpipe.cpp b/engines/fullpipe/fullpipe.cpp
index bb0838395d..ebaff32550 100644
--- a/engines/fullpipe/fullpipe.cpp
+++ b/engines/fullpipe/fullpipe.cpp
@@ -163,7 +163,7 @@ FullpipeEngine::FullpipeEngine(OSystem *syst, const ADGameDescription *gameDesc)
for (int i = 0; i < 11; i++)
_currSoundList1[i] = 0;
-
+
for (int i = 0; i < 200; i++)
_mapTable[i] = 0;
@@ -285,7 +285,7 @@ Common::Error FullpipeEngine::run() {
freeGameLoader();
_currentScene = 0;
_updateTicks = 0;
-
+
loadGam("fullpipe.gam");
_needRestart = false;
}
diff --git a/engines/fullpipe/gfx.cpp b/engines/fullpipe/gfx.cpp
index 61fbf7192f..42846850ca 100644
--- a/engines/fullpipe/gfx.cpp
+++ b/engines/fullpipe/gfx.cpp
@@ -153,7 +153,7 @@ bool PictureObject::load(MfcArchive &file, bool bigPicture) {
if (count > 0) {
GameObject *o = new GameObject();
-
+
o->load(file);
_pictureObject2List->push_back(o);
}
@@ -286,9 +286,9 @@ bool GameObject::load(MfcArchive &file) {
_okeyCode = 0;
_flags = 0;
_field_20 = 0;
-
+
_id = file.readUint16LE();
-
+
_objectName = file.readPascalString();
_ox = file.readUint32LE();
_oy = file.readUint32LE();
@@ -498,7 +498,7 @@ bool Picture::load(MfcArchive &file) {
_x = file.readUint32LE();
_y = file.readUint32LE();
_field_44 = file.readUint16LE();
-
+
assert(g_fp->_gameProjectVersion >= 2);
_width = file.readUint32LE();
diff --git a/engines/fullpipe/input.cpp b/engines/fullpipe/input.cpp
index 7c97461a24..b681f4fbe7 100644
--- a/engines/fullpipe/input.cpp
+++ b/engines/fullpipe/input.cpp
@@ -70,7 +70,7 @@ void setInputDisabled(bool state) {
void InputController::addCursor(CursorInfo *cursor) {
CursorInfo *newc = new CursorInfo(cursor);
Common::Point p;
-
+
cursor->picture->getDimensions(&p);
newc->width = p.x;
diff --git a/engines/fullpipe/motion.cpp b/engines/fullpipe/motion.cpp
index 49cf88434e..9573e0517b 100644
--- a/engines/fullpipe/motion.cpp
+++ b/engines/fullpipe/motion.cpp
@@ -1040,11 +1040,11 @@ MessageQueue *MovGraph::doWalkTo(StaticANIObject *subj, int xpos, int ypos, int
if (!mq || !mq->getExCommandByIndex(0))
return 0;
-
+
ExCommand *ex = mq->getExCommandByIndex(0);
- if ((ex->_messageKind != 1 && ex->_messageKind != 20) ||
- ex->_messageNum != subj->_movement->_id ||
+ if ((ex->_messageKind != 1 && ex->_messageKind != 20) ||
+ ex->_messageNum != subj->_movement->_id ||
(ex->_field_14 >= 1 && ex->_field_14 <= subj->_movement->_currDynamicPhaseIndex))
subj->playIdle();
}
@@ -1416,8 +1416,8 @@ Common::Array<MovArr *> *MovGraph::genMovArr(int x, int y, int *arrSize, int fla
movarr = new MovArr;
movarr->_link = lnk;
- movarr->_dist = ((double)(lnk->_movGraphNode1->_y - lnk->_movGraphNode2->_y) * (double)(lnk->_movGraphNode1->_y - point.y) +
- (double)(lnk->_movGraphNode2->_x - lnk->_movGraphNode1->_x) * (double)(point.x - lnk->_movGraphNode1->_x)) /
+ movarr->_dist = ((double)(lnk->_movGraphNode1->_y - lnk->_movGraphNode2->_y) * (double)(lnk->_movGraphNode1->_y - point.y) +
+ (double)(lnk->_movGraphNode2->_x - lnk->_movGraphNode1->_x) * (double)(point.x - lnk->_movGraphNode1->_x)) /
lnk->_distance / lnk->_distance;
movarr->_point = point;
@@ -1445,8 +1445,8 @@ Common::Array<MovArr *> *MovGraph::genMovArr(int x, int y, int *arrSize, int fla
} else {
movarr = new MovArr;
movarr->_link = lnk;
- movarr->_dist = ((double)(lnk->_movGraphNode1->_y - lnk->_movGraphNode2->_y) * (double)(lnk->_movGraphNode1->_y - y) +
- (double)(lnk->_movGraphNode2->_x - lnk->_movGraphNode1->_x) * (double)(x - lnk->_movGraphNode1->_x)) /
+ movarr->_dist = ((double)(lnk->_movGraphNode1->_y - lnk->_movGraphNode2->_y) * (double)(lnk->_movGraphNode1->_y - y) +
+ (double)(lnk->_movGraphNode2->_x - lnk->_movGraphNode1->_x) * (double)(x - lnk->_movGraphNode1->_x)) /
lnk->_distance / lnk->_distance;
movarr->_point.x = x;
movarr->_point.y = y;
diff --git a/engines/fullpipe/scene.cpp b/engines/fullpipe/scene.cpp
index 8463b3ab40..00dd70c1b2 100644
--- a/engines/fullpipe/scene.cpp
+++ b/engines/fullpipe/scene.cpp
@@ -162,7 +162,7 @@ bool Scene::load(MfcArchive &file) {
Background::load(file);
_sceneId = file.readUint16LE();
-
+
_sceneName = file.readPascalString();
debug(0, "scene: <%s> %d", transCyrillic((byte *)_sceneName), _sceneId);
diff --git a/engines/fullpipe/scenes/scene02.cpp b/engines/fullpipe/scenes/scene02.cpp
index 109a20a07a..fd542d580d 100644
--- a/engines/fullpipe/scenes/scene02.cpp
+++ b/engines/fullpipe/scenes/scene02.cpp
@@ -134,5 +134,5 @@ int sceneHandler02(ExCommand *ex) {
return res;
}
-
+
} // End of namespace Fullpipe
diff --git a/engines/fullpipe/scenes/scene14.cpp b/engines/fullpipe/scenes/scene14.cpp
index 21dbe8101f..446f477133 100644
--- a/engines/fullpipe/scenes/scene14.cpp
+++ b/engines/fullpipe/scenes/scene14.cpp
@@ -57,7 +57,7 @@ void scene14_initScene(Scene *sc) {
ball->_flags &= 0xFFFB;
g_vars->scene14_balls.push_back(ball);
-
+
for (uint i = 0; i < 3; i++) {
ball = new StaticANIObject(ball); // create a copy
diff --git a/engines/fullpipe/scenes/scene15.cpp b/engines/fullpipe/scenes/scene15.cpp
index 452f2edeca..efc69a5fa6 100644
--- a/engines/fullpipe/scenes/scene15.cpp
+++ b/engines/fullpipe/scenes/scene15.cpp
@@ -71,7 +71,7 @@ void scene15_initScene(Scene *sc) {
grandma->hide();
g_fp->setObjectState(sO_LeftPipe_15, g_fp->getObjectEnumState(sO_LeftPipe_15, sO_IsOpened));
}
-
+
g_vars->scene15_plusminus = sc->getStaticANIObject1ById(ANI_PLUSMINUS, -1);
if (g_fp->getObjectState(sO_Guard_2) == g_fp->getObjectEnumState(sO_Guard_2, sO_Off))
diff --git a/engines/fullpipe/scenes/scene16.cpp b/engines/fullpipe/scenes/scene16.cpp
index ed3c51a6c2..e9d3a37efd 100644
--- a/engines/fullpipe/scenes/scene16.cpp
+++ b/engines/fullpipe/scenes/scene16.cpp
@@ -57,9 +57,9 @@ void scene16_initScene(Scene *sc) {
boy[1] = new StaticANIObject(boy[0]);
sc->addStaticANIObject(boy[1], 1);
-
+
int idx = 0;
-
+
for (int i = 0; i < 3; i++) {
g_vars->scene16_figures.push_back(boy[idx]);
@@ -68,7 +68,7 @@ void scene16_initScene(Scene *sc) {
if (idx >= 2)
idx = 0;
}
-
+
g_vars->scene16_figures.push_back(sc->getStaticANIObject1ById(ANI_GIRL, -1));
for (int i = 0; i < 4; i++) {
@@ -259,7 +259,7 @@ void sceneHandler16_drink() {
mq = new MessageQueue(g_fp->_currentScene->getMessageQueueById(QU_SC16_BOYKICK), 0, 1);
mq->replaceKeyCode(-1, g_vars->scene16_walkingBoy->_okeyCode);
-
+
ex = new ExCommand(ANI_MAN, 34, 384, 0, 0, 0, 1, 0, 0, 0);
ex->_excFlags |= 3u;
ex->_field_14 = 384;
diff --git a/engines/fullpipe/scenes/scene23.cpp b/engines/fullpipe/scenes/scene23.cpp
index ccfbac9223..f66ea12b4b 100644
--- a/engines/fullpipe/scenes/scene23.cpp
+++ b/engines/fullpipe/scenes/scene23.cpp
@@ -146,7 +146,7 @@ void scene23_initScene(Scene *sc) {
sc->getStaticANIObject1ById(ANI_INV_LEVERHANDLE, -1)->hide();
}
-
+
g_fp->_currentScene = oldsc;
}
diff --git a/engines/fullpipe/scenes/scene27.cpp b/engines/fullpipe/scenes/scene27.cpp
index 1431ceffba..8ec05caaff 100644
--- a/engines/fullpipe/scenes/scene27.cpp
+++ b/engines/fullpipe/scenes/scene27.cpp
@@ -340,7 +340,7 @@ void sceneHandler27_wipeDo() {
bool sceneHandler27_batFallLogic(uint batn) {
Bat *bat = g_vars->scene27_bats[batn];
- int y = (bat->currY - 458.0) * 0.4848484848484849 + 734.0;
+ int y = (int)((bat->currY - 458.0) * 0.4848484848484849 + 734.0);
if (y >= bat->currX)
return false;
diff --git a/engines/fullpipe/scenes/scene28.cpp b/engines/fullpipe/scenes/scene28.cpp
index c21ce05502..de5a96e70d 100644
--- a/engines/fullpipe/scenes/scene28.cpp
+++ b/engines/fullpipe/scenes/scene28.cpp
@@ -46,7 +46,7 @@ void scene28_initScene(Scene *sc) {
g_vars->scene28_lift6inside = false;
g_fp->_floaters->init(g_fp->getGameLoaderGameVar()->getSubVarByName("SC_28"));
-
+
g_fp->initArcadeKeys("SC_28");
}
diff --git a/engines/fullpipe/scenes/scene29.cpp b/engines/fullpipe/scenes/scene29.cpp
index 8f82e99ad1..222a541554 100644
--- a/engines/fullpipe/scenes/scene29.cpp
+++ b/engines/fullpipe/scenes/scene29.cpp
@@ -840,7 +840,7 @@ void sceneHandler29_shootersEscape() {
void sceneHandler29_manRideBack() {
g_vars->scene29_manX -= 2;
-
+
g_fp->_aniMan->setOXY(g_vars->scene29_manX, g_vars->scene29_manY);
}
diff --git a/engines/fullpipe/scenes/scene37.cpp b/engines/fullpipe/scenes/scene37.cpp
index 09da01f138..324d3ac92d 100644
--- a/engines/fullpipe/scenes/scene37.cpp
+++ b/engines/fullpipe/scenes/scene37.cpp
@@ -91,7 +91,7 @@ void scene37_initScene(Scene *sc) {
g_vars->scene37_rings.push_back(ring);
g_fp->setObjectState(sO_LeftPipe_37, g_fp->getObjectEnumState(sO_LeftPipe_37, sO_IsClosed));
-
+
Scene *oldsc = g_fp->_currentScene;
g_fp->_currentScene = sc;
diff --git a/engines/fullpipe/sound.cpp b/engines/fullpipe/sound.cpp
index a4ca06f489..230d6c39a9 100644
--- a/engines/fullpipe/sound.cpp
+++ b/engines/fullpipe/sound.cpp
@@ -62,7 +62,7 @@ bool SoundList::load(MfcArchive &file, char *fname) {
}
return true;
-
+
}
bool SoundList::loadFile(const char *fname, char *libname) {
diff --git a/engines/fullpipe/statics.cpp b/engines/fullpipe/statics.cpp
index 717de84925..880c2eb0df 100644
--- a/engines/fullpipe/statics.cpp
+++ b/engines/fullpipe/statics.cpp
@@ -246,7 +246,7 @@ bool StaticANIObject::load(MfcArchive &file) {
void StaticANIObject::setOXY(int x, int y) {
_ox = x;
_oy = y;
-
+
if (_movement)
_movement->setOXY(x, y);
}
@@ -713,7 +713,7 @@ void StaticANIObject::setSpeed(int speed) {
void StaticANIObject::setAlpha(int alpha) {
for (uint i = 0; i < _movements.size(); i++)
_movements[i]->setAlpha(alpha);
-
+
for (uint i = 0; i < _staticsList.size(); i++)
_staticsList[i]->setAlpha(alpha);
}
@@ -1813,7 +1813,7 @@ void Movement::initStatics(StaticANIObject *ani) {
_staticsObj2 = ani->addReverseStatics(_currMovement->_staticsObj2);
_staticsObj1 = ani->addReverseStatics(_currMovement->_staticsObj1);
-
+
_mx = _currMovement->_mx;
_my = _currMovement->_my;
@@ -2279,7 +2279,7 @@ bool StaticPhase::load(MfcArchive &file) {
_initialCountdown = file.readUint16LE();
_field_6A = file.readUint16LE();
-
+
if (g_fp->_gameProjectVersion >= 12) {
_exCommand = (ExCommand *)file.readClass();
diff --git a/engines/gob/POTFILES b/engines/gob/POTFILES
index 9a512469dd..ca7aa14177 100644
--- a/engines/gob/POTFILES
+++ b/engines/gob/POTFILES
@@ -1,3 +1,5 @@
engines/gob/inter_playtoons.cpp
engines/gob/inter_v2.cpp
engines/gob/inter_v5.cpp
+engines/gob/inter_geisha.cpp
+
diff --git a/engines/gob/inter_v1.cpp b/engines/gob/inter_v1.cpp
index 40134bbf17..676564a9fb 100644
--- a/engines/gob/inter_v1.cpp
+++ b/engines/gob/inter_v1.cpp
@@ -1124,8 +1124,6 @@ void Inter_v1::o1_palLoad(OpFuncParams &params) {
_vm->_draw->_vgaPalette[i].green = _vm->_game->_script->readByte();
_vm->_draw->_vgaPalette[i].blue = _vm->_game->_script->readByte();
}
-
- memcpy(_vm->_draw->_vgaPalette, _vm->_draw->_vgaPalette, 16 * 3);
break;
case 53:
diff --git a/engines/groovie/graphics.cpp b/engines/groovie/graphics.cpp
index b85277fac7..e0c198f377 100644
--- a/engines/groovie/graphics.cpp
+++ b/engines/groovie/graphics.cpp
@@ -63,7 +63,7 @@ void GraphicsMan::update() {
// Clear the buffer when ending the fade out
if (_fading == 2)
- _foreground.fillRect(Common::Rect(640, 320), 0);
+ _foreground.fillRect(Common::Rect(640, _foreground.h), 0);
}
}
@@ -74,6 +74,22 @@ void GraphicsMan::update() {
}
}
+void GraphicsMan::switchToFullScreen(bool fullScreen) {
+ _foreground.free();
+ _background.free();
+
+ if (fullScreen) {
+ _foreground.create(640, 480, _vm->_pixelFormat);
+ _background.create(640, 480, _vm->_pixelFormat);
+ } else {
+ _vm->_system->fillScreen(0);
+ _foreground.create(640, 320, _vm->_pixelFormat);
+ _background.create(640, 320, _vm->_pixelFormat);
+ }
+
+ _changed = true;
+}
+
void GraphicsMan::change() {
_changed = true;
}
@@ -84,7 +100,7 @@ void GraphicsMan::mergeFgAndBg() {
countf = (byte *)_foreground.getPixels();
countb = (byte *)_background.getPixels();
- for (i = 640 * 320; i; i--) {
+ for (i = 640 * _foreground.h; i; i--) {
if (255 == *(countf)) {
*(countf) = *(countb);
}
@@ -94,7 +110,10 @@ void GraphicsMan::mergeFgAndBg() {
}
void GraphicsMan::updateScreen(Graphics::Surface *source) {
- _vm->_system->copyRectToScreen(source->getPixels(), 640, 0, 80, 640, 320);
+ if (!isFullScreen())
+ _vm->_system->copyRectToScreen(source->getPixels(), source->pitch, 0, 80, 640, 320);
+ else
+ _vm->_system->copyRectToScreen(source->getPixels(), source->pitch, 0, 0, 640, 480);
change();
}
diff --git a/engines/groovie/graphics.h b/engines/groovie/graphics.h
index 72ab01deb6..69934f9d68 100644
--- a/engines/groovie/graphics.h
+++ b/engines/groovie/graphics.h
@@ -38,6 +38,8 @@ public:
void update();
void change();
void mergeFgAndBg();
+ void switchToFullScreen(bool fullScreen);
+ bool isFullScreen() { return (_foreground.h == 480); }
void updateScreen(Graphics::Surface *source);
Graphics::Surface _foreground; // The main surface that most things are drawn to
Graphics::Surface _background; // Used occasionally, mostly (only?) in puzzles
diff --git a/engines/groovie/roq.cpp b/engines/groovie/roq.cpp
index 379fcabc07..f14cacd6b8 100644
--- a/engines/groovie/roq.cpp
+++ b/engines/groovie/roq.cpp
@@ -28,6 +28,7 @@
#include "groovie/groovie.h"
#include "common/debug.h"
+#include "common/debug-channels.h"
#include "common/rect.h"
#include "common/substream.h"
#include "common/textconsole.h"
@@ -46,6 +47,7 @@ namespace Groovie {
ROQPlayer::ROQPlayer(GroovieEngine *vm) :
VideoPlayer(vm), _codingTypeCount(0),
+ _fg(&_vm->_graphicsMan->_foreground),
_bg(&_vm->_graphicsMan->_background),
_firstFrame(true) {
@@ -63,6 +65,22 @@ ROQPlayer::~ROQPlayer() {
}
uint16 ROQPlayer::loadInternal() {
+ if (DebugMan.isDebugChannelEnabled(kDebugVideo)) {
+ int8 i;
+ debugN(1, "Groovie::ROQ: New ROQ: bitflags are ");
+ for (i = 15; i >= 0; i--) {
+ debugN(1, "%d", _flags & (1 << i)? 1 : 0);
+ if (i % 4 == 0) {
+ debugN(1, " ");
+ }
+ }
+ debug(1, " <- 0 ");
+ }
+
+ // Flags:
+ // - 2 For overlay videos, show the whole video
+ _flagTwo = ((_flags & (1 << 2)) != 0);
+
// Begin reading the file
debugC(1, kDebugVideo, "Groovie::ROQ: Loading video");
@@ -106,13 +124,23 @@ uint16 ROQPlayer::loadInternal() {
}
void ROQPlayer::buildShowBuf() {
+ if (_alpha)
+ _fg->copyFrom(*_bg);
+
for (int line = 0; line < _bg->h; line++) {
- uint32 *out = (uint32 *)_bg->getBasePtr(0, line);
+ uint32 *out = _alpha ? (uint32 *)_fg->getBasePtr(0, line) : (uint32 *)_bg->getBasePtr(0, line);
uint32 *in = (uint32 *)_currBuf->getBasePtr(0, line / _scaleY);
for (int x = 0; x < _bg->w; x++) {
- // Copy a pixel
- *out++ = *in;
+ // Copy a pixel, checking the alpha channel first
+ if (_alpha && !(*in & 0xFF))
+ out++;
+ else if (_fg->h == 480 && *in == _vm->_pixelFormat.RGBToColor(255, 255, 255))
+ // Handle transparency in Gamepad videos
+ // TODO: For now, we detect these videos by checking for full screen
+ out++;
+ else
+ *out++ = *in;
// Skip to the next pixel
if (!(x % _scaleX))
@@ -145,19 +173,27 @@ bool ROQPlayer::playFrameInternal() {
}
// Wait until the current frame can be shown
- waitFrame();
+ // Don't wait if we're just showing one frame
+ if (!playFirstFrame())
+ waitFrame();
if (_dirty) {
// Update the screen
- _syst->copyRectToScreen(_bg->getPixels(), _bg->pitch, 0, (_syst->getHeight() - _bg->h) / 2, _bg->w, _bg->h);
+ void *src = (_alpha) ? _fg->getPixels() : _bg->getPixels();
+ _syst->copyRectToScreen(src, _bg->pitch, 0, (_syst->getHeight() - _bg->h) / 2, _bg->w, _bg->h);
_syst->updateScreen();
+ // For overlay videos, set the background buffer when the video ends
+ if (_alpha && (!_flagTwo || (_flagTwo && _file->eos())))
+ _bg->copyFrom(*_fg);
+
// Clear the dirty flag
_dirty = false;
}
- // Return whether the video has ended
- return _file->eos();
+ // Report the end of the video if we reached the end of the file or if we
+ // just wanted to play one frame.
+ return _file->eos() || playFirstFrame();
}
bool ROQPlayer::readBlockHeader(ROQBlockHeader &blockHeader) {
@@ -277,9 +313,17 @@ bool ROQPlayer::processBlockInfo(ROQBlockHeader &blockHeader) {
_prevBuf->create(width, height, _vm->_pixelFormat);
}
+ // Switch from/to fullscreen, if needed
+ if (_bg->h != 480 && height == 480)
+ _vm->_graphicsMan->switchToFullScreen(true);
+ else if (_bg->h == 480 && height != 480)
+ _vm->_graphicsMan->switchToFullScreen(false);
+
// Clear the buffers with black
- _currBuf->fillRect(Common::Rect(width, height), _vm->_pixelFormat.RGBToColor(0, 0, 0));
- _prevBuf->fillRect(Common::Rect(width, height), _vm->_pixelFormat.RGBToColor(0, 0, 0));
+ if (!_alpha) {
+ _currBuf->fillRect(Common::Rect(width, height), _vm->_pixelFormat.RGBToColor(0, 0, 0));
+ _prevBuf->fillRect(Common::Rect(width, height), _vm->_pixelFormat.RGBToColor(0, 0, 0));
+ }
return true;
}
@@ -448,7 +492,7 @@ bool ROQPlayer::processBlockSoundMono(ROQBlockHeader &blockHeader) {
}
// Initialize the audio stream if needed
- if (!_audioStream) {
+ if (!_audioStream && !playFirstFrame()) {
_audioStream = Audio::makeQueuingAudioStream(22050, false);
Audio::SoundHandle sound_handle;
g_system->getMixer()->playStream(Audio::Mixer::kPlainSoundType, &sound_handle, _audioStream);
@@ -477,7 +521,10 @@ bool ROQPlayer::processBlockSoundMono(ROQBlockHeader &blockHeader) {
#ifdef SCUMM_LITTLE_ENDIAN
flags |= Audio::FLAG_LITTLE_ENDIAN;
#endif
- _audioStream->queueBuffer((byte *)buffer, blockHeader.size * 2, DisposeAfterUse::YES, flags);
+ if (!playFirstFrame())
+ _audioStream->queueBuffer((byte *)buffer, blockHeader.size * 2, DisposeAfterUse::YES, flags);
+ else
+ free(buffer);
return true;
}
@@ -491,7 +538,7 @@ bool ROQPlayer::processBlockSoundStereo(ROQBlockHeader &blockHeader) {
}
// Initialize the audio stream if needed
- if (!_audioStream) {
+ if (!_audioStream && !playFirstFrame()) {
_audioStream = Audio::makeQueuingAudioStream(22050, true);
Audio::SoundHandle sound_handle;
g_system->getMixer()->playStream(Audio::Mixer::kPlainSoundType, &sound_handle, _audioStream);
@@ -533,7 +580,10 @@ bool ROQPlayer::processBlockSoundStereo(ROQBlockHeader &blockHeader) {
#ifdef SCUMM_LITTLE_ENDIAN
flags |= Audio::FLAG_LITTLE_ENDIAN;
#endif
- _audioStream->queueBuffer((byte *)buffer, blockHeader.size * 2, DisposeAfterUse::YES, flags);
+ if (!playFirstFrame())
+ _audioStream->queueBuffer((byte *)buffer, blockHeader.size * 2, DisposeAfterUse::YES, flags);
+ else
+ free(buffer);
return true;
}
diff --git a/engines/groovie/roq.h b/engines/groovie/roq.h
index 7e7d38580e..ce1a3a2d58 100644
--- a/engines/groovie/roq.h
+++ b/engines/groovie/roq.h
@@ -57,6 +57,7 @@ private:
bool processBlockSoundMono(ROQBlockHeader &blockHeader);
bool processBlockSoundStereo(ROQBlockHeader &blockHeader);
bool processBlockAudioContainer(ROQBlockHeader &blockHeader);
+ bool playFirstFrame() { return _alpha && !_flagTwo; }
void paint2(byte i, int destx, int desty);
void paint4(byte i, int destx, int desty);
@@ -74,8 +75,11 @@ private:
uint32 _codebook2[256 * 4];
byte _codebook4[256 * 4];
+ // Flags
+ bool _flagTwo;
+
// Buffers
- Graphics::Surface *_bg;
+ Graphics::Surface *_fg, *_bg;
Graphics::Surface *_currBuf, *_prevBuf;
void buildShowBuf();
byte _scaleX, _scaleY;
diff --git a/engines/groovie/script.cpp b/engines/groovie/script.cpp
index 7625151082..eef97b6ff9 100644
--- a/engines/groovie/script.cpp
+++ b/engines/groovie/script.cpp
@@ -179,12 +179,20 @@ void Script::directGameLoad(int slot) {
// TODO: Return to the main script, likely reusing most of o_returnscript()
- // HACK: We set variable 0x19 to the slot to load, and set the current
- // instruction to the one that actually loads the saved game specified
- // in that variable. This will change in other versions of the game and
- // in other games.
- setVariable(0x19, slot);
- _currentInstruction = 0x287;
+ // HACK: We set the slot to load in the appropriate variable, and set the
+ // current instruction to the one that actually loads the saved game
+ // specified in that variable. This differs depending on the game and its
+ // version.
+ if (_version == kGroovieT7G) {
+ // 7th Guest
+ setVariable(0x19, slot);
+ _currentInstruction = 0x287;
+ } else {
+ // 11th Hour
+ setVariable(0xF, slot);
+ // FIXME: This bypasses a lot of the game's initialization procedure
+ _currentInstruction = 0xE78E;
+ }
// TODO: We'll probably need to start by running the beginning of the
// script to let it do the soundcard initialization and then do the
@@ -350,9 +358,10 @@ bool Script::hotspot(Common::Rect rect, uint16 address, uint8 cursor) {
// Show hotspots when debugging
if (DebugMan.isDebugChannelEnabled(kDebugHotspots)) {
- rect.translate(0, -80);
+ if (!_vm->_graphicsMan->isFullScreen())
+ rect.translate(0, -80);
_vm->_graphicsMan->_foreground.frameRect(rect, 250);
- _vm->_system->copyRectToScreen(_vm->_graphicsMan->_foreground.getPixels(), _vm->_graphicsMan->_foreground.pitch, 0, 80, 640, 320);
+ _vm->_graphicsMan->updateScreen(&_vm->_graphicsMan->_foreground);
_vm->_system->updateScreen();
}
@@ -962,7 +971,7 @@ void Script::o_strcmpnejmp_var() { // 0x21
void Script::o_copybgtofg() { // 0x22
debugC(1, kDebugScript, "COPY_BG_TO_FG");
- memcpy(_vm->_graphicsMan->_foreground.getPixels(), _vm->_graphicsMan->_background.getPixels(), 640 * 320);
+ memcpy(_vm->_graphicsMan->_foreground.getPixels(), _vm->_graphicsMan->_background.getPixels(), 640 * _vm->_graphicsMan->_foreground.h);
}
void Script::o_strcmpeqjmp() { // 0x23
@@ -1198,6 +1207,7 @@ void Script::o_copyrecttobg() { // 0x37
uint16 top = readScript16bits();
uint16 right = readScript16bits();
uint16 bottom = readScript16bits();
+ uint16 baseTop = (!_vm->_graphicsMan->isFullScreen()) ? 80 : 0;
// Sanity checks to prevent bad pointer access crashes
if (left > right) {
@@ -1216,9 +1226,9 @@ void Script::o_copyrecttobg() { // 0x37
bottom = top;
top = j;
}
- if (top < 80) {
- warning("COPYRECT top < 80... clamping");
- top = 80;
+ if (top < baseTop) {
+ warning("COPYRECT top < baseTop... clamping");
+ top = baseTop;
}
if (top >= 480) {
warning("COPYRECT top >= 480... clamping");
@@ -1243,13 +1253,13 @@ void Script::o_copyrecttobg() { // 0x37
debugC(1, kDebugScript, "COPYRECT((%d,%d)->(%d,%d))", left, top, right, bottom);
- fg = (byte *)_vm->_graphicsMan->_foreground.getBasePtr(left, top - 80);
- bg = (byte *)_vm->_graphicsMan->_background.getBasePtr(left, top - 80);
+ fg = (byte *)_vm->_graphicsMan->_foreground.getBasePtr(left, top - baseTop);
+ bg = (byte *)_vm->_graphicsMan->_background.getBasePtr(left, top - baseTop);
for (i = 0; i < height; i++) {
memcpy(bg + offset, fg + offset, width);
offset += 640;
}
- _vm->_system->copyRectToScreen(_vm->_graphicsMan->_background.getBasePtr(left, top - 80), 640, left, top, width, height);
+ _vm->_system->copyRectToScreen(_vm->_graphicsMan->_background.getBasePtr(left, top - baseTop), 640, left, top, width, height);
_vm->_graphicsMan->change();
}
@@ -1595,8 +1605,7 @@ void Script::o_hotspot_outrect() {
bool contained = rect.contains(mousepos);
if (!contained) {
- error("hotspot-outrect unimplemented");
- // TODO: what to do with address?
+ _currentInstruction = address;
}
}
@@ -1670,15 +1679,29 @@ void Script::o2_vdxtransition() {
void Script::o2_copyscreentobg() {
uint16 val = readScript16bits();
+ // TODO: Parameter
+ if (val)
+ warning("o2_copyscreentobg: Param is %d", val);
+
+ Graphics::Surface *screen = _vm->_system->lockScreen();
+ _vm->_graphicsMan->_background.copyFrom(screen->getSubArea(Common::Rect(0, 80, 640, 320)));
+ _vm->_system->unlockScreen();
+
debugC(1, kDebugScript, "CopyScreenToBG3: 0x%04X", val);
- error("Unimplemented Opcode 0x4F");
}
void Script::o2_copybgtoscreen() {
uint16 val = readScript16bits();
+ // TODO: Parameter
+ if (val)
+ warning("o2_copybgtoscreen: Param is %d", val);
+
+ Graphics::Surface *screen = _vm->_system->lockScreen();
+ _vm->_graphicsMan->_background.copyRectToSurface(*screen, 0, 80, Common::Rect(0, 0, 640, 320 - 80));
+ _vm->_system->unlockScreen();
+
debugC(1, kDebugScript, "CopyBG3ToScreen: 0x%04X", val);
- error("Unimplemented Opcode 0x50");
}
void Script::o2_setvideoskip() {
@@ -1686,6 +1709,12 @@ void Script::o2_setvideoskip() {
debugC(1, kDebugScript, "SetVideoSkip (0x%04X)", _videoSkipAddress);
}
+void Script::o2_stub42() {
+ uint8 arg = readScript8bits();
+ // TODO: Switch with 5 cases (0 - 5). Anything above 5 is a NOP
+ debugC(1, kDebugScript, "STUB42 (0x%02X)", arg);
+}
+
void Script::o2_stub52() {
uint8 arg = readScript8bits();
debugC(1, kDebugScript, "STUB52 (0x%02X)", arg);
@@ -1859,7 +1888,7 @@ Script::OpcodeFunc Script::_opcodesV2[NUM_OPCODES] = {
&Script::o_loadscript,
&Script::o_setvideoorigin, // 0x40
&Script::o_sub,
- &Script::o_cellmove,
+ &Script::o2_stub42,
&Script::o_returnscript,
&Script::o_sethotspotright, // 0x44
&Script::o_sethotspotleft,
diff --git a/engines/groovie/script.h b/engines/groovie/script.h
index 35e52593de..a9f6143509 100644
--- a/engines/groovie/script.h
+++ b/engines/groovie/script.h
@@ -238,6 +238,7 @@ private:
void o2_setvideoskip();
void o2_copyscreentobg();
void o2_copybgtoscreen();
+ void o2_stub42();
void o2_stub52();
void o2_setscriptend();
};
diff --git a/engines/hopkins/POTFILES b/engines/hopkins/POTFILES
new file mode 100644
index 0000000000..1ea7d5111b
--- /dev/null
+++ b/engines/hopkins/POTFILES
@@ -0,0 +1,2 @@
+engines/hopkins/detection.cpp
+
diff --git a/engines/hopkins/computer.cpp b/engines/hopkins/computer.cpp
index 84d5c631c7..18b16cb4c8 100644
--- a/engines/hopkins/computer.cpp
+++ b/engines/hopkins/computer.cpp
@@ -883,7 +883,7 @@ void ComputerManager::getScoreName() {
_vm->_graphicsMan->setColorPercentage(254, 0, 0, 0);
byte *ptr = _vm->_fileIO->loadFile("ALPHA.SPR");
_vm->_graphicsMan->fadeInBreakout();
-
+
// Figure out the line to put the new high score on
int scoreLine = 0;
while (scoreLine < 5 && _breakoutScore < atol(_score[scoreLine]._score.c_str()))
diff --git a/engines/hopkins/files.cpp b/engines/hopkins/files.cpp
index 6620f2878c..3100ed6cdc 100644
--- a/engines/hopkins/files.cpp
+++ b/engines/hopkins/files.cpp
@@ -74,7 +74,7 @@ int FileManager::readStream(Common::ReadStream &stream, void *buf, size_t nbytes
* It's now using the config manager and a per-engine GUI option.
*/
void FileManager::initCensorship() {
- _vm->_globals->_censorshipFl = ConfMan.getBool("enable_gore");
+ _vm->_globals->_censorshipFl = !ConfMan.getBool("enable_gore");
}
/**
diff --git a/engines/hopkins/sound.cpp b/engines/hopkins/sound.cpp
index 773c714899..6660233740 100644
--- a/engines/hopkins/sound.cpp
+++ b/engines/hopkins/sound.cpp
@@ -261,9 +261,9 @@ void SoundManager::loadAnimSound() {
}
}
-void SoundManager::playAnimSound(int soundNumber) {
+void SoundManager::playAnimSound(int animFrame) {
if (!_vm->_globals->_censorshipFl && _specialSoundNum == 2) {
- switch (soundNumber) {
+ switch (animFrame) {
case 20:
playSample(5);
break;
@@ -273,44 +273,59 @@ void SoundManager::playAnimSound(int soundNumber) {
playSample(1);
break;
case 75:
- playSample(2);
+ // This removes the sound of the gun played while the guard is being shot, as this part of the scene has been
+ // removed in the Polish version of the game
+ if (_vm->getLanguage() != Common::PL_POL)
+ playSample(2);
+ break;
+ case 95:
+ // This fixes an original bug in the Polish version of the game, which was literally butchered for some reason
+ if (_vm->getLanguage() == Common::PL_POL)
+ playSample(3);
break;
case 109:
- playSample(3);
+ if (_vm->getLanguage() != Common::PL_POL)
+ playSample(3);
+ break;
+ case 108:
+ // This fixes an original bug in the Polish version of the game, which was literally butchered for some reason
+ if (_vm->getLanguage() == Common::PL_POL)
+ playSample(4);
break;
case 122:
- playSample(4);
+ if (_vm->getLanguage() != Common::PL_POL)
+ playSample(4);
break;
}
- } else if (_specialSoundNum == 1 && soundNumber == 17)
+ } else if (_specialSoundNum == 1 && animFrame == 17)
playSoundFile("SOUND42.WAV");
- else if (_specialSoundNum == 5 && soundNumber == 19)
+ else if (_specialSoundNum == 5 && animFrame == 19)
playWav(1);
- else if (_specialSoundNum == 14 && soundNumber == 625)
+ else if (_specialSoundNum == 14 && animFrame == 625)
playWav(1);
- else if (_specialSoundNum == 16 && soundNumber == 25)
+ else if (_specialSoundNum == 16 && animFrame == 25)
playWav(1);
else if (_specialSoundNum == 17) {
- if (soundNumber == 6)
+ if (animFrame == 6)
playSample(1);
- else if (soundNumber == 14)
+ else if (animFrame == 14)
playSample(2);
- else if (soundNumber == 67)
+ else if (animFrame == 67)
playSample(3);
- } else if (_specialSoundNum == 198 && soundNumber == 15)
+ } else if (_specialSoundNum == 198 && animFrame == 15)
playWav(1);
- else if (_specialSoundNum == 199 && soundNumber == 72)
+ else if (_specialSoundNum == 199 && animFrame == 72)
playWav(1);
- else if (_specialSoundNum == 208 && soundNumber == 40)
+ else if (_specialSoundNum == 208 && animFrame == 40)
playWav(1);
- else if (_specialSoundNum == 210 && soundNumber == 2)
+ else if (_specialSoundNum == 210 && animFrame == 2)
playWav(1);
- else if (_specialSoundNum == 211 && soundNumber == 22)
+ else if (_specialSoundNum == 211 && animFrame == 22)
playWav(1);
else if (_specialSoundNum == 229) {
- if (soundNumber == 15)
+ if (animFrame == 15)
playWav(1);
- else if (soundNumber == 91)
+ else if (animFrame == 91)
playWav(2);
}
}
diff --git a/engines/hopkins/sound.h b/engines/hopkins/sound.h
index 97cdcdc1dd..1fb4f9ae71 100644
--- a/engines/hopkins/sound.h
+++ b/engines/hopkins/sound.h
@@ -116,7 +116,7 @@ public:
~SoundManager();
void loadAnimSound();
- void playAnimSound(int soundNumber);
+ void playAnimSound(int animFrame);
void loadSample(int wavIndex, const Common::String &file);
void playSample(int wavIndex, int voiceMode = 9);
diff --git a/engines/hopkins/talk.cpp b/engines/hopkins/talk.cpp
index df7b26c82c..00c4ab0332 100644
--- a/engines/hopkins/talk.cpp
+++ b/engines/hopkins/talk.cpp
@@ -68,7 +68,7 @@ void TalkManager::startAnimatedCharacterDialogue(const Common::String &filename)
getStringFromBuffer(40, spriteFilename, (const char *)_characterBuffer);
getStringFromBuffer(0, _questionsFilename, (const char *)_characterBuffer);
getStringFromBuffer(20, _answersFilename, (const char *)_characterBuffer);
-
+
switch (_vm->_globals->_language) {
case LANG_FR:
_answersFilename = _questionsFilename = "RUE.TXT";
diff --git a/engines/kyra/POTFILES b/engines/kyra/POTFILES
index 16888e2c5a..e5b380e52e 100644
--- a/engines/kyra/POTFILES
+++ b/engines/kyra/POTFILES
@@ -1,3 +1,4 @@
engines/kyra/detection.cpp
engines/kyra/lol.cpp
engines/kyra/sound_midi.cpp
+engines/kyra/saveload_eob.cpp
diff --git a/engines/kyra/detection_tables.h b/engines/kyra/detection_tables.h
index 1ada9a87ba..2ee0262ef2 100644
--- a/engines/kyra/detection_tables.h
+++ b/engines/kyra/detection_tables.h
@@ -1568,6 +1568,22 @@ const KYRAGameDescription adGameDescs[] = {
EOB_FLAGS
},
+ { // Italian fan translation
+ {
+ "eob",
+ 0,
+ {
+ { "EOBDATA3.PAK", 0, "3ed915ab5b94d60dbfe1b55379889c51", -1 },
+ { 0, 0, 0, 0 }
+ },
+ Common::IT_ITA,
+ Common::kPlatformDOS,
+ ADGF_TESTING,
+ GUIO7(GUIO_NOSPEECH, GUIO_MIDIADLIB, GUIO_MIDIPCSPK, GUIO_RENDERVGA, GUIO_RENDEREGA, GUIO_RENDERCGA, GAMEOPTION_EOB_HPGRAPHS)
+ },
+ EOB_FLAGS
+ },
+
{
{
"eob2",
diff --git a/engines/kyra/items_lol.cpp b/engines/kyra/items_lol.cpp
index f2a9637dfe..e1f864ddd2 100644
--- a/engines/kyra/items_lol.cpp
+++ b/engines/kyra/items_lol.cpp
@@ -265,7 +265,7 @@ bool LoLEngine::addItemToInventory(Item itemIndex) {
gui_drawInventory();
}
- assert(pos > 0 && pos < 48);
+ assert(pos >= 0 && pos < 48);
_inventory[pos] = itemIndex;
gui_drawInventory();
diff --git a/engines/kyra/sound_adlib.cpp b/engines/kyra/sound_adlib.cpp
index f950f9d5aa..89ee41e859 100644
--- a/engines/kyra/sound_adlib.cpp
+++ b/engines/kyra/sound_adlib.cpp
@@ -61,7 +61,7 @@ public:
~AdLibDriver();
void initDriver();
- void setSoundData(uint8 *data);
+ void setSoundData(uint8 *data, uint32 size);
void queueTrack(int track, int volume);
bool isChannelPlaying(int channel) const;
void stopAllChannels();
@@ -130,13 +130,13 @@ private:
struct Channel {
bool lock; // New to ScummVM
uint8 opExtraLevel2;
- uint8 *dataptr;
+ const uint8 *dataptr;
uint8 duration;
uint8 repeatCounter;
int8 baseOctave;
uint8 priority;
uint8 dataptrStackPos;
- uint8 *dataptrStack[4];
+ const uint8 *dataptrStack[4];
int8 baseNote;
uint8 unk29;
uint8 unk31;
@@ -194,7 +194,7 @@ private:
void setupDuration(uint8 duration, Channel &channel);
void setupNote(uint8 rawNote, Channel &channel, bool flag = false);
- void setupInstrument(uint8 regOffset, uint8 *dataptr, Channel &channel);
+ void setupInstrument(uint8 regOffset, const uint8 *dataptr, Channel &channel);
void noteOn(Channel &channel);
void adjustVolume(Channel &channel);
@@ -216,14 +216,24 @@ private:
// * One for instruments, starting at offset 500.
uint8 *getProgram(int progId) {
- uint16 offset = READ_LE_UINT16(_soundData + 2 * progId);
- //TODO: Check in LoL CD AdLib driver
- if (offset == 0xFFFF)
- return 0;
- return _soundData + READ_LE_UINT16(_soundData + 2 * progId);
+ const uint16 offset = READ_LE_UINT16(_soundData + 2 * progId);
+
+ // In case an invalid offset is specified we return nullptr to
+ // indicate an error. 0xFFFF seems to indicate "this is not a valid
+ // program/instrument". However, 0 is also invalid because it points
+ // inside the offset table itself. We also ignore any offsets outside
+ // of the actual data size.
+ // The original does not contain any safety checks and will simply
+ // read outside of the valid sound data in case an invalid offset is
+ // encountered.
+ if (offset == 0 || offset >= _soundDataSize) {
+ return nullptr;
+ } else {
+ return _soundData + offset;
+ }
}
- uint8 *getInstrument(int instrumentId) {
+ const uint8 *getInstrument(int instrumentId) {
return getProgram(_numPrograms + instrumentId);
}
@@ -231,7 +241,7 @@ private:
void executePrograms();
struct ParserOpcode {
- typedef int (AdLibDriver::*POpcode)(uint8 *&dataptr, Channel &channel, uint8 value);
+ typedef int (AdLibDriver::*POpcode)(const uint8 *&dataptr, Channel &channel, uint8 value);
POpcode function;
const char *name;
};
@@ -240,61 +250,61 @@ private:
const ParserOpcode *_parserOpcodeTable;
int _parserOpcodeTableSize;
- int update_setRepeat(uint8 *&dataptr, Channel &channel, uint8 value);
- int update_checkRepeat(uint8 *&dataptr, Channel &channel, uint8 value);
- int update_setupProgram(uint8 *&dataptr, Channel &channel, uint8 value);
- int update_setNoteSpacing(uint8 *&dataptr, Channel &channel, uint8 value);
- int update_jump(uint8 *&dataptr, Channel &channel, uint8 value);
- int update_jumpToSubroutine(uint8 *&dataptr, Channel &channel, uint8 value);
- int update_returnFromSubroutine(uint8 *&dataptr, Channel &channel, uint8 value);
- int update_setBaseOctave(uint8 *&dataptr, Channel &channel, uint8 value);
- int update_stopChannel(uint8 *&dataptr, Channel &channel, uint8 value);
- int update_playRest(uint8 *&dataptr, Channel &channel, uint8 value);
- int update_writeAdLib(uint8 *&dataptr, Channel &channel, uint8 value);
- int update_setupNoteAndDuration(uint8 *&dataptr, Channel &channel, uint8 value);
- int update_setBaseNote(uint8 *&dataptr, Channel &channel, uint8 value);
- int update_setupSecondaryEffect1(uint8 *&dataptr, Channel &channel, uint8 value);
- int update_stopOtherChannel(uint8 *&dataptr, Channel &channel, uint8 value);
- int update_waitForEndOfProgram(uint8 *&dataptr, Channel &channel, uint8 value);
- int update_setupInstrument(uint8 *&dataptr, Channel &channel, uint8 value);
- int update_setupPrimaryEffect1(uint8 *&dataptr, Channel &channel, uint8 value);
- int update_removePrimaryEffect1(uint8 *&dataptr, Channel &channel, uint8 value);
- int update_setBaseFreq(uint8 *&dataptr, Channel &channel, uint8 value);
- int update_setupPrimaryEffect2(uint8 *&dataptr, Channel &channel, uint8 value);
- int update_setPriority(uint8 *&dataptr, Channel &channel, uint8 value);
- int updateCallback23(uint8 *&dataptr, Channel &channel, uint8 value);
- int updateCallback24(uint8 *&dataptr, Channel &channel, uint8 value);
- int update_setExtraLevel1(uint8 *&dataptr, Channel &channel, uint8 value);
- int update_setupDuration(uint8 *&dataptr, Channel &channel, uint8 value);
- int update_playNote(uint8 *&dataptr, Channel &channel, uint8 value);
- int update_setFractionalNoteSpacing(uint8 *&dataptr, Channel &channel, uint8 value);
- int update_setTempo(uint8 *&dataptr, Channel &channel, uint8 value);
- int update_removeSecondaryEffect1(uint8 *&dataptr, Channel &channel, uint8 value);
- int update_setChannelTempo(uint8 *&dataptr, Channel &channel, uint8 value);
- int update_setExtraLevel3(uint8 *&dataptr, Channel &channel, uint8 value);
- int update_setExtraLevel2(uint8 *&dataptr, Channel &channel, uint8 value);
- int update_changeExtraLevel2(uint8 *&dataptr, Channel &channel, uint8 value);
- int update_setAMDepth(uint8 *&dataptr, Channel &channel, uint8 value);
- int update_setVibratoDepth(uint8 *&dataptr, Channel &channel, uint8 value);
- int update_changeExtraLevel1(uint8 *&dataptr, Channel &channel, uint8 value);
- int updateCallback38(uint8 *&dataptr, Channel &channel, uint8 value);
- int updateCallback39(uint8 *&dataptr, Channel &channel, uint8 value);
- int update_removePrimaryEffect2(uint8 *&dataptr, Channel &channel, uint8 value);
- int update_pitchBend(uint8 *&dataptr, Channel &channel, uint8 value);
- int update_resetToGlobalTempo(uint8 *&dataptr, Channel &channel, uint8 value);
- int update_nop(uint8 *&dataptr, Channel &channel, uint8 value);
- int update_setDurationRandomness(uint8 *&dataptr, Channel &channel, uint8 value);
- int update_changeChannelTempo(uint8 *&dataptr, Channel &channel, uint8 value);
- int updateCallback46(uint8 *&dataptr, Channel &channel, uint8 value);
- int update_setupRhythmSection(uint8 *&dataptr, Channel &channel, uint8 value);
- int update_playRhythmSection(uint8 *&dataptr, Channel &channel, uint8 value);
- int update_removeRhythmSection(uint8 *&dataptr, Channel &channel, uint8 value);
- int updateCallback51(uint8 *&dataptr, Channel &channel, uint8 value);
- int updateCallback52(uint8 *&dataptr, Channel &channel, uint8 value);
- int updateCallback53(uint8 *&dataptr, Channel &channel, uint8 value);
- int update_setSoundTrigger(uint8 *&dataptr, Channel &channel, uint8 value);
- int update_setTempoReset(uint8 *&dataptr, Channel &channel, uint8 value);
- int updateCallback56(uint8 *&dataptr, Channel &channel, uint8 value);
+ int update_setRepeat(const uint8 *&dataptr, Channel &channel, uint8 value);
+ int update_checkRepeat(const uint8 *&dataptr, Channel &channel, uint8 value);
+ int update_setupProgram(const uint8 *&dataptr, Channel &channel, uint8 value);
+ int update_setNoteSpacing(const uint8 *&dataptr, Channel &channel, uint8 value);
+ int update_jump(const uint8 *&dataptr, Channel &channel, uint8 value);
+ int update_jumpToSubroutine(const uint8 *&dataptr, Channel &channel, uint8 value);
+ int update_returnFromSubroutine(const uint8 *&dataptr, Channel &channel, uint8 value);
+ int update_setBaseOctave(const uint8 *&dataptr, Channel &channel, uint8 value);
+ int update_stopChannel(const uint8 *&dataptr, Channel &channel, uint8 value);
+ int update_playRest(const uint8 *&dataptr, Channel &channel, uint8 value);
+ int update_writeAdLib(const uint8 *&dataptr, Channel &channel, uint8 value);
+ int update_setupNoteAndDuration(const uint8 *&dataptr, Channel &channel, uint8 value);
+ int update_setBaseNote(const uint8 *&dataptr, Channel &channel, uint8 value);
+ int update_setupSecondaryEffect1(const uint8 *&dataptr, Channel &channel, uint8 value);
+ int update_stopOtherChannel(const uint8 *&dataptr, Channel &channel, uint8 value);
+ int update_waitForEndOfProgram(const uint8 *&dataptr, Channel &channel, uint8 value);
+ int update_setupInstrument(const uint8 *&dataptr, Channel &channel, uint8 value);
+ int update_setupPrimaryEffect1(const uint8 *&dataptr, Channel &channel, uint8 value);
+ int update_removePrimaryEffect1(const uint8 *&dataptr, Channel &channel, uint8 value);
+ int update_setBaseFreq(const uint8 *&dataptr, Channel &channel, uint8 value);
+ int update_setupPrimaryEffect2(const uint8 *&dataptr, Channel &channel, uint8 value);
+ int update_setPriority(const uint8 *&dataptr, Channel &channel, uint8 value);
+ int updateCallback23(const uint8 *&dataptr, Channel &channel, uint8 value);
+ int updateCallback24(const uint8 *&dataptr, Channel &channel, uint8 value);
+ int update_setExtraLevel1(const uint8 *&dataptr, Channel &channel, uint8 value);
+ int update_setupDuration(const uint8 *&dataptr, Channel &channel, uint8 value);
+ int update_playNote(const uint8 *&dataptr, Channel &channel, uint8 value);
+ int update_setFractionalNoteSpacing(const uint8 *&dataptr, Channel &channel, uint8 value);
+ int update_setTempo(const uint8 *&dataptr, Channel &channel, uint8 value);
+ int update_removeSecondaryEffect1(const uint8 *&dataptr, Channel &channel, uint8 value);
+ int update_setChannelTempo(const uint8 *&dataptr, Channel &channel, uint8 value);
+ int update_setExtraLevel3(const uint8 *&dataptr, Channel &channel, uint8 value);
+ int update_setExtraLevel2(const uint8 *&dataptr, Channel &channel, uint8 value);
+ int update_changeExtraLevel2(const uint8 *&dataptr, Channel &channel, uint8 value);
+ int update_setAMDepth(const uint8 *&dataptr, Channel &channel, uint8 value);
+ int update_setVibratoDepth(const uint8 *&dataptr, Channel &channel, uint8 value);
+ int update_changeExtraLevel1(const uint8 *&dataptr, Channel &channel, uint8 value);
+ int updateCallback38(const uint8 *&dataptr, Channel &channel, uint8 value);
+ int updateCallback39(const uint8 *&dataptr, Channel &channel, uint8 value);
+ int update_removePrimaryEffect2(const uint8 *&dataptr, Channel &channel, uint8 value);
+ int update_pitchBend(const uint8 *&dataptr, Channel &channel, uint8 value);
+ int update_resetToGlobalTempo(const uint8 *&dataptr, Channel &channel, uint8 value);
+ int update_nop(const uint8 *&dataptr, Channel &channel, uint8 value);
+ int update_setDurationRandomness(const uint8 *&dataptr, Channel &channel, uint8 value);
+ int update_changeChannelTempo(const uint8 *&dataptr, Channel &channel, uint8 value);
+ int updateCallback46(const uint8 *&dataptr, Channel &channel, uint8 value);
+ int update_setupRhythmSection(const uint8 *&dataptr, Channel &channel, uint8 value);
+ int update_playRhythmSection(const uint8 *&dataptr, Channel &channel, uint8 value);
+ int update_removeRhythmSection(const uint8 *&dataptr, Channel &channel, uint8 value);
+ int updateCallback51(const uint8 *&dataptr, Channel &channel, uint8 value);
+ int updateCallback52(const uint8 *&dataptr, Channel &channel, uint8 value);
+ int updateCallback53(const uint8 *&dataptr, Channel &channel, uint8 value);
+ int update_setSoundTrigger(const uint8 *&dataptr, Channel &channel, uint8 value);
+ int update_setTempoReset(const uint8 *&dataptr, Channel &channel, uint8 value);
+ int updateCallback56(const uint8 *&dataptr, Channel &channel, uint8 value);
private:
// These variables have not yet been named, but some of them are partly
// known nevertheless:
@@ -358,6 +368,7 @@ private:
FM_OPL *_adlib;
uint8 *_soundData;
+ uint32 _soundDataSize;
struct QueueEntry {
QueueEntry() : data(0), id(0), volume(0) {}
@@ -421,6 +432,7 @@ AdLibDriver::AdLibDriver(Audio::Mixer *mixer, int version) {
memset(_channels, 0, sizeof(_channels));
_soundData = 0;
+ _soundDataSize = 0;
_vibratoAndAMDepthBits = _curRegOffset = 0;
@@ -522,7 +534,7 @@ void AdLibDriver::initDriver() {
resetAdLibState();
}
-void AdLibDriver::setSoundData(uint8 *data) {
+void AdLibDriver::setSoundData(uint8 *data, uint32 size) {
Common::StackLock lock(_mutex);
// Drop all tracks that are still queued. These would point to the old
@@ -536,6 +548,7 @@ void AdLibDriver::setSoundData(uint8 *data) {
}
_soundData = data;
+ _soundDataSize = size;
}
void AdLibDriver::queueTrack(int track, int volume) {
@@ -791,7 +804,7 @@ void AdLibDriver::executePrograms() {
// This fixes a subtle music bug where the
// wrong music would play when getting the
// quill in Kyra 1.
- uint8 *dataptr = channel.dataptr;
+ const uint8 *dataptr = channel.dataptr;
while (dataptr) {
uint8 opcode = *dataptr++;
uint8 param = *dataptr++;
@@ -1030,7 +1043,7 @@ void AdLibDriver::setupNote(uint8 rawNote, Channel &channel, bool flag) {
writeOPL(0xB0 + _curChannel, channel.regBx);
}
-void AdLibDriver::setupInstrument(uint8 regOffset, uint8 *dataptr, Channel &channel) {
+void AdLibDriver::setupInstrument(uint8 regOffset, const uint8 *dataptr, Channel &channel) {
debugC(9, kDebugLevelSound, "setupInstrument(%d, %p, %lu)", regOffset, (const void *)dataptr, (long)(&channel - _channels));
if (_curChannel >= 9)
@@ -1340,12 +1353,12 @@ uint8 AdLibDriver::calculateOpLevel2(Channel &channel) {
// parser opcodes
-int AdLibDriver::update_setRepeat(uint8 *&dataptr, Channel &channel, uint8 value) {
+int AdLibDriver::update_setRepeat(const uint8 *&dataptr, Channel &channel, uint8 value) {
channel.repeatCounter = value;
return 0;
}
-int AdLibDriver::update_checkRepeat(uint8 *&dataptr, Channel &channel, uint8 value) {
+int AdLibDriver::update_checkRepeat(const uint8 *&dataptr, Channel &channel, uint8 value) {
++dataptr;
if (--channel.repeatCounter) {
int16 add = READ_LE_UINT16(dataptr - 2);
@@ -1354,14 +1367,23 @@ int AdLibDriver::update_checkRepeat(uint8 *&dataptr, Channel &channel, uint8 val
return 0;
}
-int AdLibDriver::update_setupProgram(uint8 *&dataptr, Channel &channel, uint8 value) {
+int AdLibDriver::update_setupProgram(const uint8 *&dataptr, Channel &channel, uint8 value) {
if (value == 0xFF)
return 0;
- uint8 *ptr = getProgram(value);
- //TODO: Check in LoL CD AdLib driver
- if (!ptr)
+ const uint8 *ptr = getProgram(value);
+
+ // In case we encounter an invalid program we simply ignore it and do
+ // nothing instead. The original did not care about invalid programs and
+ // simply tried to play them anyway... But to avoid crashes due we ingore
+ // them.
+ // This, for example, happens in the Lands of Lore intro when Scotia gets
+ // the ring in the intro.
+ if (!ptr) {
+ debugC(3, kDebugLevelSound, "AdLibDriver::update_setupProgram: Invalid program %d specified", value);
return 0;
+ }
+
uint8 chan = *ptr++;
uint8 priority = *ptr++;
@@ -1390,12 +1412,12 @@ int AdLibDriver::update_setupProgram(uint8 *&dataptr, Channel &channel, uint8 va
return 0;
}
-int AdLibDriver::update_setNoteSpacing(uint8 *&dataptr, Channel &channel, uint8 value) {
+int AdLibDriver::update_setNoteSpacing(const uint8 *&dataptr, Channel &channel, uint8 value) {
channel.spacing1 = value;
return 0;
}
-int AdLibDriver::update_jump(uint8 *&dataptr, Channel &channel, uint8 value) {
+int AdLibDriver::update_jump(const uint8 *&dataptr, Channel &channel, uint8 value) {
--dataptr;
int16 add = READ_LE_UINT16(dataptr); dataptr += 2;
if (_version == 1)
@@ -1407,7 +1429,7 @@ int AdLibDriver::update_jump(uint8 *&dataptr, Channel &channel, uint8 value) {
return 0;
}
-int AdLibDriver::update_jumpToSubroutine(uint8 *&dataptr, Channel &channel, uint8 value) {
+int AdLibDriver::update_jumpToSubroutine(const uint8 *&dataptr, Channel &channel, uint8 value) {
--dataptr;
int16 add = READ_LE_UINT16(dataptr); dataptr += 2;
channel.dataptrStack[channel.dataptrStackPos++] = dataptr;
@@ -1418,17 +1440,17 @@ int AdLibDriver::update_jumpToSubroutine(uint8 *&dataptr, Channel &channel, uint
return 0;
}
-int AdLibDriver::update_returnFromSubroutine(uint8 *&dataptr, Channel &channel, uint8 value) {
+int AdLibDriver::update_returnFromSubroutine(const uint8 *&dataptr, Channel &channel, uint8 value) {
dataptr = channel.dataptrStack[--channel.dataptrStackPos];
return 0;
}
-int AdLibDriver::update_setBaseOctave(uint8 *&dataptr, Channel &channel, uint8 value) {
+int AdLibDriver::update_setBaseOctave(const uint8 *&dataptr, Channel &channel, uint8 value) {
channel.baseOctave = value;
return 0;
}
-int AdLibDriver::update_stopChannel(uint8 *&dataptr, Channel &channel, uint8 value) {
+int AdLibDriver::update_stopChannel(const uint8 *&dataptr, Channel &channel, uint8 value) {
channel.priority = 0;
if (_curChannel != 9)
noteOff(channel);
@@ -1436,30 +1458,30 @@ int AdLibDriver::update_stopChannel(uint8 *&dataptr, Channel &channel, uint8 val
return 2;
}
-int AdLibDriver::update_playRest(uint8 *&dataptr, Channel &channel, uint8 value) {
+int AdLibDriver::update_playRest(const uint8 *&dataptr, Channel &channel, uint8 value) {
setupDuration(value, channel);
noteOff(channel);
return (value != 0);
}
-int AdLibDriver::update_writeAdLib(uint8 *&dataptr, Channel &channel, uint8 value) {
+int AdLibDriver::update_writeAdLib(const uint8 *&dataptr, Channel &channel, uint8 value) {
writeOPL(value, *dataptr++);
return 0;
}
-int AdLibDriver::update_setupNoteAndDuration(uint8 *&dataptr, Channel &channel, uint8 value) {
+int AdLibDriver::update_setupNoteAndDuration(const uint8 *&dataptr, Channel &channel, uint8 value) {
setupNote(value, channel);
value = *dataptr++;
setupDuration(value, channel);
return (value != 0);
}
-int AdLibDriver::update_setBaseNote(uint8 *&dataptr, Channel &channel, uint8 value) {
+int AdLibDriver::update_setBaseNote(const uint8 *&dataptr, Channel &channel, uint8 value) {
channel.baseNote = value;
return 0;
}
-int AdLibDriver::update_setupSecondaryEffect1(uint8 *&dataptr, Channel &channel, uint8 value) {
+int AdLibDriver::update_setupSecondaryEffect1(const uint8 *&dataptr, Channel &channel, uint8 value) {
channel.unk18 = value;
channel.unk19 = value;
channel.unk20 = channel.unk21 = *dataptr++;
@@ -1483,7 +1505,7 @@ int AdLibDriver::update_setupSecondaryEffect1(uint8 *&dataptr, Channel &channel,
return 0;
}
-int AdLibDriver::update_stopOtherChannel(uint8 *&dataptr, Channel &channel, uint8 value) {
+int AdLibDriver::update_stopOtherChannel(const uint8 *&dataptr, Channel &channel, uint8 value) {
Channel &channel2 = _channels[value];
channel2.duration = 0;
channel2.priority = 0;
@@ -1491,8 +1513,16 @@ int AdLibDriver::update_stopOtherChannel(uint8 *&dataptr, Channel &channel, uint
return 0;
}
-int AdLibDriver::update_waitForEndOfProgram(uint8 *&dataptr, Channel &channel, uint8 value) {
- uint8 *ptr = getProgram(value);
+int AdLibDriver::update_waitForEndOfProgram(const uint8 *&dataptr, Channel &channel, uint8 value) {
+ const uint8 *ptr = getProgram(value);
+
+ // Safety check in case an invalid program is specified. This would make
+ // getProgram return a nullptr and thus cause invalid memory reads.
+ if (!ptr) {
+ debugC(3, kDebugLevelSound, "AdLibDriver::update_waitForEndOfProgram: Invalid program %d specified", value);
+ return 0;
+ }
+
uint8 chan = *ptr;
if (!_channels[chan].dataptr)
@@ -1502,12 +1532,25 @@ int AdLibDriver::update_waitForEndOfProgram(uint8 *&dataptr, Channel &channel, u
return 2;
}
-int AdLibDriver::update_setupInstrument(uint8 *&dataptr, Channel &channel, uint8 value) {
- setupInstrument(_curRegOffset, getInstrument(value), channel);
+int AdLibDriver::update_setupInstrument(const uint8 *&dataptr, Channel &channel, uint8 value) {
+ const uint8 *instrument = getInstrument(value);
+
+ // We add a safety check to avoid setting up invalid instruments. This is
+ // not done in the original. However, to avoid crashes due to invalid
+ // memory reads we simply ignore the request.
+ // This happens, for example, in Hand of Fate when using the swampsnake
+ // potion on Zanthia to scare off the rat in the cave in the first chapter
+ // of the game.
+ if (!instrument) {
+ debugC(3, kDebugLevelSound, "AdLibDriver::update_setupInstrument: Invalid instrument %d specified", value);
+ return 0;
+ }
+
+ setupInstrument(_curRegOffset, instrument, channel);
return 0;
}
-int AdLibDriver::update_setupPrimaryEffect1(uint8 *&dataptr, Channel &channel, uint8 value) {
+int AdLibDriver::update_setupPrimaryEffect1(const uint8 *&dataptr, Channel &channel, uint8 value) {
channel.unk29 = value;
channel.unk30 = READ_BE_UINT16(dataptr);
dataptr += 2;
@@ -1516,19 +1559,19 @@ int AdLibDriver::update_setupPrimaryEffect1(uint8 *&dataptr, Channel &channel, u
return 0;
}
-int AdLibDriver::update_removePrimaryEffect1(uint8 *&dataptr, Channel &channel, uint8 value) {
+int AdLibDriver::update_removePrimaryEffect1(const uint8 *&dataptr, Channel &channel, uint8 value) {
--dataptr;
channel.primaryEffect = 0;
channel.unk30 = 0;
return 0;
}
-int AdLibDriver::update_setBaseFreq(uint8 *&dataptr, Channel &channel, uint8 value) {
+int AdLibDriver::update_setBaseFreq(const uint8 *&dataptr, Channel &channel, uint8 value) {
channel.baseFreq = value;
return 0;
}
-int AdLibDriver::update_setupPrimaryEffect2(uint8 *&dataptr, Channel &channel, uint8 value) {
+int AdLibDriver::update_setupPrimaryEffect2(const uint8 *&dataptr, Channel &channel, uint8 value) {
channel.unk32 = value;
channel.unk33 = *dataptr++;
uint8 temp = *dataptr++;
@@ -1539,12 +1582,12 @@ int AdLibDriver::update_setupPrimaryEffect2(uint8 *&dataptr, Channel &channel, u
return 0;
}
-int AdLibDriver::update_setPriority(uint8 *&dataptr, Channel &channel, uint8 value) {
+int AdLibDriver::update_setPriority(const uint8 *&dataptr, Channel &channel, uint8 value) {
channel.priority = value;
return 0;
}
-int AdLibDriver::updateCallback23(uint8 *&dataptr, Channel &channel, uint8 value) {
+int AdLibDriver::updateCallback23(const uint8 *&dataptr, Channel &channel, uint8 value) {
value >>= 1;
_unkValue1 = _unkValue2 = value;
_callbackTimer = 0xFF;
@@ -1552,7 +1595,7 @@ int AdLibDriver::updateCallback23(uint8 *&dataptr, Channel &channel, uint8 value
return 0;
}
-int AdLibDriver::updateCallback24(uint8 *&dataptr, Channel &channel, uint8 value) {
+int AdLibDriver::updateCallback24(const uint8 *&dataptr, Channel &channel, uint8 value) {
if (_unkValue5) {
if (_unkValue4 & value) {
_unkValue5 = 0;
@@ -1568,50 +1611,50 @@ int AdLibDriver::updateCallback24(uint8 *&dataptr, Channel &channel, uint8 value
return 2;
}
-int AdLibDriver::update_setExtraLevel1(uint8 *&dataptr, Channel &channel, uint8 value) {
+int AdLibDriver::update_setExtraLevel1(const uint8 *&dataptr, Channel &channel, uint8 value) {
channel.opExtraLevel1 = value;
adjustVolume(channel);
return 0;
}
-int AdLibDriver::update_setupDuration(uint8 *&dataptr, Channel &channel, uint8 value) {
+int AdLibDriver::update_setupDuration(const uint8 *&dataptr, Channel &channel, uint8 value) {
setupDuration(value, channel);
return (value != 0);
}
-int AdLibDriver::update_playNote(uint8 *&dataptr, Channel &channel, uint8 value) {
+int AdLibDriver::update_playNote(const uint8 *&dataptr, Channel &channel, uint8 value) {
setupDuration(value, channel);
noteOn(channel);
return (value != 0);
}
-int AdLibDriver::update_setFractionalNoteSpacing(uint8 *&dataptr, Channel &channel, uint8 value) {
+int AdLibDriver::update_setFractionalNoteSpacing(const uint8 *&dataptr, Channel &channel, uint8 value) {
channel.fractionalSpacing = value & 7;
return 0;
}
-int AdLibDriver::update_setTempo(uint8 *&dataptr, Channel &channel, uint8 value) {
+int AdLibDriver::update_setTempo(const uint8 *&dataptr, Channel &channel, uint8 value) {
_tempo = value;
return 0;
}
-int AdLibDriver::update_removeSecondaryEffect1(uint8 *&dataptr, Channel &channel, uint8 value) {
+int AdLibDriver::update_removeSecondaryEffect1(const uint8 *&dataptr, Channel &channel, uint8 value) {
--dataptr;
channel.secondaryEffect = 0;
return 0;
}
-int AdLibDriver::update_setChannelTempo(uint8 *&dataptr, Channel &channel, uint8 value) {
+int AdLibDriver::update_setChannelTempo(const uint8 *&dataptr, Channel &channel, uint8 value) {
channel.tempo = value;
return 0;
}
-int AdLibDriver::update_setExtraLevel3(uint8 *&dataptr, Channel &channel, uint8 value) {
+int AdLibDriver::update_setExtraLevel3(const uint8 *&dataptr, Channel &channel, uint8 value) {
channel.opExtraLevel3 = value;
return 0;
}
-int AdLibDriver::update_setExtraLevel2(uint8 *&dataptr, Channel &channel, uint8 value) {
+int AdLibDriver::update_setExtraLevel2(const uint8 *&dataptr, Channel &channel, uint8 value) {
int channelBackUp = _curChannel;
_curChannel = value;
@@ -1623,7 +1666,7 @@ int AdLibDriver::update_setExtraLevel2(uint8 *&dataptr, Channel &channel, uint8
return 0;
}
-int AdLibDriver::update_changeExtraLevel2(uint8 *&dataptr, Channel &channel, uint8 value) {
+int AdLibDriver::update_changeExtraLevel2(const uint8 *&dataptr, Channel &channel, uint8 value) {
int channelBackUp = _curChannel;
_curChannel = value;
@@ -1638,7 +1681,7 @@ int AdLibDriver::update_changeExtraLevel2(uint8 *&dataptr, Channel &channel, uin
// Apart from initializing to zero, these two functions are the only ones that
// modify _vibratoAndAMDepthBits.
-int AdLibDriver::update_setAMDepth(uint8 *&dataptr, Channel &channel, uint8 value) {
+int AdLibDriver::update_setAMDepth(const uint8 *&dataptr, Channel &channel, uint8 value) {
if (value & 1)
_vibratoAndAMDepthBits |= 0x80;
else
@@ -1648,7 +1691,7 @@ int AdLibDriver::update_setAMDepth(uint8 *&dataptr, Channel &channel, uint8 valu
return 0;
}
-int AdLibDriver::update_setVibratoDepth(uint8 *&dataptr, Channel &channel, uint8 value) {
+int AdLibDriver::update_setVibratoDepth(const uint8 *&dataptr, Channel &channel, uint8 value) {
if (value & 1)
_vibratoAndAMDepthBits |= 0x40;
else
@@ -1658,13 +1701,13 @@ int AdLibDriver::update_setVibratoDepth(uint8 *&dataptr, Channel &channel, uint8
return 0;
}
-int AdLibDriver::update_changeExtraLevel1(uint8 *&dataptr, Channel &channel, uint8 value) {
+int AdLibDriver::update_changeExtraLevel1(const uint8 *&dataptr, Channel &channel, uint8 value) {
channel.opExtraLevel1 += value;
adjustVolume(channel);
return 0;
}
-int AdLibDriver::updateCallback38(uint8 *&dataptr, Channel &channel, uint8 value) {
+int AdLibDriver::updateCallback38(const uint8 *&dataptr, Channel &channel, uint8 value) {
int channelBackUp = _curChannel;
_curChannel = value;
@@ -1693,7 +1736,7 @@ int AdLibDriver::updateCallback38(uint8 *&dataptr, Channel &channel, uint8 value
return 0;
}
-int AdLibDriver::updateCallback39(uint8 *&dataptr, Channel &channel, uint8 value) {
+int AdLibDriver::updateCallback39(const uint8 *&dataptr, Channel &channel, uint8 value) {
if (_curChannel >= 9)
return 0;
@@ -1714,35 +1757,35 @@ int AdLibDriver::updateCallback39(uint8 *&dataptr, Channel &channel, uint8 value
return 0;
}
-int AdLibDriver::update_removePrimaryEffect2(uint8 *&dataptr, Channel &channel, uint8 value) {
+int AdLibDriver::update_removePrimaryEffect2(const uint8 *&dataptr, Channel &channel, uint8 value) {
--dataptr;
channel.primaryEffect = 0;
return 0;
}
-int AdLibDriver::update_pitchBend(uint8 *&dataptr, Channel &channel, uint8 value) {
+int AdLibDriver::update_pitchBend(const uint8 *&dataptr, Channel &channel, uint8 value) {
channel.pitchBend = value;
setupNote(channel.rawNote, channel, true);
return 0;
}
-int AdLibDriver::update_resetToGlobalTempo(uint8 *&dataptr, Channel &channel, uint8 value) {
+int AdLibDriver::update_resetToGlobalTempo(const uint8 *&dataptr, Channel &channel, uint8 value) {
--dataptr;
channel.tempo = _tempo;
return 0;
}
-int AdLibDriver::update_nop(uint8 *&dataptr, Channel &channel, uint8 value) {
+int AdLibDriver::update_nop(const uint8 *&dataptr, Channel &channel, uint8 value) {
--dataptr;
return 0;
}
-int AdLibDriver::update_setDurationRandomness(uint8 *&dataptr, Channel &channel, uint8 value) {
+int AdLibDriver::update_setDurationRandomness(const uint8 *&dataptr, Channel &channel, uint8 value) {
channel.durationRandomness = value;
return 0;
}
-int AdLibDriver::update_changeChannelTempo(uint8 *&dataptr, Channel &channel, uint8 value) {
+int AdLibDriver::update_changeChannelTempo(const uint8 *&dataptr, Channel &channel, uint8 value) {
int tempo = channel.tempo + (int8)value;
if (tempo <= 0)
@@ -1754,7 +1797,7 @@ int AdLibDriver::update_changeChannelTempo(uint8 *&dataptr, Channel &channel, ui
return 0;
}
-int AdLibDriver::updateCallback46(uint8 *&dataptr, Channel &channel, uint8 value) {
+int AdLibDriver::updateCallback46(const uint8 *&dataptr, Channel &channel, uint8 value) {
uint8 entry = *dataptr++;
_tablePtr1 = _unkTable2[entry++];
_tablePtr2 = _unkTable2[entry];
@@ -1765,27 +1808,43 @@ int AdLibDriver::updateCallback46(uint8 *&dataptr, Channel &channel, uint8 value
return 0;
}
-int AdLibDriver::update_setupRhythmSection(uint8 *&dataptr, Channel &channel, uint8 value) {
+int AdLibDriver::update_setupRhythmSection(const uint8 *&dataptr, Channel &channel, uint8 value) {
int channelBackUp = _curChannel;
int regOffsetBackUp = _curRegOffset;
_curChannel = 6;
_curRegOffset = _regOffset[6];
- setupInstrument(_curRegOffset, getInstrument(value), channel);
+ const uint8 *instrument;
+ instrument = getInstrument(value);
+ if (instrument) {
+ setupInstrument(_curRegOffset, instrument, channel);
+ } else {
+ debugC(3, kDebugLevelSound, "AdLibDriver::update_setupRhythmSection: Invalid instrument %d for channel 6 specified", value);
+ }
_unkValue6 = channel.opLevel2;
_curChannel = 7;
_curRegOffset = _regOffset[7];
- setupInstrument(_curRegOffset, getInstrument(*dataptr++), channel);
+ instrument = getInstrument(*dataptr++);
+ if (instrument) {
+ setupInstrument(_curRegOffset, instrument, channel);
+ } else {
+ debugC(3, kDebugLevelSound, "AdLibDriver::update_setupRhythmSection: Invalid instrument %d for channel 7 specified", value);
+ }
_unkValue7 = channel.opLevel1;
_unkValue8 = channel.opLevel2;
_curChannel = 8;
_curRegOffset = _regOffset[8];
- setupInstrument(_curRegOffset, getInstrument(*dataptr++), channel);
+ instrument = getInstrument(*dataptr++);
+ if (instrument) {
+ setupInstrument(_curRegOffset, instrument, channel);
+ } else {
+ debugC(3, kDebugLevelSound, "AdLibDriver::update_setupRhythmSection: Invalid instrument %d for channel 8 specified", value);
+ }
_unkValue9 = channel.opLevel1;
_unkValue10 = channel.opLevel2;
@@ -1810,7 +1869,7 @@ int AdLibDriver::update_setupRhythmSection(uint8 *&dataptr, Channel &channel, ui
return 0;
}
-int AdLibDriver::update_playRhythmSection(uint8 *&dataptr, Channel &channel, uint8 value) {
+int AdLibDriver::update_playRhythmSection(const uint8 *&dataptr, Channel &channel, uint8 value) {
// Any instrument that we want to play, and which was already playing,
// is temporarily keyed off. Instruments that were off already, or
// which we don't want to play, retain their old on/off status. This is
@@ -1830,7 +1889,7 @@ int AdLibDriver::update_playRhythmSection(uint8 *&dataptr, Channel &channel, uin
return 0;
}
-int AdLibDriver::update_removeRhythmSection(uint8 *&dataptr, Channel &channel, uint8 value) {
+int AdLibDriver::update_removeRhythmSection(const uint8 *&dataptr, Channel &channel, uint8 value) {
--dataptr;
_rhythmSectionBits = 0;
@@ -1841,7 +1900,7 @@ int AdLibDriver::update_removeRhythmSection(uint8 *&dataptr, Channel &channel, u
return 0;
}
-int AdLibDriver::updateCallback51(uint8 *&dataptr, Channel &channel, uint8 value) {
+int AdLibDriver::updateCallback51(const uint8 *&dataptr, Channel &channel, uint8 value) {
uint8 value2 = *dataptr++;
if (value & 1) {
@@ -1882,7 +1941,7 @@ int AdLibDriver::updateCallback51(uint8 *&dataptr, Channel &channel, uint8 value
return 0;
}
-int AdLibDriver::updateCallback52(uint8 *&dataptr, Channel &channel, uint8 value) {
+int AdLibDriver::updateCallback52(const uint8 *&dataptr, Channel &channel, uint8 value) {
uint8 value2 = *dataptr++;
if (value & 1) {
@@ -1923,7 +1982,7 @@ int AdLibDriver::updateCallback52(uint8 *&dataptr, Channel &channel, uint8 value
return 0;
}
-int AdLibDriver::updateCallback53(uint8 *&dataptr, Channel &channel, uint8 value) {
+int AdLibDriver::updateCallback53(const uint8 *&dataptr, Channel &channel, uint8 value) {
uint8 value2 = *dataptr++;
if (value & 1) {
@@ -1964,17 +2023,17 @@ int AdLibDriver::updateCallback53(uint8 *&dataptr, Channel &channel, uint8 value
return 0;
}
-int AdLibDriver::update_setSoundTrigger(uint8 *&dataptr, Channel &channel, uint8 value) {
+int AdLibDriver::update_setSoundTrigger(const uint8 *&dataptr, Channel &channel, uint8 value) {
_soundTrigger = value;
return 0;
}
-int AdLibDriver::update_setTempoReset(uint8 *&dataptr, Channel &channel, uint8 value) {
+int AdLibDriver::update_setTempoReset(const uint8 *&dataptr, Channel &channel, uint8 value) {
channel.tempoReset = value;
return 0;
}
-int AdLibDriver::updateCallback56(uint8 *&dataptr, Channel &channel, uint8 value) {
+int AdLibDriver::updateCallback56(const uint8 *&dataptr, Channel &channel, uint8 value) {
channel.unk39 = value;
channel.unk40 = *dataptr++;
return 0;
@@ -2487,13 +2546,13 @@ void SoundAdLibPC::internalLoadFile(Common::String file) {
_soundDataPtr = new uint8[soundDataSize];
assert(_soundDataPtr);
- memcpy(_soundDataPtr, p, soundDataSize*sizeof(uint8));
+ memcpy(_soundDataPtr, p, soundDataSize);
delete[] fileData;
fileData = p = 0;
fileSize = 0;
- _driver->setSoundData(_soundDataPtr);
+ _driver->setSoundData(_soundDataPtr, soundDataSize);
_soundFileLoaded = file;
}
diff --git a/engines/kyra/staticres.cpp b/engines/kyra/staticres.cpp
index 9b3b92b9c7..731f2f4ce5 100644
--- a/engines/kyra/staticres.cpp
+++ b/engines/kyra/staticres.cpp
@@ -39,7 +39,7 @@
namespace Kyra {
-#define RESFILE_VERSION 85
+#define RESFILE_VERSION 86
namespace {
bool checkKyraDat(Common::SeekableReadStream *file) {
diff --git a/engines/kyra/staticres_eob.cpp b/engines/kyra/staticres_eob.cpp
index 54cc3066ec..aa7adc7461 100644
--- a/engines/kyra/staticres_eob.cpp
+++ b/engines/kyra/staticres_eob.cpp
@@ -464,20 +464,34 @@ void EoBCoreEngine::initStaticResource() {
// EOB I doesn't have load and save menus, because there is only one single
// save slot. Instead of emulating this we provide a menu similiar to EOB II.
- static const char *const saveLoadStrings[3][4] = {
- { "Cancel", "Empty Slot", "Save Game", "Load Game" },
- { "Abbr.", "Leerer Slot", "Speichern", " Laden" },
- { 0, 0, 0, 0 }
+ static const char *const saveLoadStrings[4][4] = {
+ { "Cancel", "Empty Slot", "Save Game", "Load Game" },
+ { "Abbr.", "Leerer Slot", "Speichern", " Laden" },
+ { " < < ", "Posizione Vuota", "Salva", "Carica" },
+ { 0, 0, 0, 0 }
};
- static const char *const errorSlotEmptyString[3] = {
+ static const char *const errorSlotEmptyString[4] = {
"There is no game\rsaved in that slot!",
"Hier ist noch kein\rSpiel gespeichert!",
+ "Non c'\x0E alcun gioco\rsalvato in quella\rposizione!",
0
};
- _saveLoadStrings = saveLoadStrings[(_flags.lang == Common::EN_ANY) ? 0 : ((_flags.lang == Common::DE_DEU) ? 1 : 2)];
- _errorSlotEmptyString = errorSlotEmptyString[(_flags.lang == Common::EN_ANY) ? 0 : ((_flags.lang == Common::DE_DEU) ? 1 : 2)];
+ if (_flags.lang == Common::EN_ANY) {
+ _saveLoadStrings = saveLoadStrings[0];
+ _errorSlotEmptyString = errorSlotEmptyString[0];
+ } else if (_flags.lang == Common::DE_DEU) {
+ _saveLoadStrings = saveLoadStrings[1];
+ _errorSlotEmptyString = errorSlotEmptyString[1];
+ } else if (_flags.lang == Common::IT_ITA) {
+ _saveLoadStrings = saveLoadStrings[2];
+ _errorSlotEmptyString = errorSlotEmptyString[2];
+ } else {
+ _saveLoadStrings = saveLoadStrings[3];
+ _errorSlotEmptyString = errorSlotEmptyString[3];
+ }
+
_menuOkString = "OK";
}
diff --git a/engines/kyra/text_rpg.cpp b/engines/kyra/text_rpg.cpp
index 03acde8497..5cd99738ef 100644
--- a/engines/kyra/text_rpg.cpp
+++ b/engines/kyra/text_rpg.cpp
@@ -30,7 +30,7 @@
namespace Kyra {
enum {
- kEoBTextBufferSize = 2048
+ kEoBTextBufferSize = 2560
};
TextDisplayer_rpg::TextDisplayer_rpg(KyraRpgEngine *engine, Screen *scr) : _vm(engine), _screen(scr),
@@ -216,7 +216,7 @@ void TextDisplayer_rpg::displayText(char *str, ...) {
break;
default:
- if (_vm->game() == GI_LOL || (unsigned char)c > 30) {
+ if (_vm->game() == GI_EOB1 || _vm->game() == GI_LOL || (unsigned char)c > 30) {
_lineWidth += (sjisTextMode ? 4 : (_screen->_currentFont == Screen::FID_SJIS_FNT ? 9 : _screen->getCharWidth((uint8)c)));
_currentLine[_numCharsLeft++] = c;
_currentLine[_numCharsLeft] = 0;
diff --git a/engines/kyra/vqa.cpp b/engines/kyra/vqa.cpp
index fb51c05e51..cfd5f6ffc6 100644
--- a/engines/kyra/vqa.cpp
+++ b/engines/kyra/vqa.cpp
@@ -532,7 +532,7 @@ void VQADecoder::VQAVideoTrack::handleVQFR(Common::SeekableReadStream *stream) {
uint32 tag = readTag(stream);
uint32 i;
size = stream->readUint32BE();
-
+
switch (tag) {
case MKTAG('C','B','F','0'): // Full codebook
stream->read(_codeBook, size);
diff --git a/engines/mads/animation.cpp b/engines/mads/animation.cpp
index 512a3979f9..2b999fa305 100644
--- a/engines/mads/animation.cpp
+++ b/engines/mads/animation.cpp
@@ -32,10 +32,8 @@ void AAHeader::load(Common::SeekableReadStream *f) {
_miscEntriesCount = f->readUint16LE();
_frameEntriesCount = f->readUint16LE();
_messagesCount = f->readUint16LE();
- f->skip(1);
- _flags = f->readByte();
-
- f->skip(2);
+ _loadFlags = f->readUint16LE();
+ _charSpacing = f->readSint16LE();
_bgType = (AnimBgType)f->readUint16LE();
_roomNumber = f->readUint16LE();
f->skip(2);
@@ -49,7 +47,7 @@ void AAHeader::load(Common::SeekableReadStream *f) {
char buffer[FILENAME_SIZE];
f->read(buffer, FILENAME_SIZE);
buffer[FILENAME_SIZE - 1] = '\0';
- _interfaceFile = Common::String(buffer);
+ _backgroundFile = Common::String(buffer);
for (int i = 0; i < 50; ++i) {
f->read(buffer, FILENAME_SIZE);
@@ -134,7 +132,8 @@ void AnimMiscEntry::load(Common::SeekableReadStream *f) {
_numTicks = f->readUint16LE();
_posAdjust.x = f->readSint16LE();
_posAdjust.y = f->readSint16LE();
- _field8 = f->readUint16LE();
+ _scroll.x = f->readSByte();
+ _scroll.y = f->readSByte();
}
/*------------------------------------------------------------------------*/
@@ -160,6 +159,7 @@ Animation *Animation::init(MADSEngine *vm, Scene *scene) {
}
Animation::Animation(MADSEngine *vm, Scene *scene) : _vm(vm), _scene(scene) {
+ _flags = 0;
_font = nullptr;
_resetFlag = false;
_messageCtr = 0;
@@ -175,6 +175,8 @@ Animation::Animation(MADSEngine *vm, Scene *scene) : _vm(vm), _scene(scene) {
_actionDetails._indirectObjectId = -1;
_currentFrame = 0;
_oldFrameEntry = 0;
+ _rgbResult = -1;
+ _palIndex1 = _palIndex2 = -1;
}
Animation::~Animation() {
@@ -189,7 +191,7 @@ Animation::~Animation() {
}
}
-void Animation::load(UserInterface &interfaceSurface, DepthSurface &depthSurface,
+void Animation::load(MSurface &backSurface, DepthSurface &depthSurface,
const Common::String &resName, int flags, Common::Array<PaletteCycle> *palCycles,
SceneInfo *sceneInfo) {
Common::String resourceName = resName;
@@ -205,9 +207,10 @@ void Animation::load(UserInterface &interfaceSurface, DepthSurface &depthSurface
if (_header._bgType == ANIMBG_INTERFACE)
flags |= PALFLAG_RESERVED;
+ _flags = flags;
if (flags & ANIMFLAG_LOAD_BACKGROUND) {
- loadInterface(interfaceSurface, depthSurface, _header, flags, palCycles, sceneInfo);
+ loadBackground(backSurface, depthSurface, _header, flags, palCycles, sceneInfo);
}
if (flags & ANIMFLAG_LOAD_BACKGROUND_ONLY) {
// No data
@@ -243,7 +246,7 @@ void Animation::load(UserInterface &interfaceSurface, DepthSurface &depthSurface
for (int i = 0; i < _header._frameEntriesCount; i++) {
AnimFrameEntry rec;
- rec.load(frameStream, flags & ANIMFLAG_LOAD_BACKGROUND);
+ rec.load(frameStream, _header._bgType == ANIMBG_INTERFACE);
_frameEntries.push_back(rec);
}
@@ -256,7 +259,7 @@ void Animation::load(UserInterface &interfaceSurface, DepthSurface &depthSurface
// Chunk 4: Misc Data
Common::SeekableReadStream *miscStream = madsPack.getItemStream(streamIndex++);
- if (flags & ANIMFLAG_LOAD_BACKGROUND) {
+ if (_header._bgType == ANIMBG_INTERFACE) {
for (int i = 0; i < _header._miscEntriesCount; ++i) {
AnimUIEntry rec;
rec.load(miscStream);
@@ -275,7 +278,7 @@ void Animation::load(UserInterface &interfaceSurface, DepthSurface &depthSurface
// If the animation specifies a font, then load it for access
delete _font;
- if (_header._flags & ANIMFLAG_CUSTOM_FONT) {
+ if (_header._loadFlags & ANIMFLAG_CUSTOM_FONT) {
Common::String fontName = "*" + _header._fontResource;
_font = _vm->_font->getFont(fontName.c_str());
} else {
@@ -337,9 +340,6 @@ void Animation::startAnimation(int endTrigger) {
_unkIndex = -1;
//SpriteAsset *asset = _scene->_sprites[_spriteListIndexes[_header._spritesIndex]];
- // TODO: Weird stuff with _unkList. Seems like it's treated as pointers
- // here, but in processText, it's used as POINTs?
-
loadFrame(1);
}
@@ -385,12 +385,12 @@ bool Animation::drawFrame(SpriteAsset &spriteSet, const Common::Point &pt, int f
return 0;
}
-void Animation::loadInterface(UserInterface &interfaceSurface, DepthSurface &depthSurface,
+void Animation::loadBackground(MSurface &backSurface, DepthSurface &depthSurface,
AAHeader &header, int flags, Common::Array<PaletteCycle> *palCycles, SceneInfo *sceneInfo) {
_scene->_depthStyle = 0;
if (header._bgType <= ANIMBG_FULL_SIZE) {
_vm->_palette->_paletteUsage.setEmpty();
- sceneInfo->load(header._roomNumber, flags, header._interfaceFile, 0, depthSurface, interfaceSurface);
+ sceneInfo->load(header._roomNumber, 0, header._backgroundFile, flags, depthSurface, backSurface);
_scene->_depthStyle = sceneInfo->_depthStyle == 2 ? 1 : 0;
if (palCycles) {
palCycles->clear();
@@ -399,8 +399,8 @@ void Animation::loadInterface(UserInterface &interfaceSurface, DepthSurface &dep
}
} else if (header._bgType == ANIMBG_INTERFACE) {
// Load a scene interface
- Common::String resourceName = "*" + header._interfaceFile;
- interfaceSurface.load(resourceName);
+ Common::String resourceName = "*" + header._backgroundFile;
+ backSurface.load(resourceName);
if (palCycles)
palCycles->clear();
@@ -415,6 +415,7 @@ bool Animation::hasScroll() const {
void Animation::update() {
Scene &scene = _vm->_game->_scene;
+ Palette &palette = *_vm->_palette;
if (_header._manualFlag) {
int spriteListIndex = _spriteListIndexes[_header._spritesIndex];
@@ -534,28 +535,43 @@ void Animation::update() {
// Start displaying the message
AnimMessage &me = _messages[idx];
- // The color index to use is dependant on how many messages are currently on-screen
- uint8 colIndex;
- switch (_messageCtr) {
- case 1:
- colIndex = 252;
- break;
- case 2:
- colIndex = 16;
- break;
- default:
- colIndex = 250;
- break;
- }
+ if (_flags & ANIMFLAG_ANIMVIEW) {
+ _rgbResult = palette._paletteUsage.checkRGB(me._rgb1, -1, true, &_palIndex1);
+ _rgbResult = palette._paletteUsage.checkRGB(me._rgb2, _rgbResult, true, &_palIndex2);
+
+ // Update the palette with the two needed colors
+ int palStart = MIN(_palIndex1, _palIndex2);
+ int palCount = ABS(_palIndex2 - _palIndex1) + 1;
+ palette.setPalette(&palette._mainPalette[palStart * 3], palStart, palCount);
+ } else {
+ // The color index to use is dependant on how many messages are currently on-screen
+ switch (_messageCtr) {
+ case 1:
+ _palIndex1 = 252;
+ break;
+ case 2:
+ _palIndex1 = 16;
+ break;
+ default:
+ _palIndex1 = 250;
+ break;
+ }
+ _palIndex2 = _palIndex1 + 1;
- _vm->_palette->setEntry(colIndex, me._rgb1[0], me._rgb1[1], me._rgb1[2]);
- _vm->_palette->setEntry(colIndex + 1, me._rgb2[0], me._rgb2[1], me._rgb2[2]);
+ _vm->_palette->setEntry(_palIndex1, me._rgb1[0], me._rgb1[1], me._rgb1[2]);
+ _vm->_palette->setEntry(_palIndex2, me._rgb2[0], me._rgb2[1], me._rgb2[2]);
+ }
// Add a kernel message to display the given text
- me._kernelMsgIndex = scene._kernelMessages.add(me._pos, colIndex * 0x101 + 0x100,
+ me._kernelMsgIndex = scene._kernelMessages.add(me._pos,
+ _palIndex1 | (_palIndex2 << 8),
0, 0, INDEFINITE_TIMEOUT, me._msg);
assert(me._kernelMsgIndex >= 0);
++_messageCtr;
+
+ // If there's an accompanying sound, also play it
+ if (me._soundId > 0)
+ _vm->_audio->playSound(me._soundId - 1);
}
}
diff --git a/engines/mads/animation.h b/engines/mads/animation.h
index 15086d3e41..8b85a5370d 100644
--- a/engines/mads/animation.h
+++ b/engines/mads/animation.h
@@ -34,10 +34,11 @@
namespace MADS {
enum AnimFlag {
- ANIMFLAG_DITHER = 0x0001, // Dither to 16 colors
- ANIMFLAG_CUSTOM_FONT = 0x0020, // Load ccustom font
+ ANIMFLAG_DITHER = 0x1000, // Dither to 16 colors
+ ANIMFLAG_CUSTOM_FONT = 0x2000, // Load ccustom font
ANIMFLAG_LOAD_BACKGROUND = 0x0100, // Load background
- ANIMFLAG_LOAD_BACKGROUND_ONLY = 0x0200 // Load background only
+ ANIMFLAG_LOAD_BACKGROUND_ONLY = 0x0200, // Load background only
+ ANIMFLAG_ANIMVIEW = 0x4000 // Cutscene animation
};
enum AnimBgType {
@@ -82,7 +83,7 @@ public:
int _msgIndex;
int _numTicks;
Common::Point _posAdjust;
- int _field8;
+ Common::Point _scroll;
/**
* Loads data for the record
@@ -116,14 +117,15 @@ public:
int _miscEntriesCount;
int _frameEntriesCount;
int _messagesCount;
- byte _flags;
+ int _loadFlags;
+ int _charSpacing;
AnimBgType _bgType;
int _roomNumber;
bool _manualFlag;
int _spritesIndex;
Common::Point _scrollPosition;
uint32 _scrollTicks;
- Common::String _interfaceFile;
+ Common::String _backgroundFile;
Common::StringArray _spriteSetNames;
Common::String _lbmFilename;
Common::String _spritesFilename;
@@ -154,6 +156,9 @@ private:
uint32 _nextScrollTimer;
int _messageCtr;
int _trigger;
+ int _flags;
+ int _rgbResult;
+ int _palIndex1, _palIndex2;
TriggerMode _triggerMode;
ActionDetails _actionDetails;
@@ -166,9 +171,9 @@ private:
bool drawFrame(SpriteAsset &spriteSet, const Common::Point &pt, int frameNumber);
/**
- * Load the user interface display for an animation
+ * Load the user interface display or background for an animation
*/
- void loadInterface(UserInterface &interfaceSurface, DepthSurface &depthSurface,
+ void loadBackground(MSurface &backSurface, DepthSurface &depthSurface,
AAHeader &header, int flags, Common::Array<PaletteCycle> *palCycles, SceneInfo *sceneInfo);
/**
@@ -196,7 +201,7 @@ public:
/**
* Loads animation data
*/
- void load(UserInterface &interfaceSurface, DepthSurface &depthSurface, const Common::String &resName,
+ void load(MSurface &backSurface, DepthSurface &depthSurface, const Common::String &resName,
int flags, Common::Array<PaletteCycle> *palCycles, SceneInfo *sceneInfo);
/**
@@ -223,6 +228,8 @@ public:
int roomNumber() const { return _header._roomNumber; }
void resetSpriteSetsCount() { _header._spriteSetsCount = 0; } // CHECKME: See if it doesn't leak the memory when the destructor is called
+
+ SpriteAsset *getSpriteSet(int idx) { return _spriteSets[idx]; }
};
} // End of namespace MADS
diff --git a/engines/mads/audio.cpp b/engines/mads/audio.cpp
index 1c61e13957..def2cd6c62 100644
--- a/engines/mads/audio.cpp
+++ b/engines/mads/audio.cpp
@@ -37,6 +37,7 @@ AudioPlayer::AudioPlayer(Audio::Mixer *mixer, uint32 gameID) : _mixer(mixer), _g
AudioPlayer::~AudioPlayer() {
_dsrEntries.clear();
+ _filename = "";
}
bool AudioPlayer::isPlaying() const {
@@ -65,25 +66,27 @@ void AudioPlayer::setDefaultSoundGroup() {
}
void AudioPlayer::setSoundGroup(const Common::String &filename) {
- _dsrEntries.clear();
-
- _filename = filename;
- _dsrFile.open(filename);
-
- // Read header
- uint16 entryCount = _dsrFile.readUint16LE();
-
- for (uint16 i = 0; i < entryCount; i++) {
- DSREntry newEntry;
- newEntry.frequency = _dsrFile.readUint16LE();
- newEntry.channels = _dsrFile.readUint32LE();
- newEntry.compSize = _dsrFile.readUint32LE();
- newEntry.uncompSize = _dsrFile.readUint32LE();
- newEntry.offset = _dsrFile.readUint32LE();
- _dsrEntries.push_back(newEntry);
+ if (_filename != filename) {
+ _dsrEntries.clear();
+
+ _filename = filename;
+ _dsrFile.open(filename);
+
+ // Read header
+ uint16 entryCount = _dsrFile.readUint16LE();
+
+ for (uint16 i = 0; i < entryCount; i++) {
+ DSREntry newEntry;
+ newEntry.frequency = _dsrFile.readUint16LE();
+ newEntry.channels = _dsrFile.readUint32LE();
+ newEntry.compSize = _dsrFile.readUint32LE();
+ newEntry.uncompSize = _dsrFile.readUint32LE();
+ newEntry.offset = _dsrFile.readUint32LE();
+ _dsrEntries.push_back(newEntry);
+ }
+
+ _dsrFile.close();
}
-
- _dsrFile.close();
}
void AudioPlayer::playSound(int soundIndex, bool loop) {
@@ -126,4 +129,8 @@ void AudioPlayer::playSound(int soundIndex, bool loop) {
*/
}
+void AudioPlayer::stop() {
+ _mixer->stopHandle(_handle);
+}
+
} // End of namespace M4
diff --git a/engines/mads/audio.h b/engines/mads/audio.h
index 21f4bed59a..13c540bf85 100644
--- a/engines/mads/audio.h
+++ b/engines/mads/audio.h
@@ -46,6 +46,7 @@ public:
void setSoundGroup(const Common::String &filename);
void setDefaultSoundGroup();
void playSound(int soundIndex, bool loop = false);
+ void stop();
void setVolume(int volume);
bool isPlaying() const;
diff --git a/engines/mads/debugger.cpp b/engines/mads/debugger.cpp
index 6bc6cf572d..99251f9fbb 100644
--- a/engines/mads/debugger.cpp
+++ b/engines/mads/debugger.cpp
@@ -24,6 +24,7 @@
#include "mads/compression.h"
#include "mads/mads.h"
#include "mads/debugger.h"
+#include "mads/nebular/menu_nebular.h"
namespace MADS {
@@ -46,6 +47,8 @@ Debugger::Debugger(MADSEngine *vm) : GUI::Debugger(), _vm(vm) {
registerCmd("show_item", WRAP_METHOD(Debugger, Cmd_ShowItem));
registerCmd("dump_items", WRAP_METHOD(Debugger, Cmd_DumpItems));
registerCmd("item", WRAP_METHOD(Debugger, Cmd_Item));
+ registerCmd("play_anim", WRAP_METHOD(Debugger, Cmd_PlayAnim));
+ registerCmd("play_text", WRAP_METHOD(Debugger, Cmd_PlayText));
}
static int strToInt(const char *s) {
@@ -348,4 +351,44 @@ bool Debugger::Cmd_Item(int argc, const char **argv) {
}
}
+bool Debugger::Cmd_PlayAnim(int argc, const char **argv) {
+ if (argc != 2) {
+ debugPrintf("Usage: %s <anim name>\n", argv[0]);
+ return true;
+ } else {
+ Common::String resName = argv[1];
+ if (resName.hasPrefix("@"))
+ resName.deleteChar(0);
+
+ Common::File f;
+ if (f.exists(resName) || f.exists(resName + ".res")) {
+ AnimationView::execute(_vm, resName);
+ return false;
+ } else {
+ debugPrintf("Could not find resource file\n");
+ return true;
+ }
+ }
+}
+
+bool Debugger::Cmd_PlayText(int argc, const char **argv) {
+ if (argc != 2) {
+ debugPrintf("Usage: %s <text name>\n", argv[0]);
+ return true;
+ } else {
+ Common::String resName = argv[1];
+ if (resName.hasPrefix("@"))
+ resName.deleteChar(0);
+
+ Common::File f;
+ if (f.exists(resName) || f.exists(resName + ".txr")) {
+ TextView::execute(_vm, resName);
+ return false;
+ } else {
+ debugPrintf("Could not find resource file\n");
+ return true;
+ }
+ }
+}
+
} // End of namespace MADS
diff --git a/engines/mads/debugger.h b/engines/mads/debugger.h
index 351eb13615..c8fee5f5b2 100644
--- a/engines/mads/debugger.h
+++ b/engines/mads/debugger.h
@@ -49,6 +49,8 @@ protected:
bool Cmd_ShowItem(int argc, const char **argv);
bool Cmd_DumpItems(int argc, const char **argv);
bool Cmd_Item(int argc, const char **argv);
+ bool Cmd_PlayAnim(int argc, const char **argv);
+ bool Cmd_PlayText(int argc, const char **argv);
public:
bool _showMousePos;
public:
diff --git a/engines/mads/dialogs.cpp b/engines/mads/dialogs.cpp
index 7e6909d113..5e38f34fc6 100644
--- a/engines/mads/dialogs.cpp
+++ b/engines/mads/dialogs.cpp
@@ -395,4 +395,78 @@ Dialogs::Dialogs(MADSEngine *vm)
_pendingDialog = DIALOG_NONE;
}
+/*------------------------------------------------------------------------*/
+
+FullScreenDialog::FullScreenDialog(MADSEngine *vm) : _vm(vm) {
+ switch (_vm->getGameID()) {
+ case GType_RexNebular:
+ _screenId = 990;
+ break;
+ case GType_Phantom:
+ _screenId = 920;
+ break;
+ case GType_Dragonsphere:
+ _screenId = 922;
+ break;
+ default:
+ error("FullScreenDialog:Unknown game");
+ }
+ _palFlag = true;
+}
+
+FullScreenDialog::~FullScreenDialog() {
+ _vm->_screen.resetClipBounds();
+ _vm->_game->_scene.restrictScene();
+}
+
+void FullScreenDialog::display() {
+ Game &game = *_vm->_game;
+ Scene &scene = game._scene;
+
+ int nextSceneId = scene._nextSceneId;
+ int currentSceneId = scene._currentSceneId;
+ int priorSceneId = scene._priorSceneId;
+
+ if (_screenId > 0) {
+ SceneInfo *sceneInfo = SceneInfo::init(_vm);
+ sceneInfo->load(_screenId, 0, "", 0, scene._depthSurface, scene._backgroundSurface);
+ }
+
+ scene._priorSceneId = priorSceneId;
+ scene._currentSceneId = currentSceneId;
+ scene._nextSceneId = nextSceneId;
+
+ _vm->_events->initVars();
+ game._kernelMode = KERNEL_ROOM_INIT;
+
+ byte pal[768];
+ if (_vm->_screenFade) {
+ Common::fill(&pal[0], &pal[PALETTE_SIZE], 0);
+ _vm->_palette->setFullPalette(pal);
+ } else {
+ _vm->_palette->getFullPalette(pal);
+ _vm->_palette->fadeOut(pal, nullptr, 0, PALETTE_COUNT, 0, 1, 1, 16);
+ }
+
+ // Set Fx state and palette entries
+ game._fx = _vm->_screenFade == SCREEN_FADE_SMOOTH ? kTransitionFadeIn : kCenterVertTransition;
+ game._trigger = 0;
+
+ // Clear the screen and draw the upper and lower horizontal lines
+ _vm->_screen.empty();
+ _vm->_palette->setLowRange();
+ _vm->_screen.hLine(0, 20, MADS_SCREEN_WIDTH, 2);
+ _vm->_screen.hLine(0, 179, MADS_SCREEN_WIDTH, 2);
+ _vm->_screen.resetClipBounds();
+ _vm->_screen.copyRectToScreen(Common::Rect(0, 0, MADS_SCREEN_WIDTH, MADS_SCREEN_HEIGHT));
+
+ // Restrict the screen to the area between the two lines
+ _vm->_screen.setClipBounds(Common::Rect(0, DIALOG_TOP, MADS_SCREEN_WIDTH,
+ DIALOG_TOP + MADS_SCENE_HEIGHT));
+ _vm->_game->_scene.restrictScene();
+
+ if (_screenId > 0)
+ scene._spriteSlots.fullRefresh();
+}
+
} // End of namespace MADS
diff --git a/engines/mads/dialogs.h b/engines/mads/dialogs.h
index c586a6f1fe..317c7bd792 100644
--- a/engines/mads/dialogs.h
+++ b/engines/mads/dialogs.h
@@ -30,6 +30,8 @@
namespace MADS {
+#define DIALOG_TOP 22
+
class Dialog {
private:
void setDialogPalette();
@@ -226,6 +228,36 @@ public:
virtual bool show(int messageId, int objectId = -1) = 0;
};
+class FullScreenDialog: public EventTarget {
+protected:
+ /**
+ * Engine reference
+ */
+ MADSEngine *_vm;
+
+ /**
+ * Screen/scene to show background from
+ */
+ int _screenId;
+
+ /**
+ * Flag for palette initialization
+ */
+ bool _palFlag;
+
+ /**
+ * Handles displaying the screen background and dialog
+ */
+ virtual void display();
+public:
+ /**
+ * Constructor
+ */
+ FullScreenDialog(MADSEngine *vm);
+
+ virtual ~FullScreenDialog();
+};
+
} // End of namespace MADS
#endif /* MADS_DIALOGS_H */
diff --git a/engines/mads/game.cpp b/engines/mads/game.cpp
index b544eff2db..94653f9a39 100644
--- a/engines/mads/game.cpp
+++ b/engines/mads/game.cpp
@@ -433,8 +433,6 @@ void Game::handleKeypress(const Common::Event &event) {
default:
break;
}
-
- warning("TODO: handleKeypress - %d", (int)event.kbd.keycode);
}
void Game::synchronize(Common::Serializer &s, bool phase1) {
@@ -558,7 +556,7 @@ void Game::writeSavegameHeader(Common::OutSaveFile *out, MADSSavegameHeader &hea
if (!_saveThumb)
createThumbnail();
Graphics::saveThumbnail(*out, *_saveThumb);
-
+
_saveThumb->free();
delete _saveThumb;
_saveThumb = nullptr;
diff --git a/engines/mads/mads.cpp b/engines/mads/mads.cpp
index 59eec40bcc..52a0b40561 100644
--- a/engines/mads/mads.cpp
+++ b/engines/mads/mads.cpp
@@ -68,6 +68,8 @@ MADSEngine::~MADSEngine() {
delete _resources;
delete _sound;
delete _audio;
+
+ _mixer->stopAll();
}
void MADSEngine::initialize() {
@@ -103,9 +105,6 @@ Common::Error MADSEngine::run() {
// Run the game
_game->run();
- // Dummy loop to keep application active
- _events->delay(9999);
-
return Common::kNoError;
}
diff --git a/engines/mads/menu_views.cpp b/engines/mads/menu_views.cpp
new file mode 100644
index 0000000000..ee4268a650
--- /dev/null
+++ b/engines/mads/menu_views.cpp
@@ -0,0 +1,768 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "common/scummsys.h"
+#include "mads/game.h"
+#include "mads/mads.h"
+#include "mads/menu_views.h"
+#include "mads/resources.h"
+#include "mads/scene.h"
+#include "mads/screen.h"
+
+namespace MADS {
+
+MenuView::MenuView(MADSEngine *vm) : FullScreenDialog(vm) {
+ _breakFlag = false;
+ _redrawFlag = true;
+ _palFlag = false;
+}
+
+void MenuView::show() {
+ Scene &scene = _vm->_game->_scene;
+ EventsManager &events = *_vm->_events;
+ _vm->_screenFade = SCREEN_FADE_FAST;
+
+ scene._spriteSlots.reset(true);
+ display();
+
+ events.setEventTarget(this);
+ events.hideCursor();
+
+ while (!_breakFlag && !_vm->shouldQuit()) {
+ if (_redrawFlag) {
+ scene._kernelMessages.update();
+
+ _vm->_game->_scene.drawElements(_vm->_game->_fx, _vm->_game->_fx);
+ _redrawFlag = false;
+ }
+
+ _vm->_events->waitForNextFrame();
+ _vm->_game->_fx = kTransitionNone;
+ doFrame();
+ }
+
+ events.setEventTarget(nullptr);
+ _vm->_sound->stop();
+}
+
+void MenuView::display() {
+ _vm->_palette->resetGamePalette(4, 8);
+
+ FullScreenDialog::display();
+}
+
+bool MenuView::onEvent(Common::Event &event) {
+ if (event.type == Common::EVENT_KEYDOWN || event.type == Common::EVENT_LBUTTONDOWN) {
+ _breakFlag = true;
+ _vm->_dialogs->_pendingDialog = DIALOG_MAIN_MENU;
+ return true;
+ }
+
+ return false;
+}
+
+Common::String MenuView::getResourceName() {
+ Common::String s(_filename);
+ s.toLowercase();
+ while (s.contains('.'))
+ s.deleteLastChar();
+
+ return s;
+}
+
+/*------------------------------------------------------------------------*/
+
+char TextView::_resourceName[100];
+#define TEXTVIEW_LINE_SPACING 2
+#define TEXT_ANIMATION_DELAY 100
+#define TV_NUM_FADE_STEPS 40
+#define TV_FADE_DELAY_MILLI 50
+
+void TextView::execute(MADSEngine *vm, const Common::String &resName) {
+ assert(resName.size() < 100);
+ Common::strlcpy(_resourceName, resName.c_str(), sizeof(_resourceName));
+ vm->_dialogs->_pendingDialog = DIALOG_TEXTVIEW;
+}
+
+TextView::TextView(MADSEngine *vm) : MenuView(vm) {
+ _animating = false;
+ _panSpeed = 0;
+ _spareScreen = nullptr;
+ _scrollCount = 0;
+ _lineY = -1;
+ _scrollTimeout = 0;
+ _panCountdown = 0;
+ _translationX = 0;
+ _screenId = -1;
+
+ _font = _vm->_font->getFont(FONT_CONVERSATION);
+ _vm->_palette->resetGamePalette(4, 0);
+
+ load();
+}
+
+TextView::~TextView() {
+ // Turn off palette cycling as well as any playing sound
+ Scene &scene = _vm->_game->_scene;
+ scene._cyclingActive = false;
+ _vm->_sound->stop();
+}
+
+void TextView::load() {
+ Common::String scriptName(_resourceName);
+ scriptName += ".txr";
+
+ _filename = scriptName;
+ if (!_script.open(scriptName))
+ error("Could not open resource %s", _resourceName);
+
+ processLines();
+}
+
+void TextView::processLines() {
+ if (_script.eos())
+ error("Attempted to read past end of response file");
+
+ while (!_script.eos()) {
+ // Read in the next line
+ _script.readLine(_currentLine, 79);
+ char *p = _currentLine + strlen(_currentLine) - 1;
+ if (*p == '\n')
+ *p = '\0';
+
+ // Commented out line, so go loop for another
+ if (_currentLine[0] == '#')
+ continue;
+
+ // Process the line
+ char *cStart = strchr(_currentLine, '[');
+ if (cStart) {
+ while (cStart) {
+ // Loop for possible multiple commands on one line
+ char *cEnd = strchr(_currentLine, ']');
+ if (!cEnd)
+ error("Unterminated command '%s' in response file", _currentLine);
+
+ *cEnd = '\0';
+ processCommand();
+
+ // Copy rest of line (if any) to start of buffer
+ Common::strlcpy(_currentLine, cEnd + 1, sizeof(_currentLine));
+
+ cStart = strchr(_currentLine, '[');
+ }
+
+ if (_currentLine[0]) {
+ processText();
+ break;
+ }
+
+ } else {
+ processText();
+ break;
+ }
+ }
+}
+
+void TextView::processCommand() {
+ Scene &scene = _vm->_game->_scene;
+ Common::String scriptLine(_currentLine + 1);
+ scriptLine.toUppercase();
+ const char *paramP;
+ const char *commandStr = scriptLine.c_str();
+
+ if (!strncmp(commandStr, "BACKGROUND", 10)) {
+ // Set the background
+ paramP = commandStr + 10;
+ resetPalette();
+ int screenId = getParameter(&paramP);
+
+ SceneInfo *sceneInfo = SceneInfo::init(_vm);
+ sceneInfo->load(screenId, 0, "", 0, scene._depthSurface, scene._backgroundSurface);
+ scene._spriteSlots.fullRefresh();
+ _redrawFlag = true;
+
+ } else if (!strncmp(commandStr, "GO", 2)) {
+ _animating = true;
+
+ } else if (!strncmp(commandStr, "PAN", 3)) {
+ // Set panning values
+ paramP = commandStr + 3;
+ int panX = getParameter(&paramP);
+ int panY = getParameter(&paramP);
+ int panSpeed = getParameter(&paramP);
+
+ if ((panX != 0) || (panY != 0)) {
+ _pan = Common::Point(panX, panY);
+ _panSpeed = panSpeed;
+ }
+
+ } else if (!strncmp(commandStr, "DRIVER", 6)) {
+ // Set the driver to use
+ paramP = commandStr + 7;
+
+ if (!strncmp(paramP, "#SOUND.00", 9)) {
+ int driverNum = paramP[9] - '0';
+ _vm->_sound->init(driverNum);
+ }
+ } else if (!strncmp(commandStr, "SOUND", 5)) {
+ // Set sound number
+ paramP = commandStr + 5;
+ int soundId = getParameter(&paramP);
+ _vm->_sound->command(soundId);
+
+ } else if (!strncmp(commandStr, "COLOR", 5) && ((commandStr[5] == '0') ||
+ (commandStr[5] == '1'))) {
+ // Set the text colors
+ int index = commandStr[5] - '0';
+ paramP = commandStr + 6;
+
+ byte r = getParameter(&paramP);
+ byte g = getParameter(&paramP);
+ byte b = getParameter(&paramP);
+
+ _vm->_palette->setEntry(5 + index, r, g, b);
+
+ } else if (!strncmp(commandStr, "SPARE", 5)) {
+ // Sets a secondary background number that can be later switched in with a PAGE command
+ paramP = commandStr + 6;
+ int spareIndex = commandStr[5] - '0';
+ assert(spareIndex < 4);
+ int screenId = getParameter(&paramP);
+
+ // Load the spare background
+ SceneInfo *sceneInfo = SceneInfo::init(_vm);
+ sceneInfo->_width = MADS_SCREEN_WIDTH;
+ sceneInfo->_height = MADS_SCENE_HEIGHT;
+ _spareScreens[spareIndex].setSize(MADS_SCREEN_WIDTH, MADS_SCENE_HEIGHT);
+ sceneInfo->loadMadsV1Background(screenId, "", SCENEFLAG_TRANSLATE,
+ _spareScreens[spareIndex]);
+ delete sceneInfo;
+
+ } else if (!strncmp(commandStr, "PAGE", 4)) {
+ // Signals to change to a previous specified secondary background
+ paramP = commandStr + 4;
+ int spareIndex = getParameter(&paramP);
+
+ // Only allow background switches if one isn't currently in progress
+ if (!_spareScreen && _spareScreens[spareIndex].getPixels() != nullptr) {
+ _spareScreen = &_spareScreens[spareIndex];
+ _translationX = 0;
+ }
+
+ } else {
+ error("Unknown response command: '%s'", commandStr);
+ }
+}
+
+int TextView::getParameter(const char **paramP) {
+ if ((**paramP != '=') && (**paramP != ','))
+ return 0;
+
+ int result = 0;
+ ++*paramP;
+ while ((**paramP >= '0') && (**paramP <= '9')) {
+ result = result * 10 + (**paramP - '0');
+ ++*paramP;
+ }
+
+ return result;
+}
+
+void TextView::processText() {
+ int xStart;
+
+ if (!strcmp(_currentLine, "***")) {
+ // Special signifier for end of script
+ _scrollCount = _font->getHeight() * 13;
+ _lineY = -1;
+ return;
+ }
+
+ _lineY = 0;
+
+ // Lines are always centered, except if line contains a '@', in which case the
+ // '@' marks the position that must be horizontally centered
+ char *centerP = strchr(_currentLine, '@');
+ if (centerP) {
+ *centerP = '\0';
+ xStart = (MADS_SCREEN_WIDTH / 2) - _font->getWidth(_currentLine);
+
+ // Delete the @ character and shift back the remainder of the string
+ char *p = centerP + 1;
+ if (*p == ' ') ++p;
+ strcpy(centerP, p);
+
+ } else {
+ int lineWidth = _font->getWidth(_currentLine);
+ xStart = (MADS_SCREEN_WIDTH - lineWidth) / 2;
+ }
+
+ // Add the new line to the list of pending lines
+ TextLine tl;
+ tl._pos = Common::Point(xStart, MADS_SCENE_HEIGHT);
+ tl._line = _currentLine;
+ tl._textDisplayIndex = -1;
+ _textLines.push_back(tl);
+}
+
+void TextView::display() {
+ FullScreenDialog::display();
+}
+
+void TextView::resetPalette() {
+ _vm->_palette->resetGamePalette(8, 8);
+ _vm->_palette->setEntry(5, 0, 63, 63);
+ _vm->_palette->setEntry(6, 0, 45, 45);
+}
+
+void TextView::doFrame() {
+ Scene &scene = _vm->_game->_scene;
+ if (!_animating)
+ return;
+
+ // Only update state if wait period has expired
+ uint32 currTime = g_system->getMillis();
+
+ // If a screen transition is in progress and it's time for another column, handle it
+ if (_spareScreen) {
+ byte *srcP = _spareScreen->getBasePtr(_translationX, 0);
+ byte *bgP = scene._backgroundSurface.getBasePtr(_translationX, 0);
+ byte *screenP = (byte *)_vm->_screen.getBasePtr(_translationX, 0);
+
+ for (int y = 0; y < MADS_SCENE_HEIGHT; ++y, srcP += MADS_SCREEN_WIDTH,
+ bgP += MADS_SCREEN_WIDTH, screenP += MADS_SCREEN_WIDTH) {
+ *bgP = *srcP;
+ *screenP = *srcP;
+ }
+
+ // Flag the column of the screen is modified
+ _vm->_screen.copyRectToScreen(Common::Rect(_translationX, 0,
+ _translationX + 1, MADS_SCENE_HEIGHT));
+
+ // Keep moving the column to copy to the right
+ if (++_translationX == MADS_SCREEN_WIDTH) {
+ // Surface transition is complete
+ _spareScreen = nullptr;
+ }
+ }
+
+ // Make sure it's time for an update
+ if (currTime < _scrollTimeout)
+ return;
+ _scrollTimeout = g_system->getMillis() + TEXT_ANIMATION_DELAY;
+ _redrawFlag = true;
+
+ // If any panning values are set, pan the background surface
+ if ((_pan.x != 0) || (_pan.y != 0)) {
+ if (_panCountdown > 0) {
+ --_panCountdown;
+ return;
+ }
+
+ // Handle horizontal panning
+ if (_pan.x != 0) {
+ byte *lineTemp = new byte[_pan.x];
+ for (int y = 0; y < MADS_SCENE_HEIGHT; ++y) {
+ byte *pixelsP = (byte *)scene._backgroundSurface.getBasePtr(0, y);
+
+ // Copy the first X pixels into temp buffer, move the rest of the line
+ // to the start of the line, and then move temp buffer pixels to end of line
+ Common::copy(pixelsP, pixelsP + _pan.x, lineTemp);
+ Common::copy(pixelsP + _pan.x, pixelsP + MADS_SCREEN_WIDTH, pixelsP);
+ Common::copy(lineTemp, lineTemp + _pan.x, pixelsP + MADS_SCREEN_WIDTH - _pan.x);
+ }
+
+ delete[] lineTemp;
+ }
+
+ // Handle vertical panning
+ if (_pan.y != 0) {
+ // Store the bottom Y lines into a temp buffer, move the rest of the lines down,
+ // and then copy the stored lines back to the top of the screen
+ byte *linesTemp = new byte[_pan.y * MADS_SCREEN_WIDTH];
+ byte *pixelsP = (byte *)scene._backgroundSurface.getBasePtr(0, MADS_SCENE_HEIGHT - _pan.y);
+ Common::copy(pixelsP, pixelsP + MADS_SCREEN_WIDTH * _pan.y, linesTemp);
+
+ for (int y = MADS_SCENE_HEIGHT - 1; y >= _pan.y; --y) {
+ byte *destP = (byte *)scene._backgroundSurface.getBasePtr(0, y);
+ byte *srcP = (byte *)scene._backgroundSurface.getBasePtr(0, y - _pan.y);
+ Common::copy(srcP, srcP + MADS_SCREEN_WIDTH, destP);
+ }
+
+ Common::copy(linesTemp, linesTemp + _pan.y * MADS_SCREEN_WIDTH,
+ (byte *)scene._backgroundSurface.getPixels());
+ delete[] linesTemp;
+ }
+
+ // Flag for a full screen refresh
+ scene._spriteSlots.fullRefresh();
+ }
+
+ // Scroll all active text lines up
+ for (int i = _textLines.size() - 1; i >= 0; --i) {
+ TextLine &tl = _textLines[i];
+ if (tl._textDisplayIndex != -1)
+ // Expire the text line that's already on-screen
+ scene._textDisplay.expire(tl._textDisplayIndex);
+
+ tl._pos.y--;
+ if (tl._pos.y < 0) {
+ _textLines.remove_at(i);
+ } else {
+ tl._textDisplayIndex = scene._textDisplay.add(tl._pos.x, tl._pos.y,
+ 0x605, -1, tl._line, _font);
+ }
+ }
+
+ if (_scrollCount > 0) {
+ // Handling final scrolling of text off of screen
+ if (--_scrollCount == 0) {
+ scriptDone();
+ return;
+ }
+ } else {
+ // Handling a text row
+ if (++_lineY == (_font->getHeight() + TEXTVIEW_LINE_SPACING))
+ processLines();
+ }
+}
+
+void TextView::scriptDone() {
+ _breakFlag = true;
+ _vm->_dialogs->_pendingDialog = DIALOG_MAIN_MENU;
+}
+
+/*------------------------------------------------------------------------*/
+
+char AnimationView::_resourceName[100];
+
+void AnimationView::execute(MADSEngine *vm, const Common::String &resName) {
+ assert(resName.size() < 100);
+ Common::strlcpy(_resourceName, resName.c_str(), sizeof(_resourceName));
+ vm->_dialogs->_pendingDialog = DIALOG_ANIMVIEW;
+}
+
+AnimationView::AnimationView(MADSEngine *vm) : MenuView(vm) {
+ _redrawFlag = false;
+
+ _soundDriverLoaded = false;
+ _previousUpdate = 0;
+ _screenId = -1;
+ _resetPalette = false;
+ _resyncMode = NEVER;
+ _v1 = 0;
+ _v2 = -1;
+ _resourceIndex = -1;
+ _currentAnimation = nullptr;
+ _sfx = 0;
+ _soundFlag = _bgLoadFlag = true;
+ _showWhiteBars = true;
+ _manualFrameNumber = 0;
+ _manualSpriteSet = nullptr;
+ _manualStartFrame = _manualEndFrame = 0;
+ _manualFrame2 = 0;
+ _animFrameNumber = 0;
+ _nextCyclingActive = false;
+ _sceneInfo = SceneInfo::init(_vm);
+
+ load();
+}
+
+AnimationView::~AnimationView() {
+ // Turn off palette cycling as well as any playing sound
+ Scene &scene = _vm->_game->_scene;
+ scene._cyclingActive = false;
+ _vm->_sound->stop();
+ _vm->_audio->stop();
+
+ // Delete data
+ delete _currentAnimation;
+ delete _sceneInfo;
+}
+
+void AnimationView::load() {
+ Common::String resName(_resourceName);
+ if (!resName.hasSuffix("."))
+ resName += ".res";
+
+ _filename = resName;
+ if (!_script.open(resName))
+ error("Could not open resource %s", resName.c_str());
+
+ processLines();
+}
+
+void AnimationView::display() {
+ Scene &scene = _vm->_game->_scene;
+ _vm->_palette->initPalette();
+ Common::fill(&_vm->_palette->_cyclingPalette[0], &_vm->_palette->_cyclingPalette[PALETTE_SIZE], 0);
+
+ _vm->_palette->resetGamePalette(1, 8);
+ scene._spriteSlots.reset();
+ scene._paletteCycles.clear();
+
+ MenuView::display();
+}
+
+bool AnimationView::onEvent(Common::Event &event) {
+ // Wait for the Escape key or a mouse press
+ if (((event.type == Common::EVENT_KEYDOWN) && (event.kbd.keycode == Common::KEYCODE_ESCAPE)) ||
+ (event.type == Common::EVENT_LBUTTONUP)) {
+ scriptDone();
+ return true;
+ }
+
+ return false;
+}
+
+void AnimationView::doFrame() {
+ Scene &scene = _vm->_game->_scene;
+
+ if (_resourceIndex == -1 || _currentAnimation->freeFlag()) {
+ if (++_resourceIndex == (int)_resources.size()) {
+ scriptDone();
+ } else {
+ scene._frameStartTime = 0;
+ loadNextResource();
+ }
+ } else if (_currentAnimation->getCurrentFrame() == 1) {
+ scene._cyclingActive = _nextCyclingActive;
+ }
+
+ if (_currentAnimation) {
+ ++scene._frameStartTime;
+ _currentAnimation->update();
+ _redrawFlag = true;
+ }
+}
+
+void AnimationView::loadNextResource() {
+ Scene &scene = _vm->_game->_scene;
+ Palette &palette = *_vm->_palette;
+ ResourceEntry &resEntry = _resources[_resourceIndex];
+ Common::Array<PaletteCycle> paletteCycles;
+
+ if (resEntry._bgFlag)
+ palette.resetGamePalette(1, 8);
+
+ palette._mainPalette[253 * 3] = palette._mainPalette[253 * 3 + 1]
+ = palette._mainPalette[253 * 3 + 2] = 0xb4;
+ palette.setPalette(&palette._mainPalette[253 * 3], 253, 1);
+
+ // Free any previous messages
+ scene._kernelMessages.reset();
+
+ // Handle the bars at the top/bottom
+ if (resEntry._showWhiteBars) {
+ // For animations the screen has been clipped to the middle 156 rows.
+ // So although it's slightly messy, bypass our screen class entirely,
+ // and draw the horizontal lines directly on the physiacl screen surface
+ Graphics::Surface *s = g_system->lockScreen();
+ s->hLine(0, 20, MADS_SCREEN_WIDTH, 253);
+ s->hLine(0, 179, MADS_SCREEN_WIDTH, 253);
+ g_system->unlockScreen();
+ }
+
+ // Load the new animation
+ delete _currentAnimation;
+ _currentAnimation = Animation::init(_vm, &scene);
+ int flags = ANIMFLAG_ANIMVIEW | (resEntry._bgFlag ? ANIMFLAG_LOAD_BACKGROUND : 0);
+ _currentAnimation->load(scene._backgroundSurface, scene._depthSurface,
+ resEntry._resourceName, flags, &paletteCycles, _sceneInfo);
+
+ // Signal for a screen refresh
+ scene._spriteSlots.fullRefresh();
+
+ // If a sound driver has been specified, then load the correct one
+ if (!_currentAnimation->_header._soundName.empty()) {
+ const char *chP = strchr(_currentAnimation->_header._soundName.c_str(), '.');
+ assert(chP);
+
+ // Handle both Rex naming (xxx.009) and naming in later games (e.g. xxx.ph9)
+ int driverNum = atoi(chP + 3);
+ // HACK for Dragon
+ if (_currentAnimation->_header._soundName == "#SOUND.DRG")
+ driverNum = 9;
+ _vm->_sound->init(driverNum);
+ }
+
+ // Handle any manual setup
+ if (_currentAnimation->_header._manualFlag) {
+ _manualFrameNumber = _currentAnimation->_header._spritesIndex;
+ _manualSpriteSet = _currentAnimation->getSpriteSet(_manualFrameNumber);
+ }
+
+ // Set the sound data for the animation
+ _vm->_sound->setEnabled(resEntry._soundFlag);
+
+ Common::String dsrName = _currentAnimation->_header._dsrName;
+ if (!dsrName.empty())
+ _vm->_audio->setSoundGroup(dsrName);
+
+ // Start the new animation
+ _currentAnimation->startAnimation(0);
+
+ // Handle the palette and cycling palette
+ scene._cyclingActive = false;
+ Common::copy(&palette._mainPalette[0], &palette._mainPalette[PALETTE_SIZE],
+ &palette._cyclingPalette[0]);
+
+ _vm->_game->_fx = (ScreenTransition)resEntry._fx;
+ _nextCyclingActive = paletteCycles.size() > 0;
+ if (!_vm->_game->_fx) {
+ palette.setFullPalette(palette._mainPalette);
+ }
+
+ scene.initPaletteAnimation(paletteCycles, _nextCyclingActive && !_vm->_game->_fx);
+}
+
+void AnimationView::scriptDone() {
+ _breakFlag = true;
+ _vm->_dialogs->_pendingDialog = DIALOG_MAIN_MENU;
+}
+
+void AnimationView::processLines() {
+ if (_script.eos()) {
+ // end of script, end animation
+ scriptDone();
+ return;
+ }
+
+ while (!_script.eos()) {
+ // Get in next line
+ _currentLine.clear();
+ char c;
+ while (!_script.eos() && (c = _script.readByte()) != '\n') {
+ if (c != '\r' && c != '\0')
+ _currentLine += c;
+ }
+
+ // Process the line
+ while (!_currentLine.empty()) {
+ if (_currentLine.hasPrefix("-")) {
+ _currentLine.deleteChar(0);
+
+ processCommand();
+ } else {
+ // Get resource name
+ Common::String resName;
+ while (!_currentLine.empty() && (c = _currentLine[0]) != ' ') {
+ _currentLine.deleteChar(0);
+ resName += c;
+ }
+
+ // Add resource into list along with any set state information
+ _resources.push_back(ResourceEntry(resName, _sfx, _soundFlag,
+ _bgLoadFlag, _showWhiteBars));
+
+ // Fx resets between resource entries
+ _sfx = 0;
+ }
+
+ // Skip any spaces
+ while (_currentLine.hasPrefix(" "))
+ _currentLine.deleteChar(0);
+ }
+ }
+}
+
+void AnimationView::processCommand() {
+ // Get the command character
+ char commandChar = toupper(_currentLine[0]);
+ _currentLine.deleteChar(0);
+
+ // Handle the command
+ switch (commandChar) {
+ case 'B':
+ _soundFlag = !_soundFlag;
+ break;
+ case 'H':
+ // -h[:ex] Disable EMS / XMS high memory support
+ if (_currentLine.hasPrefix(":"))
+ _currentLine.deleteChar(0);
+ while (_currentLine.hasPrefix("e") || _currentLine.hasPrefix("x"))
+ _currentLine.deleteChar(0);
+ break;
+ case 'O':
+ // -o:xxx Specify opening special effect
+ assert(_currentLine[0] == ':');
+ _currentLine.deleteChar(0);
+ _sfx = getParameter();
+ break;
+ case 'P':
+ // Switch to CONCAT mode, which is ignored anyway
+ break;
+ case 'R': {
+ // Resynch timer (always, beginning, never)
+ assert(_currentLine[0] == ':');
+ _currentLine.deleteChar(0);
+
+ char v = toupper(_currentLine[0]);
+ _currentLine.deleteChar(0);
+ if (v == 'N')
+ _resyncMode = NEVER;
+ else if (v == 'A')
+ _resyncMode = ALWAYS;
+ else if (v == 'B')
+ _resyncMode = BEGINNING;
+ else
+ error("Unknown parameter");
+ break;
+ }
+ case 'W':
+ // Switch white bars being visible
+ _showWhiteBars = !_showWhiteBars;
+ break;
+ case 'X':
+ // Exit after animation finishes. Ignore
+ break;
+ case 'D':
+ // Unimplemented and ignored in the original. Ignore as well
+ break;
+ case 'Y':
+ // Reset palette on startup
+ _resetPalette = true;
+ break;
+ default:
+ error("Unknown command char: '%c'", commandChar);
+ }
+}
+
+int AnimationView::getParameter() {
+ int result = 0;
+
+ while (!_currentLine.empty()) {
+ char c = _currentLine[0];
+
+ if (c >= '0' && c <= '9') {
+ _currentLine.deleteChar(0);
+ result = result * 10 + (c - '0');
+ } else {
+ break;
+ }
+ }
+
+ return result;
+}
+
+} // End of namespace MADS
diff --git a/engines/mads/menu_views.h b/engines/mads/menu_views.h
new file mode 100644
index 0000000000..cc5a13006f
--- /dev/null
+++ b/engines/mads/menu_views.h
@@ -0,0 +1,225 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef MADS_MENU_VIEWS_H
+#define MADS_MENU_VIEWS_H
+
+#include "common/scummsys.h"
+#include "mads/dialogs.h"
+#include "mads/game.h"
+#include "mads/msurface.h"
+
+namespace MADS {
+
+class MADSEngine;
+
+class MenuView: public FullScreenDialog {
+protected:
+ bool _breakFlag;
+ bool _redrawFlag;
+ Common::String _filename;
+
+ virtual void doFrame() = 0;
+
+ virtual void display();
+
+ /**
+ * Event handler
+ */
+ virtual bool onEvent(Common::Event &event);
+public:
+ MenuView(MADSEngine *vm);
+
+ virtual ~MenuView() {}
+
+ virtual void show();
+
+ Common::String getResourceName();
+};
+
+struct TextLine {
+ Common::Point _pos;
+ Common::String _line;
+ int _textDisplayIndex;
+};
+
+/**
+ * Scrolling text view
+ */
+class TextView : public MenuView {
+private:
+ static char _resourceName[100];
+
+ bool _animating;
+ Common::Array<TextLine> _textLines;
+ Common::Point _pan;
+ int _panSpeed;
+ MSurface _spareScreens[4];
+ int _scrollCount;
+ int _lineY;
+ uint32 _scrollTimeout;
+ int _panCountdown;
+ int _translationX;
+ Common::File _script;
+ char _currentLine[80];
+ MSurface *_spareScreen;
+ Font *_font;
+private:
+ /**
+ * Load the text resource
+ */
+ void load();
+
+ /**
+ * Process the lines
+ */
+ void processLines();
+
+ /**
+ * Process a command from the script file
+ */
+ void processCommand();
+
+ /**
+ * Process text from the script file
+ */
+ void processText();
+
+ /**
+ * Get a parameter from line
+ */
+ int getParameter(const char **paramP);
+
+ /**
+ * Reset the game palette
+ */
+ void resetPalette();
+protected:
+ virtual void display();
+
+ virtual void doFrame();
+
+ /**
+ * Called when the script is finished
+ */
+ virtual void scriptDone();
+public:
+ /**
+ * Queue the given text resource for display
+ */
+ static void execute(MADSEngine *vm, const Common::String &resName);
+
+ TextView(MADSEngine *vm);
+
+ virtual ~TextView();
+};
+
+enum ResyncMode { NEVER, ALWAYS, BEGINNING };
+
+struct ResourceEntry {
+ Common::String _resourceName;
+ int _fx;
+ bool _soundFlag;
+ bool _bgFlag;
+ bool _showWhiteBars;
+
+ ResourceEntry() {}
+ ResourceEntry(const Common::String &resName, int fx, bool soundFlag,
+ bool bgFlag, bool showWhiteBars) {
+ _resourceName = resName;
+ _fx = fx;
+ _soundFlag = soundFlag;
+ _bgFlag = bgFlag;
+ _showWhiteBars = showWhiteBars;
+ }
+};
+
+struct ResIndexEntry {
+ int _id;
+ int _v;
+ Common::String _resourceName;
+
+ ResIndexEntry() {}
+};
+
+/**
+* Animation cutscene view
+*/
+class AnimationView : public MenuView {
+private:
+ static char _resourceName[100];
+
+ Common::File _script;
+ uint32 _previousUpdate;
+ Common::String _currentLine;
+ bool _soundDriverLoaded;
+ bool _resetPalette;
+ ResyncMode _resyncMode;
+ int _sfx;
+ bool _soundFlag;
+ bool _bgLoadFlag;
+ bool _showWhiteBars;
+ Common::Array<ResourceEntry> _resources;
+ Common::Array<ResIndexEntry> _resIndex;
+ int _v1;
+ int _v2;
+ int _resourceIndex;
+ SceneInfo *_sceneInfo;
+ Animation *_currentAnimation;
+ int _manualFrameNumber;
+ SpriteAsset *_manualSpriteSet;
+ int _manualStartFrame, _manualEndFrame;
+ int _manualFrame2;
+ int _animFrameNumber;
+ bool _nextCyclingActive;
+private:
+ void load();
+
+ void processLines();
+
+ void processCommand();
+
+ int getParameter();
+
+ void loadNextResource();
+protected:
+ virtual void display();
+
+ virtual void doFrame();
+
+ virtual bool onEvent(Common::Event &event);
+
+ virtual void scriptDone();
+public:
+ /**
+ * Queue the given text resource for display
+ */
+ static void execute(MADSEngine *vm, const Common::String &resName);
+
+ AnimationView(MADSEngine *vm);
+
+ virtual ~AnimationView();
+};
+
+} // End of namespace MADS
+
+#endif /* MADS_MENU_VIEWS_H */
diff --git a/engines/mads/messages.cpp b/engines/mads/messages.cpp
index d41696044b..e83b69d210 100644
--- a/engines/mads/messages.cpp
+++ b/engines/mads/messages.cpp
@@ -546,8 +546,7 @@ void TextDisplayList::draw(MSurface *s) {
for (uint idx = 0; idx < size(); ++idx) {
TextDisplay &td = (*this)[idx];
if (td._active && (td._expire >= 0)) {
- Common::Point destPos(td._bounds.left + _vm->_screen._offset.x,
- td._bounds.top + _vm->_screen._offset.y);
+ Common::Point destPos(td._bounds.left, td._bounds.top);
td._font->setColors(0xFF, td._color1, td._color2, 0);
td._font->writeString(s, td._msg, destPos, td._spacing, td._bounds.width());
}
diff --git a/engines/mads/module.mk b/engines/mads/module.mk
index 96353e9ae5..fc04a2f8ba 100644
--- a/engines/mads/module.mk
+++ b/engines/mads/module.mk
@@ -35,6 +35,7 @@ MODULE_OBJS := \
hotspots.o \
inventory.o \
mads.o \
+ menu_views.o \
messages.o \
msurface.o \
palette.o \
diff --git a/engines/mads/msurface.cpp b/engines/mads/msurface.cpp
index 349f4a5f23..39824bac4b 100644
--- a/engines/mads/msurface.cpp
+++ b/engines/mads/msurface.cpp
@@ -87,7 +87,6 @@ void MSurface::drawSprite(const Common::Point &pt, SpriteInfo &info, const Commo
// rectangle is always 0, 0
assert(clipRect.top == 0 && clipRect.left == 0);
- // TODO: Put err* and scaled* into SpriteInfo
int errX = info.hotX * info.scaleX % 100;
int errY = info.hotY * info.scaleY % 100;
int scaledWidth = scaleValue(info.width, info.scaleX, errX);
@@ -160,7 +159,6 @@ void MSurface::drawSprite(const Common::Point &pt, SpriteInfo &info, const Commo
if (status == kStatusDraw && clipY == 0) {
// Draw previously scaled line
- // TODO Implement different drawing types (depth, shadow etc.)
byte *tempDst = dst;
for (int lineX = 0; lineX < scaledWidth; lineX++) {
byte pixel = scaledLineBuf[lineX];
@@ -186,8 +184,6 @@ void MSurface::drawSprite(const Common::Point &pt, SpriteInfo &info, const Commo
}
dst += pitch;
heightAmt--;
- // TODO depth etc.
- //depthAddress += Destination -> Width;
errY += 100;
if (errY >= 0)
@@ -266,11 +262,11 @@ void MSurface::copyFrom(MSurface *src, const Common::Point &destPos, int depth,
int highestDim = MAX(frameWidth, frameHeight);
bool lineDist[MADS_SCREEN_WIDTH];
- int distIndex = 0;
int distXCount = 0, distYCount = 0;
if (scale != -1) {
int distCtr = 0;
+ int distIndex = 0;
do {
distCtr += scale;
if (distCtr < 100) {
@@ -356,9 +352,10 @@ void MSurface::copyFrom(MSurface *src, const Common::Point &destPos, int depth,
if (widthAmount > 0)
spriteWidth -= widthAmount;
- int spriteRight = spriteLeft + spriteWidth;
if (spriteWidth <= 0)
return;
+
+ int spriteRight = spriteLeft + spriteWidth;
if (flipped) {
destX += distXCount - 1;
spriteLeft = -(distXCount - spriteRight);
diff --git a/engines/mads/msurface.h b/engines/mads/msurface.h
index cd6bde1271..ebfb1f437a 100644
--- a/engines/mads/msurface.h
+++ b/engines/mads/msurface.h
@@ -51,10 +51,9 @@ struct SpriteInfo {
* MADS graphics surface
*/
class MSurface : public Graphics::Surface {
-private:
- bool _freeFlag;
protected:
static MADSEngine *_vm;
+ bool _freeFlag;
public:
/**
* Sets the engine refrence used all surfaces
@@ -65,6 +64,11 @@ public:
* Helper method for calculating new dimensions when scaling a sprite
*/
static int scaleValue(int value, int scale, int err);
+
+ /**
+ * Base method for descendents to load their contents
+ */
+ virtual void load(const Common::String &resName) {}
public:
/**
* Basic constructor
diff --git a/engines/mads/nebular/dialogs_nebular.cpp b/engines/mads/nebular/dialogs_nebular.cpp
index f3eddc3fbb..f5355517bd 100644
--- a/engines/mads/nebular/dialogs_nebular.cpp
+++ b/engines/mads/nebular/dialogs_nebular.cpp
@@ -313,6 +313,18 @@ void DialogsNebular::showDialog() {
delete dlg;
break;
}
+ case DIALOG_TEXTVIEW: {
+ TextView *dlg = new RexTextView(_vm);
+ dlg->show();
+ delete dlg;
+ break;
+ }
+ case DIALOG_ANIMVIEW: {
+ AnimationView *dlg = new RexAnimationView(_vm);
+ dlg->show();
+ delete dlg;
+ break;
+ }
default:
break;
}
@@ -334,7 +346,6 @@ void DialogsNebular::showScummVMSaveDialog() {
}
scene->_spriteSlots.reset();
- _vm->_screen._offset.y = 0;
scene->loadScene(scene->_currentSceneId, game._aaName, true);
scene->_userInterface.noInventoryAnim();
game._scene.drawElements(kTransitionFadeIn, false);
@@ -542,60 +553,6 @@ void PictureDialog::restore() {
/*------------------------------------------------------------------------*/
-FullScreenDialog::FullScreenDialog(MADSEngine *vm) : _vm(vm) {
- _screenId = 990;
- _palFlag = true;
-}
-
-FullScreenDialog::~FullScreenDialog() {
- _vm->_screen._offset.y = 0;
-}
-
-void FullScreenDialog::display() {
- Game &game = *_vm->_game;
- Scene &scene = game._scene;
-
- int nextSceneId = scene._nextSceneId;
- int currentSceneId = scene._currentSceneId;
- int priorSceneId = scene._priorSceneId;
-
- scene.loadScene(_screenId, game._aaName, _palFlag);
-
- scene._priorSceneId = priorSceneId;
- scene._currentSceneId = currentSceneId;
- scene._nextSceneId = nextSceneId;
-
- _vm->_screen._offset.y = 22;
- _vm->_events->initVars();
- game._kernelMode = KERNEL_ROOM_INIT;
-
- byte pal[768];
- if (_vm->_screenFade) {
- Common::fill(&pal[0], &pal[PALETTE_SIZE], 0);
- _vm->_palette->setFullPalette(pal);
- } else {
- _vm->_palette->getFullPalette(pal);
- _vm->_palette->fadeOut(pal, nullptr, 0, PALETTE_COUNT, 0, 1, 1, 16);
- }
-
- _vm->_screen.empty();
- _vm->_screen.hLine(0, 20, MADS_SCREEN_WIDTH, 2);
- _vm->_screen.hLine(0, 179, MADS_SCREEN_WIDTH, 2);
- game._scene._spriteSlots.fullRefresh();
-
- game._fx = _vm->_screenFade == SCREEN_FADE_SMOOTH ? kTransitionFadeIn : kCenterVertTransition;
- game._trigger = 0;
-
- _vm->_palette->setEntry(10, 0, 63, 0);
- _vm->_palette->setEntry(11, 0, 45, 0);
- _vm->_palette->setEntry(12, 63, 63, 0);
- _vm->_palette->setEntry(13, 45, 45, 0);
- _vm->_palette->setEntry(14, 63, 63, 63);
- _vm->_palette->setEntry(15, 45, 45, 45);
-}
-
-/*------------------------------------------------------------------------*/
-
GameDialog::DialogLine::DialogLine() {
_active = true;
_state = DLGSTATE_UNSELECTED;
@@ -637,6 +594,9 @@ GameDialog::GameDialog(MADSEngine *vm) : FullScreenDialog(vm) {
_vm->_events->waitCursor();
scene.clearVocab();
scene._dynamicHotspots.clear();
+ // Clear scene sprites and objects
+ scene._spriteSlots.reset();
+ _vm->_game->_screenObjects.clear();
_vm->_dialogs->_defaultPosition = Common::Point(-1, -1);
_menuSpritesIndex = 0;
}
@@ -644,6 +604,14 @@ GameDialog::GameDialog(MADSEngine *vm) : FullScreenDialog(vm) {
void GameDialog::display() {
FullScreenDialog::display();
+ Palette &palette = *_vm->_palette;
+ palette.setEntry(10, 0, 63, 0);
+ palette.setEntry(11, 0, 45, 0);
+ palette.setEntry(12, 63, 63, 0);
+ palette.setEntry(13, 45, 45, 0);
+ palette.setEntry(14, 63, 63, 63);
+ palette.setEntry(15, 45, 45, 45);
+
Scene &scene = _vm->_game->_scene;
SpriteAsset *menuSprites = new SpriteAsset(_vm, "*MENU", 0);
_menuSpritesIndex = scene._sprites.add(menuSprites);
@@ -655,7 +623,7 @@ void GameDialog::display() {
}
GameDialog::~GameDialog() {
- _vm->_screen._offset.y = 0;
+ _vm->_screen.resetClipBounds();
}
void GameDialog::clearLines() {
@@ -856,10 +824,11 @@ void GameDialog::handleEvents() {
_vm->_events->pollEvents();
// Scan for objects in the dialog
- int objIndex = screenObjects.scan(events.currentPos() - _vm->_screen._offset, LAYER_GUI);
+ Common::Point mousePos = events.currentPos() - Common::Point(0, DIALOG_TOP);
+ int objIndex = screenObjects.scan(mousePos, LAYER_GUI);
if (_movedFlag) {
- int yp = events.currentPos().y - _vm->_screen._offset.y;
+ int yp = mousePos.y;
if (yp < screenObjects[1]._bounds.top) {
if (!events._mouseReleased)
_lines[1]._state = DLGSTATE_SELECTED;
@@ -939,7 +908,7 @@ void GameDialog::refreshText() {
}
if (!skipFlag) {
- _lines[i]._textDisplayIndex = scene._textDisplay.add(_lines[i]._pos.x, _lines[i]._pos.y,
+ _lines[i]._textDisplayIndex = scene._textDisplay.add(_lines[i]._pos.x, _lines[i]._pos.y,
fontColor, _lines[i]._widthAdjust, _lines[i]._msg, _lines[i]._font);
}
}
@@ -950,6 +919,7 @@ void GameDialog::refreshText() {
DifficultyDialog::DifficultyDialog(MADSEngine *vm) : GameDialog(vm) {
setLines();
+ _vm->_palette->resetGamePalette(18, 10);
}
void DifficultyDialog::setLines() {
@@ -1094,6 +1064,14 @@ void OptionsDialog::display() {
void OptionsDialog::show() {
Nebular::GameNebular &game = *(Nebular::GameNebular *)_vm->_game;
+
+ // Previous options, restored when cancel is selected
+ bool prevEasyMouse = _vm->_easyMouse;
+ bool prevInvObjectsAnimated = _vm->_invObjectsAnimated;
+ bool prevTextWindowStill = _vm->_textWindowStill;
+ ScreenFade prevScreenFade = _vm->_screenFade;
+ StoryMode prevStoryMode = game._storyMode;
+
do {
_selectedLine = 0;
GameDialog::show();
@@ -1138,10 +1116,15 @@ void OptionsDialog::show() {
switch (_selectedLine) {
case 8: // Done
- // TODO: Copy from temporary config
+ // New options will be applied
break;
case 9: // Cancel
- // TODO: Ignore all changes to temporary config
+ // Revert all options from the saved ones
+ _vm->_easyMouse = prevEasyMouse;
+ _vm->_invObjectsAnimated = prevInvObjectsAnimated;
+ _vm->_textWindowStill = prevTextWindowStill;
+ _vm->_screenFade = prevScreenFade;
+ game._storyMode = prevStoryMode;
break;
default:
break;
diff --git a/engines/mads/nebular/dialogs_nebular.h b/engines/mads/nebular/dialogs_nebular.h
index 1468db38c8..5dbe4da6f0 100644
--- a/engines/mads/nebular/dialogs_nebular.h
+++ b/engines/mads/nebular/dialogs_nebular.h
@@ -107,36 +107,6 @@ enum DialogTextAlign { ALIGN_NONE = 0, ALIGN_CENTER = -1, ALIGN_AT_CENTER = -2,
enum DialogState { DLGSTATE_UNSELECTED = 0, DLGSTATE_SELECTED = 1, DLGSTATE_FOCUSED = 2 };
-class FullScreenDialog: public EventTarget {
-protected:
- /**
- * Engine reference
- */
- MADSEngine *_vm;
-
- /**
- * Screen/scene to show background from
- */
- int _screenId;
-
- /**
- * Flag for palette initialization
- */
- bool _palFlag;
-
- /**
- * Handles displaying the screen background and dialog
- */
- virtual void display();
-public:
- /**
- * Constructor
- */
- FullScreenDialog(MADSEngine *vm);
-
- virtual ~FullScreenDialog();
-};
-
class GameDialog: public FullScreenDialog {
struct DialogLine {
bool _active;
@@ -146,7 +116,7 @@ class GameDialog: public FullScreenDialog {
Common::String _msg;
Font *_font;
int _widthAdjust;
-
+
DialogLine();
DialogLine(const Common::String &s);
};
@@ -160,7 +130,7 @@ protected:
int _menuSpritesIndex;
int _lineIndex;
int _textLineCount;
-
+
/**
* Display the dialog
*/
diff --git a/engines/mads/nebular/game_nebular.cpp b/engines/mads/nebular/game_nebular.cpp
index 902f42507a..fd669bc5cf 100644
--- a/engines/mads/nebular/game_nebular.cpp
+++ b/engines/mads/nebular/game_nebular.cpp
@@ -27,6 +27,7 @@
#include "mads/game.h"
#include "mads/screen.h"
#include "mads/msurface.h"
+#include "mads/menu_views.h"
#include "mads/nebular/game_nebular.h"
#include "mads/nebular/dialogs_nebular.h"
#include "mads/nebular/globals_nebular.h"
@@ -309,6 +310,31 @@ void GameNebular::setSectionHandler() {
}
void GameNebular::checkShowDialog() {
+ // Handling to start endgame sequences if the win/lose type has been set
+ switch (_winStatus) {
+ case 1:
+ // No shields failure ending
+ AnimationView::execute(_vm, "rexend1");
+ break;
+ case 2:
+ // Shields, but no targetting failure ending
+ AnimationView::execute(_vm, "rexend2");
+ break;
+ case 3:
+ // Completed game successfully, so activate quotes item on the main menu
+ ConfMan.setBool("ShowQuotes", true);
+ ConfMan.flushToDisk();
+
+ AnimationView::execute(_vm, "rexend3");
+ break;
+ case 4:
+ // Decompression ending
+ TextView::execute(_vm, "ending4");
+ break;
+ }
+ _winStatus = 0;
+
+ // Loop for showing dialogs, if any need to be shown
if (_vm->_dialogs->_pendingDialog && _player._stepEnabled && !_globals[kCopyProtectFailed]) {
_player.releasePlayerSprites();
@@ -599,7 +625,7 @@ void GameNebular::doObjectAction() {
_objects.addToInventory(OBJ_DURAFAIL_CELLS);
if (_difficulty == DIFFICULTY_HARD) {
dialogs.showItem(OBJ_DURAFAIL_CELLS, 416);
- }
+ }
_globals[kHandsetCellStatus] = 0;
break;
case 3:
diff --git a/engines/mads/nebular/game_nebular.h b/engines/mads/nebular/game_nebular.h
index da607d47ee..efa21a2e73 100644
--- a/engines/mads/nebular/game_nebular.h
+++ b/engines/mads/nebular/game_nebular.h
@@ -133,18 +133,16 @@ public:
virtual void synchronize(Common::Serializer &s, bool phase1);
};
-
+// Section handlers aren't needed in ScummVM implementation
class Section1Handler : public SectionHandler {
public:
Section1Handler(MADSEngine *vm) : SectionHandler(vm) {}
- // TODO: Properly implement handler methods
virtual void preLoadSection() {}
virtual void sectionPtr2() {}
virtual void postLoadSection() {}
};
-// TODO: Properly implement handler classes
typedef Section1Handler Section2Handler;
typedef Section1Handler Section3Handler;
typedef Section1Handler Section4Handler;
diff --git a/engines/mads/nebular/menu_nebular.cpp b/engines/mads/nebular/menu_nebular.cpp
index 98eb669616..28de4e5650 100644
--- a/engines/mads/nebular/menu_nebular.cpp
+++ b/engines/mads/nebular/menu_nebular.cpp
@@ -21,9 +21,12 @@
*/
#include "common/scummsys.h"
+#include "common/config-manager.h"
#include "mads/game.h"
#include "mads/mads.h"
+#include "mads/menu_views.h"
#include "mads/resources.h"
+#include "mads/scene.h"
#include "mads/screen.h"
#include "mads/nebular/menu_nebular.h"
@@ -35,44 +38,6 @@ namespace Nebular {
#define MADS_MENU_Y ((MADS_SCREEN_HEIGHT - MADS_SCENE_HEIGHT) / 2)
#define MADS_MENU_ANIM_DELAY 70
-MenuView::MenuView(MADSEngine *vm) : FullScreenDialog(vm) {
- _breakFlag = false;
- _redrawFlag = true;
- _palFlag = false;
-}
-
-void MenuView::show() {
- Scene &scene = _vm->_game->_scene;
- EventsManager &events = *_vm->_events;
- display();
-
- events.setEventTarget(this);
- events.hideCursor();
-
- while (!_breakFlag && !_vm->shouldQuit()) {
- if (_redrawFlag) {
- scene.drawElements(_vm->_game->_fx, _vm->_game->_fx);
-
- _vm->_screen.copyRectToScreen(Common::Rect(0, 0, 320, 200));
- _redrawFlag = false;
- }
-
- _vm->_events->waitForNextFrame();
- _vm->_game->_fx = kTransitionNone;
- doFrame();
- }
-
- events.setEventTarget(nullptr);
-}
-
-void MenuView::display() {
- _vm->_palette->resetGamePalette(4, 8);
-
- FullScreenDialog::display();
-}
-
-/*------------------------------------------------------------------------*/
-
MainMenu::MainMenu(MADSEngine *vm): MenuView(vm) {
Common::fill(&_menuItems[0], &_menuItems[7], (SpriteAsset *)nullptr);
Common::fill(&_menuItemIndexes[0], &_menuItemIndexes[7], -1);
@@ -83,12 +48,23 @@ MainMenu::MainMenu(MADSEngine *vm): MenuView(vm) {
_highlightedIndex = -1;
_selectedIndex = -1;
_buttonDown = false;
-
+
for (int i = 0; i < 7; ++i)
_menuItems[i] = nullptr;
}
MainMenu::~MainMenu() {
+ Scene &scene = _vm->_game->_scene;
+ for (int i = 0; i < 7; ++i) {
+ if (_menuItemIndexes[i] != -1)
+ scene._sprites.remove(_menuItemIndexes[i]);
+ }
+
+ scene._spriteSlots.reset();
+}
+
+bool MainMenu::shouldShowQuotes() {
+ return ConfMan.hasKey("ShowQuotes") && ConfMan.getBool("ShowQuotes");
}
void MainMenu::display() {
@@ -107,10 +83,10 @@ void MainMenu::display() {
// Register the menu item area in the screen objects
MSprite *frame0 = _menuItems[i]->getFrame(0);
Common::Point pt(frame0->_offset.x - (frame0->w / 2),
- frame0->_offset.y - frame0->h + _vm->_screen._offset.y);
+ frame0->_offset.y - frame0->h);
screenObjects.add(
- Common::Rect(pt.x, pt.y, pt.x + frame0->w, pt.y + frame0->h),
- LAYER_GUI, CAT_COMMAND, i);
+ Common::Rect(pt.x, pt.y + DIALOG_TOP, pt.x + frame0->w,
+ pt.y + frame0->h + DIALOG_TOP), LAYER_GUI, CAT_COMMAND, i);
}
// Set the cursor for when it's shown
@@ -130,6 +106,9 @@ void MainMenu::doFrame() {
handleAction((MADSGameAction)_selectedIndex);
} else {
for (_menuItemIndex = 0; _menuItemIndex < 6; ++_menuItemIndex) {
+ if (_menuItemIndex == 4 && !shouldShowQuotes())
+ continue;
+
if (_menuItemIndex != _selectedIndex) {
addSpriteSlot();
}
@@ -147,8 +126,11 @@ void MainMenu::doFrame() {
// If the user has chosen to skip the animation, show the full menu immediately
if (_skipFlag && _menuItemIndex >= 0) {
- // Quickly loop through all the menu items to display each's final frame
+ // Quickly loop through all the menu items to display each's final frame
for (; _menuItemIndex < 6; ++_menuItemIndex) {
+ if (_menuItemIndex == 4 && !shouldShowQuotes())
+ continue;
+
// Draw the final frame of the menuitem
_frameIndex = 0;
addSpriteSlot();
@@ -158,9 +140,12 @@ void MainMenu::doFrame() {
} else {
if ((_menuItemIndex == -1) || (_frameIndex == 0)) {
if (++_menuItemIndex == 6) {
+
// Reached end of display animation
_vm->_events->showCursor();
return;
+ } else if (_menuItemIndex == 4 && !shouldShowQuotes()) {
+ ++_menuItemIndex;
}
_frameIndex = _menuItems[_menuItemIndex]->getCount() - 1;
@@ -176,7 +161,7 @@ void MainMenu::doFrame() {
void MainMenu::addSpriteSlot() {
Scene &scene = _vm->_game->_scene;
SpriteSlots &spriteSlots = scene._spriteSlots;
-
+
int seqIndex = (_menuItemIndex < 6) ? _menuItemIndex : _frameIndex;
spriteSlots.deleteTimer(seqIndex);
@@ -270,7 +255,7 @@ bool MainMenu::onEvent(Common::Event &event) {
}
return true;
- case Common::EVENT_MOUSEMOVE:
+ case Common::EVENT_MOUSEMOVE:
if (_buttonDown) {
int menuIndex = getHighlightedItem(event.mouse);
if (menuIndex != _highlightedIndex) {
@@ -302,7 +287,7 @@ bool MainMenu::onEvent(Common::Event &event) {
default:
break;
}
-
+
return false;
}
@@ -332,13 +317,13 @@ void MainMenu::handleAction(MADSGameAction action) {
break;
case RESUME_GAME:
- // The original resumed the most recently saved game. Instead,
+ // The original resumed the most recently saved game. Instead,
// just show the load game scren
_vm->_dialogs->_pendingDialog = DIALOG_RESTORE;
return;
case SHOW_INTRO:
- AnimationView::execute(_vm, "@rexopen");
+ AnimationView::execute(_vm, "rexopen");
break;
case CREDITS:
@@ -369,12 +354,14 @@ void AdvertView::show() {
uint32 expiryTime = g_system->getMillis() + 10 * 1000;
_vm->_palette->resetGamePalette(4, 8);
-
+
// Load the advert background onto the screen
SceneInfo *sceneInfo = SceneInfo::init(_vm);
sceneInfo->load(screenId, 0, Common::String(), 0, _vm->_game->_scene._depthSurface,
_vm->_screen);
_vm->_screen.copyRectToScreen(_vm->_screen.getBounds());
+ _vm->_palette->setFullPalette(_vm->_palette->_mainPalette);
+
delete sceneInfo;
EventsManager &events = *_vm->_events;
@@ -390,6 +377,7 @@ void AdvertView::show() {
events.setEventTarget(nullptr);
_vm->quitGame();
+ events.pollEvents();
}
bool AdvertView::onEvent(Common::Event &event) {
@@ -403,375 +391,16 @@ bool AdvertView::onEvent(Common::Event &event) {
/*------------------------------------------------------------------------*/
-char TextView::_resourceName[100];
-#define TEXTVIEW_LINE_SPACING 2
-#define TEXT_ANIMATION_DELAY 100
-#define TV_NUM_FADE_STEPS 40
-#define TV_FADE_DELAY_MILLI 50
-
-void TextView::execute(MADSEngine *vm, const Common::String &resName) {
- assert(resName.size() < 100);
- strncpy(_resourceName, resName.c_str(), sizeof(_resourceName));
- vm->_dialogs->_pendingDialog = DIALOG_TEXTVIEW;
-}
-
-TextView::TextView(MADSEngine *vm) : MenuView(vm),
- _textSurface(MADS_SCREEN_WIDTH, MADS_SCREEN_HEIGHT + _vm->_font->getHeight()) {
- _animating = false;
- _panSpeed = 0;
- Common::fill(&_spareScreens[0], &_spareScreens[10], 0);
- _spareScreen = nullptr;
- _scrollCount = 0;
- _lineY = -1;
- _scrollTimeout = 0;
- _panCountdown = 0;
- _translationX = 0;
-}
-
-TextView::~TextView() {
- delete _spareScreen;
-}
-
-void TextView::load() {
- if (!_script.open(_resourceName))
- error("Could not open resource %s", _resourceName);
-
- processLines();
-}
-
-void TextView::processLines() {
- if (_script.eos())
- error("Attempted to read past end of response file");
-
- while (!_script.eos()) {
- _script.readLine(_currentLine, 79);
-
- // Commented out line, so go loop for another
- if (_currentLine[0] == '#')
- continue;
-
- // Process the line
- char *cStart = strchr(_currentLine, '[');
- if (cStart) {
- while (cStart) {
- // Loop for possible multiple commands on one line
- char *cEnd = strchr(_currentLine, ']');
- if (!cEnd)
- error("Unterminated command '%s' in response file", _currentLine);
-
- *cEnd = '\0';
- processCommand();
-
- // Copy rest of line (if any) to start of buffer
- strncpy(_currentLine, cEnd + 1, sizeof(_currentLine));
-
- cStart = strchr(_currentLine, '[');
- }
-
- if (_currentLine[0]) {
- processText();
- break;
- }
-
- } else {
- processText();
- break;
- }
- }
-}
-
-void TextView::processCommand() {
- Scene &scene = _vm->_game->_scene;
- Common::String scriptLine(_currentLine + 1);
- scriptLine.toUppercase();
- const char *paramP;
- const char *commandStr = scriptLine.c_str();
-
- if (!strncmp(commandStr, "BACKGROUND", 10)) {
- // Set the background
- paramP = commandStr + 10;
- int screenId = getParameter(&paramP);
-
- SceneInfo *sceneInfo = SceneInfo::init(_vm);
- sceneInfo->load(screenId, 0, Common::String(), 0, scene._depthSurface,
- scene._backgroundSurface);
-
- } else if (!strncmp(commandStr, "GO", 2)) {
- _animating = true;
-
- // Grab what the final palete will be
- byte destPalette[PALETTE_SIZE];
- _vm->_palette->grabPalette(destPalette, 0, 256);
-
- // Copy the loaded background, if any, to the view surface
- //int yp = 22;
- //scene._backgroundSurface.copyTo(this, 0, 22);
-
- // Handle fade-in
- //byte srcPalette[768];
- //Common::fill(&srcPalette[0], &srcPalette[PALETTE_SIZE], 0);
- //_vm->_palette->fadeIn(srcPalette, destPalette, 0, PALETTE_COUNT, 0, 0,
- // TV_FADE_DELAY_MILLI, TV_NUM_FADE_STEPS);
- _vm->_game->_fx = kTransitionFadeIn;
-
- } else if (!strncmp(commandStr, "PAN", 3)) {
- // Set panning values
- paramP = commandStr + 3;
- int panX = getParameter(&paramP);
- int panY = getParameter(&paramP);
- int panSpeed = getParameter(&paramP);
-
- if ((panX != 0) || (panY != 0)) {
- _pan = Common::Point(panX, panY);
- _panSpeed = panSpeed;
- }
-
- } else if (!strncmp(commandStr, "DRIVER", 6)) {
- // Set the driver to use
- paramP = commandStr + 6;
- int driverNum = getParameter(&paramP);
- _vm->_sound->init(driverNum);
-
- } else if (!strncmp(commandStr, "SOUND", 5)) {
- // Set sound number
- paramP = commandStr + 5;
- int soundId = getParameter(&paramP);
- _vm->_sound->command(soundId);
-
- } else if (!strncmp(commandStr, "COLOR", 5) && ((commandStr[5] == '0') ||
- (commandStr[5] == '1'))) {
- // Set the text colors
- int index = commandStr[5] - '0';
- paramP = commandStr + 6;
-
- byte palEntry[3];
- palEntry[0] = getParameter(&paramP) << 2;
- palEntry[1] = getParameter(&paramP) << 2;
- palEntry[2] = getParameter(&paramP) << 2;
- _vm->_palette->setPalette(&palEntry[0], 5 + index, 1);
-
- } else if (!strncmp(commandStr, "SPARE", 5)) {
- // Sets a secondary background number that can be later switched in with a PAGE command
- paramP = commandStr + 6;
- int spareIndex = commandStr[5] - '0';
- if ((spareIndex >= 0) && (spareIndex <= 9)) {
- int screenId = getParameter(&paramP);
-
- _spareScreens[spareIndex] = screenId;
- }
-
- } else if (!strncmp(commandStr, "PAGE", 4)) {
- // Signals to change to a previous specified secondary background
- paramP = commandStr + 4;
- int spareIndex = getParameter(&paramP);
-
- // Only allow background switches if one isn't currently in progress
- if (!_spareScreen && (_spareScreens[spareIndex] != 0)) {
- _spareScreen = new MSurface(MADS_SCREEN_WIDTH, MADS_SCREEN_HEIGHT);
- //_spareScreen->loadBackground(_spareScreens[spareIndex], &_bgSpare);
-
- _translationX = 0;
- }
-
- } else {
- error("Unknown response command: '%s'", commandStr);
- }
-}
-
-int TextView::getParameter(const char **paramP) {
- if ((**paramP != '=') && (**paramP != ','))
- return 0;
-
- int result = 0;
- ++*paramP;
- while ((**paramP >= '0') && (**paramP <= '9')) {
- result = result * 10 + (**paramP - '0');
- ++*paramP;
- }
-
- return result;
-}
-
-void TextView::processText() {
- int lineWidth, xStart;
-
- if (!strcmp(_currentLine, "***")) {
- // Special signifier for end of script
- _scrollCount = _vm->_font->getHeight() * 13;
- _lineY = -1;
- return;
- }
-
- _lineY = 0;
-
- // Lines are always centered, except if line contains a '@', in which case the
- // '@' marks the position that must be horizontally centered
- char *centerP = strchr(_currentLine, '@');
- if (centerP) {
- *centerP = '\0';
- xStart = (MADS_SCREEN_WIDTH / 2) - _vm->_font->getWidth(_currentLine);
-
- // Delete the @ character and shift back the remainder of the string
- char *p = centerP + 1;
- if (*p == ' ') ++p;
- strcpy(centerP, p);
-
- } else {
- lineWidth = _vm->_font->getWidth(_currentLine);
- xStart = (MADS_SCREEN_WIDTH - lineWidth) / 2;
- }
-
- // Copy the text line onto the bottom of the textSurface surface, which will allow it
- // to gradually scroll onto the screen
- int yp = _textSurface.h - _vm->_font->getHeight() - TEXTVIEW_LINE_SPACING;
- _textSurface.fillRect(Common::Rect(0, yp, MADS_SCREEN_WIDTH, _textSurface.h), 0);
- _vm->_font->writeString(&_textSurface, _currentLine, Common::Point(xStart, yp));
-}
-
-/*------------------------------------------------------------------------*/
-
-char AnimationView::_resourceName[100];
-
-void AnimationView::execute(MADSEngine *vm, const Common::String &resName) {
- assert(resName.size() < 100);
- strncpy(_resourceName, resName.c_str(), sizeof(_resourceName));
- vm->_dialogs->_pendingDialog = DIALOG_ANIMVIEW;
-}
-
-AnimationView::AnimationView(MADSEngine *vm) : MenuView(vm) {
- _soundDriverLoaded = false;
- _previousUpdate = 0;
-}
-
-void AnimationView::load() {
- Common::String resName(_resourceName);
- if (!resName.hasSuffix("."))
- resName += ".res";
-
- if (!_script.open(resName))
- error("Could not open resource %s", resName.c_str());
-
- processLines();
-}
+void RexAnimationView::scriptDone() {
+ AnimationView::scriptDone();
-bool AnimationView::onEvent(Common::Event &event) {
- // Wait for the Escape key or a mouse press
- if (((event.type == Common::EVENT_KEYDOWN) && (event.kbd.keycode == Common::KEYCODE_ESCAPE)) ||
- (event.type == Common::EVENT_RBUTTONUP)) {
- scriptDone();
- return true;
- }
-
- return false;
-}
-
-void AnimationView::doFrame() {
- Scene &scene = _vm->_game->_scene;
- int bgNumber = 0;
-
- // Only update state if wait period has expired
- if (_previousUpdate > 0) {
- if (g_system->getMillis() - _previousUpdate < 3000) {
- return;
- } else {
- // time for an update
- _previousUpdate = g_system->getMillis();
- }
- } else {
- _previousUpdate = g_system->getMillis();
- return;
- }
-
- char bgFile[10];
- strncpy(bgFile, _currentFile, 5);
- bgFile[0] = bgFile[2];
- bgFile[1] = bgFile[3];
- bgFile[2] = bgFile[4];
- bgFile[3] = '\0';
- bgNumber = atoi(bgFile);
- sprintf(bgFile, "rm%i.art", bgNumber);
-
- // Not all scenes have a background. If there is one, refresh it
- if (Common::File::exists(bgFile)) {
- _vm->_palette->resetGamePalette(4, 8);
- SceneInfo *sceneInfo = SceneInfo::init(_vm);
- sceneInfo->load(bgNumber, 0, Common::String(), 0, scene._depthSurface,
- scene._backgroundSurface);
- }
-
- // Read next line
- processLines();
-}
-
-void AnimationView::scriptDone() {
- _breakFlag = true;
- _vm->_dialogs->_pendingDialog = DIALOG_MAIN_MENU;
-}
-
-void AnimationView::processLines() {
- if (_script.eos()) {
- // end of script, end animation
- scriptDone();
- return;
- }
-
- while (!_script.eos()) {
- _script.readLine(_currentLine, 79);
-
- // Process the line
- char *cStart = strchr(_currentLine, '-');
- if (cStart) {
- while (cStart) {
- // Loop for possible multiple commands on one line
- char *cEnd = strchr(_currentLine, ' ');
- if (!cEnd)
- error("Unterminated command '%s' in response file", _currentLine);
-
- *cEnd = '\0';
- processCommand();
-
- // Copy rest of line (if any) to start of buffer
- // Don't use strcpy() here, because if the
- // rest of the line is the longer of the two
- // strings, the memory areas will overlap.
- memmove(_currentLine, cEnd + 1, strlen(cEnd + 1) + 1);
-
- cStart = strchr(_currentLine, '-');
- }
-
- if (_currentLine[0]) {
- sprintf(_currentFile, "%s", _currentLine);
- //printf("File: %s\n", _currentLine);
- break;
- }
-
- } else {
- sprintf(_currentFile, "%s", _currentLine);
- warning("File: %s\n", _currentLine);
- break;
- }
- }
-}
-
-void AnimationView::processCommand() {
- Common::String commandLine(_currentLine + 1);
- commandLine.toUppercase();
- const char *commandStr = commandLine.c_str();
- const char *param = commandStr;
-
- if (!strncmp(commandStr, "X", 1)) {
- //printf("X ");
- } else if (!strncmp(commandStr, "W", 1)) {
- //printf("W ");
- } else if (!strncmp(commandStr, "R", 1)) {
- param = param + 2;
- //printf("R:%s ", param);
- } else if (!strncmp(commandStr, "O", 1)) {
- // Set the transition effect
- param = param + 2;
- _vm->_game->_fx = (ScreenTransition)atoi(param);
- } else {
- error("Unknown response command: '%s'", commandStr);
+ Common::String s = getResourceName();
+ if (s == "rexend1") {
+ TextView::execute(_vm, "ending1");
+ } else if (s == "rexend2") {
+ TextView::execute(_vm, "ending2");
+ } else if (s == "rexend3") {
+ TextView::execute(_vm, "credits");
}
}
diff --git a/engines/mads/nebular/menu_nebular.h b/engines/mads/nebular/menu_nebular.h
index 6e877a8a24..77b8b6fc6e 100644
--- a/engines/mads/nebular/menu_nebular.h
+++ b/engines/mads/nebular/menu_nebular.h
@@ -25,6 +25,7 @@
#include "common/scummsys.h"
#include "mads/game.h"
+#include "mads/menu_views.h"
#include "mads/msurface.h"
#include "mads/nebular/dialogs_nebular.h"
@@ -36,22 +37,6 @@ namespace Nebular {
enum MADSGameAction { START_GAME, RESUME_GAME, SHOW_INTRO, CREDITS, QUOTES, EXIT };
-class MenuView: public FullScreenDialog {
-protected:
- bool _breakFlag;
- bool _redrawFlag;
-
- virtual void doFrame() = 0;
-
- virtual void display();
-public:
- MenuView(MADSEngine *vm);
-
- virtual ~MenuView() {}
-
- virtual void show();
-};
-
class MainMenu: public MenuView {
private:
SpriteAsset *_menuItems[7];
@@ -95,6 +80,8 @@ private:
* Add a sprite slot for the current menuitem frame
*/
void addSpriteSlot();
+
+ bool shouldShowQuotes();
protected:
/**
* Display the menu
@@ -143,95 +130,16 @@ public:
void show();
};
-/**
- * Scrolling text view
- */
-class TextView : public MenuView {
-private:
- static char _resourceName[100];
-
- bool _animating;
- Common::Point _pan;
- int _panSpeed;
- int _spareScreens[10];
- int _scrollCount;
- int _lineY;
- uint32 _scrollTimeout;
- int _panCountdown;
- int _translationX;
- Common::File _script;
- char _currentLine[80];
- MSurface _textSurface;
- MSurface *_spareScreen;
-private:
- /**
- * Load the text resource
- */
- void load();
-
- /**
- * Process the lines
- */
- void processLines();
-
- /**
- * Process a command from the script file
- */
- void processCommand();
-
- /**
- * Process text from the script file
- */
- void processText();
-
- /**
- * Get a parameter from line
- */
- int getParameter(const char **paramP);
+class RexAnimationView : public AnimationView {
+protected:
+ virtual void scriptDone();
public:
- /**
- * Queue the given text resource for display
- */
- static void execute(MADSEngine *vm, const Common::String &resName);
-
- TextView(MADSEngine *vm);
-
- virtual ~TextView();
+ RexAnimationView(MADSEngine *vm) : AnimationView(vm) {}
};
-/**
-* Animation cutscene view
-*/
-class AnimationView : public MenuView {
-private:
- static char _resourceName[100];
-
- Common::File _script;
- uint32 _previousUpdate;
- char _currentLine[80];
- char _currentFile[10];
- bool _soundDriverLoaded;
-private:
- void load();
-
- void processLines();
-
- void processCommand();
-
- void scriptDone();
-
- void doFrame();
-protected:
- virtual bool onEvent(Common::Event &event);
+class RexTextView : public TextView {
public:
- /**
- * Queue the given text resource for display
- */
- static void execute(MADSEngine *vm, const Common::String &resName);
-
- AnimationView(MADSEngine *vm);
-
- virtual ~AnimationView() {}
+ RexTextView(MADSEngine *vm) : TextView(vm) {}
};
} // End of namespace Nebular
diff --git a/engines/mads/nebular/nebular_scenes.cpp b/engines/mads/nebular/nebular_scenes.cpp
index c71512ed4c..b5e2491624 100644
--- a/engines/mads/nebular/nebular_scenes.cpp
+++ b/engines/mads/nebular/nebular_scenes.cpp
@@ -331,7 +331,7 @@ void SceneInfoNebular::loadCodes(MSurface &depthSurface, Common::SeekableReadStr
byte runValue = stream->readByte();
// Write out the run length
- Common::fill(destP, destP + runLength, runValue);
+ Common::fill(destP, MIN(endP, destP + runLength), runValue);
destP += runLength;
// Get the next run length
diff --git a/engines/mads/nebular/nebular_scenes5.cpp b/engines/mads/nebular/nebular_scenes5.cpp
index 5a67d1541f..66d8294fc6 100644
--- a/engines/mads/nebular/nebular_scenes5.cpp
+++ b/engines/mads/nebular/nebular_scenes5.cpp
@@ -2847,8 +2847,6 @@ void Scene551::actions() {
_vm->_dialogs->show(55113);
else if (_action.isAction(VERB_LOOK, NOUN_TELEPORTER))
_vm->_dialogs->show(55114);
- else if (_action.isAction(VERB_LOOK, NOUN_BUILDING))
- _vm->_dialogs->show(55115);
else if (_action.isAction(VERB_LOOK, NOUN_SIDEWALK_TO_WEST)) {
if (_game._visitedScenes.exists(505))
_vm->_dialogs->show(55116);
diff --git a/engines/mads/nebular/nebular_scenes6.cpp b/engines/mads/nebular/nebular_scenes6.cpp
index d33675c578..679039535f 100644
--- a/engines/mads/nebular/nebular_scenes6.cpp
+++ b/engines/mads/nebular/nebular_scenes6.cpp
@@ -643,7 +643,8 @@ void Scene603::actions() {
_game._player._visible = true;
_game._player._stepEnabled = true;
}
- }
+ } else
+ _vm->_dialogs->show(60323);
} else if (_action._lookFlag)
_vm->_dialogs->show(60310);
else if (_action.isAction(VERB_LOOK, NOUN_BED))
@@ -670,8 +671,6 @@ void Scene603::actions() {
_vm->_dialogs->show(60321);
else if (_action.isAction(VERB_TAKE, NOUN_PERFUME))
_vm->_dialogs->show(60322);
- else if (_action.isAction(VERB_TAKE, NOUN_NOTE))
- _vm->_dialogs->show(60323);
else if (_action.isAction(VERB_LOOK, NOUN_NOTE)) {
if (_game._objects[OBJ_NOTE]._roomNumber == _scene->_currentSceneId)
_vm->_dialogs->show(60324);
@@ -3156,7 +3155,7 @@ bool Scene611::check2ChargedBatteries() {
}
bool Scene611::check4ChargedBatteries() {
- if (_game._objects.isInInventory(OBJ_DURAFAIL_CELLS) && _game._objects.isInInventory(OBJ_PHONE_CELLS)
+ if (_game._objects.isInInventory(OBJ_DURAFAIL_CELLS) && _game._objects.isInInventory(OBJ_PHONE_CELLS)
&& _globals[kDurafailRecharged])
return true;
diff --git a/engines/mads/nebular/nebular_scenes7.cpp b/engines/mads/nebular/nebular_scenes7.cpp
index 930bb7c250..0f019c4b19 100644
--- a/engines/mads/nebular/nebular_scenes7.cpp
+++ b/engines/mads/nebular/nebular_scenes7.cpp
@@ -2616,7 +2616,7 @@ void Scene752::actions() {
default:
break;
}
- } else if (_action.isAction(VERB_TAKE, NOUN_BONES) && (_action._savedFields._mainObjectSource == CAT_HOTSPOT) &&
+ } else if (_action.isAction(VERB_TAKE, NOUN_BONES) && (_action._savedFields._mainObjectSource == CAT_HOTSPOT) &&
(!_game._objects.isInInventory(OBJ_BONES) || _game._trigger)) {
switch (_game._trigger) {
case 0:
diff --git a/engines/mads/nebular/nebular_scenes8.cpp b/engines/mads/nebular/nebular_scenes8.cpp
index 14f36756de..62a1a262b0 100644
--- a/engines/mads/nebular/nebular_scenes8.cpp
+++ b/engines/mads/nebular/nebular_scenes8.cpp
@@ -1098,7 +1098,7 @@ void Scene804::actions() {
_action.isAction(VERB_OPEN, NOUN_SERVICE_PANEL)) {
_scene->_nextSceneId = 805;
} else if ((_action.isAction(VERB_ACTIVATE, NOUN_REMOTE)) && _globals[kTopButtonPushed]) {
- if (!_globals[kInSpace]) {
+ if (!_globals[kInSpace]) {
// Top button pressed on panel in hanger control
if (!_globals[kBeamIsUp]) {
_globals[kFromCockpit] = true;
diff --git a/engines/mads/nebular/sound_nebular.cpp b/engines/mads/nebular/sound_nebular.cpp
index fc2755db2f..0a054440b2 100644
--- a/engines/mads/nebular/sound_nebular.cpp
+++ b/engines/mads/nebular/sound_nebular.cpp
@@ -24,6 +24,7 @@
#include "audio/decoders/raw.h"
#include "common/algorithm.h"
#include "common/debug.h"
+#include "common/md5.h"
#include "common/memstream.h"
#include "mads/sound.h"
#include "mads/nebular/sound_nebular.h"
@@ -149,7 +150,7 @@ AdlibSample::AdlibSample(Common::SeekableReadStream &s) {
/*-----------------------------------------------------------------------*/
-ASound::ASound(Audio::Mixer *mixer, const Common::String &filename, int dataOffset) {
+ASound::ASound(Audio::Mixer *mixer, FM_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());
@@ -197,8 +198,7 @@ ASound::ASound(Audio::Mixer *mixer, const Common::String &filename, int dataOffs
// Store passed parameters, and setup OPL
_dataOffset = dataOffset;
_mixer = mixer;
- _opl = OPL::Config::create();
- assert(_opl);
+ _opl = opl;
_opl->init(getRate());
_mixer->playStream(Audio::Mixer::kPlainSoundType, &_soundHandle, this, -1,
@@ -217,7 +217,32 @@ ASound::~ASound() {
delete[] (*i)._data;
_mixer->stopHandle(_soundHandle);
- delete _opl;
+}
+
+void ASound::validate() {
+ Common::File f;
+ static const char *const MD5[] = {
+ "205398468de2c8873b7d4d73d5be8ddc",
+ "f9b2d944a2fb782b1af5c0ad592306d3",
+ "7431f8dad77d6ddfc24e6f3c0c4ac7df",
+ "eb1f3f5a4673d3e73d8ac1818c957cf4",
+ "f936dd853073fa44f3daac512e91c476",
+ "3dc139d3e02437a6d9b732072407c366",
+ "af0edab2934947982e9a405476702e03",
+ "8cbc25570b50ba41c9b5361cad4fbedc",
+ "a31e4783e098f633cbb6689adb41dd4f"
+ };
+
+ for (int i = 1; i <= 9; ++i) {
+ Common::String filename = Common::String::format("ASOUND.00%d", i);
+ if (!f.open(filename))
+ error("Could not process - %s", filename.c_str());
+ Common::String md5str = Common::computeStreamMD5AsString(f, 8192);
+ f.close();
+
+ if (md5str != MD5[i - 1])
+ error("Invalid sound file - %s", filename.c_str());
+ }
}
void ASound::adlibInit() {
@@ -941,8 +966,8 @@ const ASound1::CommandPtr ASound1::_commandList[42] = {
&ASound1::command40, &ASound1::command41
};
-ASound1::ASound1(Audio::Mixer *mixer)
- : ASound(mixer, "asound.001", 0x1520) {
+ASound1::ASound1(Audio::Mixer *mixer, FM_OPL *opl)
+ : ASound(mixer, opl, "asound.001", 0x1520) {
_cmd23Toggle = false;
// Load sound samples
@@ -1242,7 +1267,7 @@ const ASound2::CommandPtr ASound2::_commandList[44] = {
&ASound2::command40, &ASound2::command41, &ASound2::command42, &ASound2::command43
};
-ASound2::ASound2(Audio::Mixer *mixer) : ASound(mixer, "asound.002", 0x15E0) {
+ASound2::ASound2(Audio::Mixer *mixer, FM_OPL *opl) : ASound(mixer, opl, "asound.002", 0x15E0) {
_command12Param = 0xFD;
// Load sound samples
@@ -1613,7 +1638,7 @@ const ASound3::CommandPtr ASound3::_commandList[61] = {
&ASound3::command60
};
-ASound3::ASound3(Audio::Mixer *mixer) : ASound(mixer, "asound.003", 0x15B0) {
+ASound3::ASound3(Audio::Mixer *mixer, FM_OPL *opl) : ASound(mixer, opl, "asound.003", 0x15B0) {
_command39Flag = false;
// Load sound samples
@@ -2017,7 +2042,7 @@ const ASound4::CommandPtr ASound4::_commandList[61] = {
&ASound4::command60
};
-ASound4::ASound4(Audio::Mixer *mixer) : ASound(mixer, "asound.004", 0x14F0) {
+ASound4::ASound4(Audio::Mixer *mixer, FM_OPL *opl) : ASound(mixer, opl, "asound.004", 0x14F0) {
// Load sound samples
_soundFile.seek(_dataOffset + 0x122);
for (int i = 0; i < 210; ++i)
@@ -2273,7 +2298,7 @@ const ASound5::CommandPtr ASound5::_commandList[42] = {
&ASound5::command40, &ASound5::command41
};
-ASound5::ASound5(Audio::Mixer *mixer) : ASound(mixer, "asound.002", 0x15E0) {
+ASound5::ASound5(Audio::Mixer *mixer, FM_OPL *opl) : ASound(mixer, opl, "asound.002", 0x15E0) {
// Load sound samples
_soundFile.seek(_dataOffset + 0x144);
for (int i = 0; i < 164; ++i)
@@ -2514,7 +2539,7 @@ const ASound6::CommandPtr ASound6::_commandList[30] = {
&ASound6::nullCommand, &ASound6::command29
};
-ASound6::ASound6(Audio::Mixer *mixer) : ASound(mixer, "asound.006", 0x1390) {
+ASound6::ASound6(Audio::Mixer *mixer, FM_OPL *opl) : ASound(mixer, opl, "asound.006", 0x1390) {
// Load sound samples
_soundFile.seek(_dataOffset + 0x122);
for (int i = 0; i < 200; ++i)
@@ -2670,7 +2695,7 @@ const ASound7::CommandPtr ASound7::_commandList[38] = {
&ASound7::command36, &ASound7::command37
};
-ASound7::ASound7(Audio::Mixer *mixer) : ASound(mixer, "asound.007", 0x1460) {
+ASound7::ASound7(Audio::Mixer *mixer, FM_OPL *opl) : ASound(mixer, opl, "asound.007", 0x1460) {
// Load sound samples
_soundFile.seek(_dataOffset + 0x122);
for (int i = 0; i < 214; ++i)
@@ -2876,7 +2901,7 @@ const ASound8::CommandPtr ASound8::_commandList[38] = {
&ASound8::command36, &ASound8::command37
};
-ASound8::ASound8(Audio::Mixer *mixer) : ASound(mixer, "asound.008", 0x1490) {
+ASound8::ASound8(Audio::Mixer *mixer, FM_OPL *opl) : ASound(mixer, opl, "asound.008", 0x1490) {
// Load sound samples
_soundFile.seek(_dataOffset + 0x122);
for (int i = 0; i < 174; ++i)
@@ -3114,6 +3139,313 @@ int ASound8::command37() {
return 0;
}
+/*-----------------------------------------------------------------------*/
+
+const ASound9::CommandPtr ASound9::_commandList[52] = {
+ &ASound9::command0, &ASound9::command1, &ASound9::command2, &ASound9::command3,
+ &ASound9::command4, &ASound9::command5, &ASound9::command6, &ASound9::command7,
+ &ASound9::command8, &ASound9::command9, &ASound9::command10, &ASound9::command11,
+ &ASound9::command12, &ASound9::command13, &ASound9::command14, &ASound9::command15,
+ &ASound9::command16, &ASound9::command17, &ASound9::command18, &ASound9::command19,
+ &ASound9::command20, &ASound9::command21, &ASound9::command22, &ASound9::command23,
+ &ASound9::command24, &ASound9::command25, &ASound9::command26, &ASound9::command27,
+ &ASound9::command28, &ASound9::command29, &ASound9::command30, &ASound9::command31,
+ &ASound9::command32, &ASound9::command33, &ASound9::command34, &ASound9::command35,
+ &ASound9::command36, &ASound9::command37, &ASound9::command38, &ASound9::command39,
+ &ASound9::command40, &ASound9::command41, &ASound9::command42, &ASound9::command43,
+ &ASound9::command44_46, &ASound9::command45, &ASound9::command44_46, &ASound9::command47,
+ &ASound9::command48, &ASound9::command49, &ASound9::command50, &ASound9::command51
+};
+
+ASound9::ASound9(Audio::Mixer *mixer, FM_OPL *opl) : ASound(mixer, opl, "asound.009", 0x16F0) {
+ _v1 = _v2 = 0;
+ _soundPtr = nullptr;
+
+ // Load sound samples
+ _soundFile.seek(_dataOffset + 0x50);
+ for (int i = 0; i < 94; ++i)
+ _samples.push_back(AdlibSample(_soundFile));
+}
+
+int ASound9::command(int commandId, int param) {
+ if (commandId > 51)
+ return 0;
+
+ _commandParam = param;
+ _frameCounter = 0;
+ return (this->*_commandList[commandId])();
+}
+
+int ASound9::command9() {
+ _v1 = 1848;
+ _v2 = 84;
+ _channels[0].load(loadData(0xAA4, 470));
+ _channels[1].load(loadData(0xE4C, 450));
+ _channels[2].load(loadData(0x1466, 702));
+ _channels[3].load(loadData(0x137E, 232));
+ _channels[4].load(loadData(0x1014, 65));
+ _channels[5].load(loadData(0x11C4, 44));
+ _channels[6].load(loadData(0XC7A, 466));
+ return 0;
+}
+
+int ASound9::command10() {
+ _channels[0].load(loadData(0x1724, 24));
+ _channels[1].load(loadData(0x173C, 24));
+ _channels[2].load(loadData(0x1754, 20));
+ _channels[3].load(loadData(0x1768, 20));
+ _channels[4].load(loadData(0x177C, 20));
+ _channels[5].load(loadData(0x1790, 20));
+ return 0;
+}
+
+int ASound9::command11() {
+ playSound(0x8232, 168);
+ playSound(0x82DA, 170);
+ return 0;
+}
+
+int ASound9::command12() {
+ playSound(0x80DA, 12);
+ playSound(0x80E6, 12);
+ return 0;
+}
+
+int ASound9::command13() {
+ playSound(0x80F2, 38);
+ playSound(0x8118, 42);
+ return 0;
+}
+
+int ASound9::command14() {
+ playSound(0x81F6, 22);
+ return 0;
+}
+
+int ASound9::command15() {
+ playSound(0x818A, 32);
+ playSound(0x81AA, 32);
+ return 0;
+}
+
+int ASound9::command16() {
+ playSound(0x8022, 36);
+ playSound(0x8046, 42);
+ return 0;
+}
+
+int ASound9::command17() {
+ command29();
+ playSound(0x858C, 11);
+ return 0;
+}
+
+int ASound9::command18() {
+ playSound(0x80C2, 24);
+ return 0;
+}
+
+int ASound9::command19() {
+ playSound(0x80A0, 34);
+ return 0;
+}
+
+int ASound9::command20() {
+ int v = (getRandomNumber() & 0x10) | 0x4D;
+ byte *pData = loadData(0x8142, 8);
+ pData[4] = v & 0x7F;
+ playSoundData(pData);
+ return 0;
+}
+
+int ASound9::command21() {
+ playSound(0x815A, 16);
+ return 0;
+}
+
+int ASound9::command22() {
+ playSound(0x816A, 16);
+ return 0;
+}
+
+int ASound9::command23() {
+ playSound(0x814A, 16);
+ return 0;
+}
+
+int ASound9::command24() {
+ playSound(0x7FE2, 34);
+ return 0;
+}
+
+int ASound9::command25() {
+ playSound(0x8004, 30);
+ return 0;
+}
+
+int ASound9::command26() {
+ _channels[6].load(loadData(0x8384, 156));
+ _channels[7].load(loadData(0x8420, 160));
+ return 0;
+}
+
+int ASound9::command27() {
+ playSound(0x84C0, 140);
+ return 0;
+}
+
+int ASound9::command28() {
+ playSound(0x81CA, 10);
+ return 0;
+}
+
+int ASound9::command29() {
+ playSound(0x81D4, 10);
+ return 0;
+}
+
+int ASound9::command30() {
+ playSound(0x817A, 16);
+ return 0;
+}
+
+int ASound9::command31() {
+ playSound(0x820C, 14);
+ playSound(0x821A, 24);
+ return 0;
+}
+
+int ASound9::command32() {
+ playSound(0x8070, 8);
+ return 0;
+}
+
+int ASound9::command33() {
+ playSound(0x8078, 16);
+ playSound(0x8088, 16);
+ return 0;
+}
+
+int ASound9::command34() {
+ // Skipped stuff in original
+ _channels[0].load(loadData(0x17A4, 24));
+ _channels[1].load(loadData(0x1CDE, 62));
+ _channels[2].load(loadData(0x2672, 980));
+ _channels[3].load(loadData(0x3336, 1000));
+ _channels[4].load(loadData(0x469E, 176));
+ _channels[5].load(loadData(0x57F2, 138));
+
+ return 0;
+}
+
+int ASound9::command35() {
+ playSound(0x854C, 64);
+ return 0;
+}
+
+int ASound9::command36() {
+ playSound(0x81DE, 10);
+ playSound(0x81E8, 14);
+ return 0;
+}
+
+int ASound9::command37() {
+ byte *pData = loadData(0x8098, 8);
+ int v = getRandomNumber();
+ if ((v &= 0x40) != 0)
+ v |= 8;
+ else
+ v += 0x4A;
+
+ pData[6] = v;
+ playSoundData(pData);
+ return 0;
+}
+
+int ASound9::command38() {
+ playSound(0x100E, 6);
+ return 0;
+}
+
+int ASound9::command39() {
+ _soundPtr = loadData(0x1055, 128);
+ return 0;
+}
+
+int ASound9::command40() {
+ _soundPtr = loadData(0x118C, 50);
+ return 0;
+}
+
+int ASound9::command41() {
+ _soundPtr = loadData(0x11BE, 6);
+ return 0;
+}
+
+int ASound9::command42() {
+ _soundPtr = loadData(0x11F0, 50);
+ return 0;
+}
+
+int ASound9::command43() {
+ _v1 = _v2 = 80;
+ _channels[0].load(loadData(0x626A, 90));
+ _channels[1].load(loadData(0x67F2, 92));
+ _channels[2].load(loadData(0x6CFE, 232));
+ _channels[3].load(loadData(0x7146, 236));
+
+ return 0;
+}
+
+int ASound9::command44_46() {
+ _soundPtr = loadData(0x10D5, 38);
+ return 0;
+}
+
+int ASound9::command45() {
+ _soundPtr = loadData(0x10FB, 38);
+ return 0;
+}
+
+int ASound9::command47() {
+ _soundPtr = loadData(0x1121, 107);
+ return 0;
+}
+
+int ASound9::command48() {
+ playSound(0x7FD0, 8);
+ playSound(0x7FD8, 10);
+ return 0;
+}
+
+int ASound9::command49() {
+ _channels[0].load(loadData(0x7AD6, 92));
+ _channels[1].load(loadData(0x7B32, 90));
+ _channels[2].load(loadData(0x7B8C, 738));
+ _channels[3].load(loadData(0x7E6E, 28));
+ _channels[4].load(loadData(0x7E8A, 30));
+ _channels[5].load(loadData(0x7EA8, 30));
+ _channels[6].load(loadData(0x7EC6, 195));
+ return 0;
+}
+
+int ASound9::command50() {
+ _soundPtr = loadData(0x1222, 348);
+ return 0;
+}
+
+int ASound9::command51() {
+ // Skipped stuff in original
+ _channels[0].load(loadData(0x17BC, 1282));
+ _channels[1].load(loadData(0x1CFC, 2422));
+ _channels[2].load(loadData(0x2A46, 2288));
+ _channels[3].load(loadData(0x371E, 3964));
+ _channels[4].load(loadData(0x474E, 1863));
+ _channels[5].load(loadData(0x587C, 2538));
+ return 0;
+}
+
+
} // End of namespace Nebular
} // End of namespace MADS
diff --git a/engines/mads/nebular/sound_nebular.h b/engines/mads/nebular/sound_nebular.h
index c485bd7955..ccfd40ad52 100644
--- a/engines/mads/nebular/sound_nebular.h
+++ b/engines/mads/nebular/sound_nebular.h
@@ -305,10 +305,12 @@ public:
public:
/**
* Constructor
+ * @param mixer Mixer
+ * @param opl OPL
* @param filename Specifies the adlib sound player file to use
* @param dataOffset Offset in the file of the data segment
*/
- ASound(Audio::Mixer *mixer, const Common::String &filename, int dataOffset);
+ ASound(Audio::Mixer *mixer, FM_OPL *opl, const Common::String &filename, int dataOffset);
/**
* Destructor
@@ -316,6 +318,11 @@ public:
virtual ~ASound();
/**
+ * Validates the Adlib sound files
+ */
+ static void validate();
+
+ /**
* Execute a player command. Most commands represent sounds to play, but some
* low number commands also provide control operations.
* @param commandId Player ommand to execute.
@@ -408,7 +415,7 @@ private:
void command111213();
int command2627293032();
public:
- ASound1(Audio::Mixer *mixer);
+ ASound1(Audio::Mixer *mixer, FM_OPL *opl);
virtual int command(int commandId, int param);
};
@@ -460,7 +467,7 @@ private:
void command9Randomize();
void command9Apply(byte *data, int val, int incr);
public:
- ASound2(Audio::Mixer *mixer);
+ ASound2(Audio::Mixer *mixer, FM_OPL *opl);
virtual int command(int commandId, int param);
};
@@ -520,7 +527,7 @@ private:
void command9Randomize();
void command9Apply(byte *data, int val, int incr);
public:
- ASound3(Audio::Mixer *mixer);
+ ASound3(Audio::Mixer *mixer, FM_OPL *opl);
virtual int command(int commandId, int param);
};
@@ -558,7 +565,7 @@ private:
void method1();
public:
- ASound4(Audio::Mixer *mixer);
+ ASound4(Audio::Mixer *mixer, FM_OPL *opl);
virtual int command(int commandId, int param);
};
@@ -604,7 +611,7 @@ private:
int command42();
int command43();
public:
- ASound5(Audio::Mixer *mixer);
+ ASound5(Audio::Mixer *mixer, FM_OPL *opl);
virtual int command(int commandId, int param);
};
@@ -633,7 +640,7 @@ private:
int command25();
int command29();
public:
- ASound6(Audio::Mixer *mixer);
+ ASound6(Audio::Mixer *mixer, FM_OPL *opl);
virtual int command(int commandId, int param);
};
@@ -665,7 +672,7 @@ private:
int command36();
int command37();
public:
- ASound7(Audio::Mixer *mixer);
+ ASound7(Audio::Mixer *mixer, FM_OPL *opl);
virtual int command(int commandId, int param);
};
@@ -708,7 +715,66 @@ private:
void method1(byte *pData);
void adjustRange(byte *pData, byte v, int incr);
public:
- ASound8(Audio::Mixer *mixer);
+ ASound8(Audio::Mixer *mixer, FM_OPL *opl);
+
+ virtual int command(int commandId, int param);
+};
+
+class ASound9 : public ASound {
+private:
+ int _v1, _v2;
+ byte *_soundPtr;
+
+ typedef int (ASound9::*CommandPtr)();
+ static const CommandPtr _commandList[52];
+
+ int command9();
+ int command10();
+ int command11();
+ int command12();
+ int command13();
+ int command14();
+ int command15();
+ int command16();
+ int command17();
+ int command18();
+ int command19();
+ int command20();
+ int command21();
+ int command22();
+ int command23();
+ int command24();
+ int command25();
+ int command26();
+ int command27();
+ int command28();
+ int command29();
+ int command30();
+ int command31();
+ int command32();
+ int command33();
+ int command34();
+ int command35();
+ int command36();
+ int command37();
+ int command38();
+ int command39();
+ int command40();
+ int command41();
+ int command42();
+ int command43();
+ int command44_46();
+ int command45();
+ int command47();
+ int command48();
+ int command49();
+ int command50();
+ int command51();
+ int command57();
+ int command59();
+ int command60();
+public:
+ ASound9(Audio::Mixer *mixer, FM_OPL *opl);
virtual int command(int commandId, int param);
};
diff --git a/engines/mads/palette.cpp b/engines/mads/palette.cpp
index eedbf36ddd..836d04f7c0 100644
--- a/engines/mads/palette.cpp
+++ b/engines/mads/palette.cpp
@@ -143,7 +143,7 @@ int PaletteUsage::process(Common::Array<RGB6> &palette, uint flags) {
for (uint palIndex = 0; palIndex < palette.size(); ++palIndex) {
bool changed = false;
- int newPalIndex = -1;
+ int newPalIndex = 0xFF;
int v1 = palRange[palIndex]._v2;
if (palette[v1]._flags & 8) {
@@ -229,8 +229,11 @@ int PaletteUsage::process(Common::Array<RGB6> &palette, uint flags) {
// In at least scene 318, when the doctor knocks you with the blackjack,
// the changed flag can be false
//assert(changed);
- assert(newPalIndex != -1);
-
+
+ // CHECKME: When pressing on F1 in the first screen, newPalIndex is set to 0xFF at this point
+ // which is a valid value for the index. Maybe a better check would be "< 256" ?
+ //assert(newPalIndex != -1);
+
int var52 = (noUsageFlag && palette[palIndex]._u2) ? 2 : 0;
_vm->_palette->_palFlags[newPalIndex] |= var52 | rgbMask;
@@ -314,6 +317,62 @@ int PaletteUsage::rgbFactor(byte *palEntry, RGB6 &pal6) {
return total;
}
+int PaletteUsage::checkRGB(const byte *rgb, int palStart, bool flag, int *palIndex) {
+ Palette &palette = *_vm->_palette;
+ bool match = false;
+ int result;
+ if (palStart >= 0) {
+ result = palStart;
+ } else {
+ result = -1;
+ for (int i = 0; i < palette._highRange; ++i) {
+ if (!palette._rgbList[i]) {
+ result = i;
+ break;
+ }
+ }
+ }
+
+ if (result >= 0) {
+ int mask = 1 << result;
+ byte *palP = &palette._mainPalette[0];
+ uint32 *flagsP = &palette._palFlags[0];
+
+ for (; flagsP < &palette._palFlags[PALETTE_COUNT]; ++flagsP, ++result) {
+ if ((!(*flagsP & 1) || flag) && !(*flagsP & 2)) {
+ if (!memcmp(palP, rgb, 3)) {
+ *flagsP |= mask;
+
+ if (palIndex)
+ *palIndex = result;
+ match = true;
+ break;
+ }
+ }
+ }
+
+ if (!match) {
+ palP = &palette._mainPalette[0];
+ flagsP = &palette._palFlags[0];
+
+ for (int i = 0; i < PALETTE_COUNT; ++i, palP += 3, ++flagsP) {
+ if (!*flagsP) {
+ Common::copy(rgb, rgb + 3, palP);
+ *flagsP |= mask;
+
+ if (palIndex)
+ *palIndex = i;
+ match = true;
+ break;
+ }
+ }
+ }
+ }
+
+ assert(match);
+ return result;
+}
+
/*------------------------------------------------------------------------*/
void RGBList::clear() {
diff --git a/engines/mads/palette.h b/engines/mads/palette.h
index 9b8b7146db..27d25f266b 100644
--- a/engines/mads/palette.h
+++ b/engines/mads/palette.h
@@ -136,6 +136,8 @@ public:
void updateUsage(Common::Array<int> &usageList, int sceneUsageIndex);
void resetPalFlags(int idx);
+
+ int checkRGB(const byte *rgb, int palStart, bool flag, int *palIndex);
};
class RGBList {
diff --git a/engines/mads/phantom/game_phantom.cpp b/engines/mads/phantom/game_phantom.cpp
index ba2179fcbf..0b2531ef65 100644
--- a/engines/mads/phantom/game_phantom.cpp
+++ b/engines/mads/phantom/game_phantom.cpp
@@ -50,11 +50,12 @@ void GamePhantom::startGame() {
}
void GamePhantom::initializeGlobals() {
- //int count, count2;
- //int bad;
-
_globals.reset();
- //_globals[kTalkInanimateCount] = 8;
+
+ warning("TODO: sub_316DA()");
+
+ _player._facing = FACING_NORTH;
+ _player._turnToFacing = FACING_NORTH;
/* Section #1 variables */
// TODO
@@ -74,11 +75,7 @@ void GamePhantom::initializeGlobals() {
/* Section #9 variables */
// TODO
- _player._facing = FACING_NORTH;
- _player._turnToFacing = FACING_NORTH;
-
- //Player::preloadSequences("RXM", 1);
- //Player::preloadSequences("ROX", 1);
+ Player::preloadSequences("RAL", 1);
}
void GamePhantom::setSectionHandler() {
diff --git a/engines/mads/scene.cpp b/engines/mads/scene.cpp
index 1f95749fd8..18ceb3c813 100644
--- a/engines/mads/scene.cpp
+++ b/engines/mads/scene.cpp
@@ -63,8 +63,7 @@ Scene::Scene(MADSEngine *vm)
_paletteUsageF.push_back(PaletteUsage::UsageEntry(0xF));
// Set up a scene surface that maps to our physical screen drawing surface
- _sceneSurface.init(MADS_SCREEN_WIDTH, MADS_SCENE_HEIGHT, MADS_SCREEN_WIDTH,
- _vm->_screen.getPixels(), Graphics::PixelFormat::createFormatCLUT8());
+ restrictScene();
// Set up the verb list
_verbList.push_back(VerbInit(VERB_LOOK, VERB_THAT, PREP_NONE));
@@ -82,6 +81,12 @@ Scene::Scene(MADSEngine *vm)
Scene::~Scene() {
delete _sceneLogic;
delete _sceneInfo;
+ delete _animationData;
+}
+
+void Scene::restrictScene() {
+ _sceneSurface.init(MADS_SCREEN_WIDTH, MADS_SCENE_HEIGHT, MADS_SCREEN_WIDTH,
+ _vm->_screen.getPixels(), Graphics::PixelFormat::createFormatCLUT8());
}
void Scene::clearVocab() {
@@ -355,6 +360,9 @@ void Scene::loop() {
if (_vm->_dialogs->_pendingDialog != DIALOG_NONE && !_vm->_game->_trigger
&& _vm->_game->_player._stepEnabled)
_reloadSceneFlag = true;
+
+ if (_vm->_game->_winStatus)
+ break;
}
}
@@ -510,7 +518,7 @@ void Scene::drawElements(ScreenTransition transitionType, bool surfaceFlag) {
_vm->_sound->startQueuedCommands();
} else {
// Copy dirty areas to the screen
- _dirtyAreas.copyToScreen(_vm->_screen._offset);
+ _dirtyAreas.copyToScreen();
}
_spriteSlots.cleanUp();
diff --git a/engines/mads/scene.h b/engines/mads/scene.h
index 407d70dc85..9fd99ad8e5 100644
--- a/engines/mads/scene.h
+++ b/engines/mads/scene.h
@@ -52,11 +52,6 @@ private:
*/
void loadVocabStrings();
- /*
- * Initializes the data for palette animation within the scene
- */
- void initPaletteAnimation(Common::Array<PaletteCycle> &palCycles, bool animFlag);
-
/**
* Handles a single frame within the game scene
*/
@@ -142,6 +137,8 @@ public:
*/
~Scene();
+ void restrictScene();
+
/**
* Clear the vocabulary list
*/
@@ -202,6 +199,11 @@ public:
*/
void drawElements(ScreenTransition transitionType, bool surfaceFlag);
+ /*
+ * Initializes the data for palette animation within the scene
+ */
+ void initPaletteAnimation(Common::Array<PaletteCycle> &palCycles, bool animFlag);
+
/**
* Handles cycling palette colors for the scene
*/
diff --git a/engines/mads/scene_data.cpp b/engines/mads/scene_data.cpp
index e874468345..b5e219ed04 100644
--- a/engines/mads/scene_data.cpp
+++ b/engines/mads/scene_data.cpp
@@ -217,7 +217,7 @@ void SceneInfo::load(int sceneId, int variant, const Common::String &resName,
int width = _width;
int height = _height;
- if (!bgSurface.getPixels()) {
+ if (!bgSurface.getPixels() || (bgSurface.w != width) || (bgSurface.h != height)) {
bgSurface.setSize(width, height);
}
@@ -232,11 +232,11 @@ void SceneInfo::load(int sceneId, int variant, const Common::String &resName,
infoFile.close();
if (_vm->getGameID() == GType_RexNebular) {
- loadMadsV1Background(sceneId, resName, flags, bgSurface);
- loadPalette(sceneId, _artFileNum, resName, flags, bgSurface);
+ loadMadsV1Background(_artFileNum, resName, flags, bgSurface);
+ loadPalette(_sceneId, _artFileNum, resName, flags, bgSurface);
} else {
- loadMadsV2Background(sceneId, resName, flags, bgSurface);
- loadPalette(sceneId, sceneId, resName, flags, bgSurface);
+ loadMadsV2Background(_sceneId, resName, flags, bgSurface);
+ loadPalette(_sceneId, _sceneId, resName, flags, bgSurface);
}
Common::Array<SpriteAsset *> spriteSets;
@@ -264,7 +264,7 @@ void SceneInfo::load(int sceneId, int variant, const Common::String &resName,
assert(asset && _depthStyle != 2);
MSprite *spr = asset->getFrame(asset->getCount() - 1);
- bgSurface.copyFrom(spr, si._position, si._depth, &depthSurface,
+ bgSurface.copyFrom(spr, si._position, si._depth, &depthSurface,
si._scale, spr->getTransparencyIndex());
}
@@ -299,6 +299,7 @@ void SceneInfo::loadPalette(int sceneId, int artFileNum, const Common::String &r
delete stream;
// Copy out the palette animation data
+ _paletteCycles.clear();
for (uint i = 0; i < artHeader._paletteCycles.size(); ++i)
_paletteCycles.push_back(artHeader._paletteCycles[i]);
@@ -333,7 +334,7 @@ void SceneInfo::loadMadsV1Background(int sceneId, const Common::String &resName,
// Get the ART resource
if (sceneFlag) {
- resourceName = Resources::formatName(RESPREFIX_RM, _artFileNum, ".ART");
+ resourceName = Resources::formatName(RESPREFIX_RM, sceneId, ".ART");
} else {
resourceName = "*" + Resources::formatResource(resName, resName);
}
@@ -342,13 +343,33 @@ void SceneInfo::loadMadsV1Background(int sceneId, const Common::String &resName,
File artFile(resourceName);
MadsPack artResource(&artFile);
- // Read in the background surface data
- assert(_width == bgSurface.w && _height == bgSurface.h);
+ // Read inhh the background surface data
+ assert(_width && _height == bgSurface.h);
stream = artResource.getItemStream(1);
stream->read(bgSurface.getPixels(), bgSurface.w * bgSurface.h);
+ delete stream;
+
+ if (flags & SCENEFLAG_TRANSLATE) {
+ // Load in the palette and translate it
+ Common::SeekableReadStream *palStream = artResource.getItemStream(0);
+ Common::Array<RGB6> palette;
+
+ _width = palStream->readUint16LE();
+ _height = palStream->readUint16LE();
+
+ int numColors = palStream->readUint16LE();
+ assert(numColors <= 252);
+ palette.resize(numColors);
+ for (int i = 0; i < numColors; ++i)
+ palette[i].load(palStream);
+ delete palStream;
+
+ // Translate the surface
+ _vm->_palette->_paletteUsage.process(palette, 0);
+ bgSurface.translate(palette);
+ }
// Close the ART file
- delete stream;
artFile.close();
}
diff --git a/engines/mads/scene_data.h b/engines/mads/scene_data.h
index 783a9ab8a9..41e094b8f5 100644
--- a/engines/mads/scene_data.h
+++ b/engines/mads/scene_data.h
@@ -55,7 +55,8 @@ class SpriteSlot;
enum {
SCENEFLAG_DITHER = 0x01, // Dither to 16 colors
- SCENEFLAG_LOAD_SHADOW = 0x10 // Load hard shadows
+ SCENEFLAG_LOAD_SHADOW = 0x10, // Load hard shadows
+ SCENEFLAG_TRANSLATE = 0x10000 // Translate palette of loaded background
};
class VerbInit {
diff --git a/engines/mads/screen.cpp b/engines/mads/screen.cpp
index ab5dff56ff..c9a0863d85 100644
--- a/engines/mads/screen.cpp
+++ b/engines/mads/screen.cpp
@@ -212,8 +212,7 @@ void DirtyAreas::copy(MSurface *srcSurface, MSurface *destSurface, const Common:
Common::Rect bounds(srcBounds.left + posAdjust.x, srcBounds.top + posAdjust.y,
srcBounds.right + posAdjust.x, srcBounds.bottom + posAdjust.y);
- Common::Point destPos(bounds.left + _vm->_screen._offset.x,
- bounds.top + _vm->_screen._offset.y);
+ Common::Point destPos(srcBounds.left, srcBounds.top);
if ((*this)[i]._active && bounds.isValidRect()) {
srcSurface->copyTo(destSurface, bounds, destPos);
@@ -221,17 +220,14 @@ void DirtyAreas::copy(MSurface *srcSurface, MSurface *destSurface, const Common:
}
}
-void DirtyAreas::copyToScreen(const Common::Point &posAdjust) {
+void DirtyAreas::copyToScreen() {
for (uint i = 0; i < size(); ++i) {
- const Common::Rect &srcBounds = (*this)[i]._bounds;
+ const Common::Rect &bounds = (*this)[i]._bounds;
// Check if this is a sane rectangle before attempting to create it
- if (srcBounds.left >= srcBounds.right || srcBounds.top >= srcBounds.bottom)
+ if (bounds.left >= bounds.right || bounds.top >= bounds.bottom)
continue;
- Common::Rect bounds(srcBounds.left + posAdjust.x, srcBounds.top + posAdjust.y,
- srcBounds.right + posAdjust.x, srcBounds.bottom + posAdjust.y);
-
if ((*this)[i]._active && (*this)[i]._bounds.isValidRect()) {
_vm->_screen.copyRectToScreen(bounds);
}
@@ -561,23 +557,32 @@ void ScreenObjects::synchronize(Common::Serializer &s) {
ScreenSurface::ScreenSurface() {
_shakeCountdown = -1;
_random = 0x4D2;
+ _surfacePixels = nullptr;
}
void ScreenSurface::init() {
- setSize(g_system->getWidth(), g_system->getHeight());
-}
+ // Set the size for the screen
+ setSize(MADS_SCREEN_WIDTH, MADS_SCREEN_HEIGHT);
-void ScreenSurface::copyRectToScreen(const Common::Point &destPos,
- const Common::Rect &bounds) {
- const byte *buf = getBasePtr(destPos.x, destPos.y);
+ // Store a copy of the raw pixels pointer for the screen, since the surface
+ // itself may be later changed to only a subset of the screen
+ _surfacePixels = (byte *)getPixels();
+ _freeFlag = false;
+}
- if (bounds.width() != 0 && bounds.height() != 0)
- g_system->copyRectToScreen(buf, this->pitch, bounds.left, bounds.top,
- bounds.width(), bounds.height());
+ScreenSurface::~ScreenSurface() {
+ delete[] _surfacePixels;
}
void ScreenSurface::copyRectToScreen(const Common::Rect &bounds) {
- copyRectToScreen(Common::Point(bounds.left, bounds.top), bounds);
+ const byte *buf = getBasePtr(bounds.left, bounds.top);
+
+ Common::Rect destBounds = bounds;
+ destBounds.translate(_clipBounds.left, _clipBounds.top);
+
+ if (bounds.width() != 0 && bounds.height() != 0)
+ g_system->copyRectToScreen(buf, this->pitch, destBounds.left, destBounds.top,
+ destBounds.width(), destBounds.height());
}
void ScreenSurface::updateScreen() {
@@ -659,4 +664,15 @@ void ScreenSurface::transition(ScreenTransition transitionType, bool surfaceFlag
}
}
+void ScreenSurface::setClipBounds(const Common::Rect &r) {
+ _clipBounds = r;
+ setPixels(_surfacePixels + pitch * r.top + r.left, r.width(), r.height());
+ this->pitch = MADS_SCREEN_WIDTH;
+}
+
+void ScreenSurface::resetClipBounds() {
+ setClipBounds(Common::Rect(0, 0, MADS_SCREEN_WIDTH, MADS_SCREEN_HEIGHT));
+}
+
+
} // End of namespace MADS
diff --git a/engines/mads/screen.h b/engines/mads/screen.h
index 7937e15456..9d01ca82e3 100644
--- a/engines/mads/screen.h
+++ b/engines/mads/screen.h
@@ -117,8 +117,8 @@ public:
/**
* Use the lsit of dirty areas to copy areas of the screen surface to
* the physical screen
- * @param posAdjust Position adjustment */
- void copyToScreen(const Common::Point &posAdjust);
+ */
+ void copyToScreen();
void reset();
};
@@ -205,8 +205,9 @@ public:
class ScreenSurface : public MSurface {
private:
uint16 _random;
+ byte *_surfacePixels;
+ Common::Rect _clipBounds;
public:
- Common::Point _offset;
int _shakeCountdown;
public:
/**
@@ -215,17 +216,14 @@ public:
ScreenSurface();
/**
- * Initialize the surface
+ * Destructor
*/
- void init();
+ ~ScreenSurface();
/**
- * Copys an area of the screen surface to a given destination position on
- * the ScummVM physical screen buffer
- * @param destPos Destination position
- * @param bounds Area of screen surface to copy
+ * Initialize the surface
*/
- void copyRectToScreen(const Common::Point &destPos, const Common::Rect &bounds);
+ void init();
/**
* Copys an area of the screen surface to the ScmmVM physical screen buffer
@@ -239,6 +237,12 @@ public:
void updateScreen();
void transition(ScreenTransition transitionType, bool surfaceFlag);
+
+ void setClipBounds(const Common::Rect &r);
+
+ void resetClipBounds();
+
+ const Common::Rect &getClipBounds() { return _clipBounds; }
};
} // End of namespace MADS
diff --git a/engines/mads/sequence.cpp b/engines/mads/sequence.cpp
index 07b1451718..05f00afb5a 100644
--- a/engines/mads/sequence.cpp
+++ b/engines/mads/sequence.cpp
@@ -473,7 +473,7 @@ int SequenceList::startReverseCycle(int srcSpriteIndex, bool flipped, int numTic
int depth = _vm->_game->_scene._depthSurface.getDepth(Common::Point(
frame->_offset.x + frame->w / 2, frame->_offset.y + frame->h / 2));
- return add(srcSpriteIndex, flipped, sprites->getCount(), triggerCountdown, timeoutTicks,
+ return add(srcSpriteIndex, flipped, sprites->getCount(), triggerCountdown, timeoutTicks,
extraTicks, numTicks, 0, 0, true, 100, depth - 1, -1, ANIMTYPE_REVERSIBLE, 0, 0);
}
diff --git a/engines/mads/sound.cpp b/engines/mads/sound.cpp
index bd99aed2f4..1652550ba3 100644
--- a/engines/mads/sound.cpp
+++ b/engines/mads/sound.cpp
@@ -36,10 +36,27 @@ SoundManager::SoundManager(MADSEngine *vm, Audio::Mixer *mixer) {
_pollSoundEnabled = false;
_soundPollFlag = false;
_newSoundsPaused = false;
+
+ _opl = OPL::Config::create();
+ _opl->init(11025);
+
+ // Validate sound files
+ switch (_vm->getGameID()) {
+ case GType_RexNebular:
+ Nebular::ASound::validate();
+ break;
+ default:
+ break;
+ }
}
SoundManager::~SoundManager() {
- delete _driver;
+ if (_driver) {
+ _driver->stop();
+ delete _driver;
+ }
+
+ delete _opl;
}
void SoundManager::init(int sectionNumber) {
@@ -49,31 +66,32 @@ void SoundManager::init(int sectionNumber) {
case GType_RexNebular:
switch (sectionNumber) {
case 1:
- _driver = new Nebular::ASound1(_mixer);
+ _driver = new Nebular::ASound1(_mixer, _opl);
break;
case 2:
- _driver = new Nebular::ASound2(_mixer);
+ _driver = new Nebular::ASound2(_mixer, _opl);
break;
case 3:
- _driver = new Nebular::ASound3(_mixer);
+ _driver = new Nebular::ASound3(_mixer, _opl);
break;
case 4:
- _driver = new Nebular::ASound4(_mixer);
+ _driver = new Nebular::ASound4(_mixer, _opl);
break;
case 5:
- _driver = new Nebular::ASound5(_mixer);
+ _driver = new Nebular::ASound5(_mixer, _opl);
break;
case 6:
- _driver = new Nebular::ASound6(_mixer);
+ _driver = new Nebular::ASound6(_mixer, _opl);
break;
case 7:
- _driver = new Nebular::ASound7(_mixer);
+ _driver = new Nebular::ASound7(_mixer, _opl);
break;
case 8:
- _driver = new Nebular::ASound8(_mixer);
+ _driver = new Nebular::ASound8(_mixer, _opl);
break;
case 9:
- error("Sound driver 9 not implemented");
+ _driver = new Nebular::ASound9(_mixer, _opl);
+ break;
default:
_driver = nullptr;
break;
diff --git a/engines/mads/sound.h b/engines/mads/sound.h
index 9a251f9dd0..72bb21a812 100644
--- a/engines/mads/sound.h
+++ b/engines/mads/sound.h
@@ -37,6 +37,7 @@ class SoundManager {
private:
MADSEngine *_vm;
Audio::Mixer *_mixer;
+ FM_OPL *_opl;
Nebular::ASound *_driver;
bool _pollSoundEnabled;
bool _soundPollFlag;
diff --git a/engines/mads/sprites.cpp b/engines/mads/sprites.cpp
index 2bf13eeb5a..fd73930475 100644
--- a/engines/mads/sprites.cpp
+++ b/engines/mads/sprites.cpp
@@ -262,7 +262,7 @@ void SpriteSlots::drawBackground() {
scene._backgroundSurface.copyFrom(frame, pt, spriteSlot._depth, &scene._depthSurface,
-1, false, frame->getTransparencyIndex());
} else {
- error("Unsupported depth style");
+ frame->copyTo(&scene._backgroundSurface, pt, frame->getTransparencyIndex());
}
}
}
@@ -331,8 +331,6 @@ void SpriteSlots::drawSprites(MSurface *s) {
xp = slot._position.x - (sprite->w / 2) - scene._posAdjust.x;
yp = slot._position.y - sprite->h - scene._posAdjust.y + 1;
}
- xp += _vm->_screen._offset.x;
- yp += _vm->_screen._offset.y;
if (slot._depth > 1) {
// Draw the frame with depth processing
@@ -406,9 +404,9 @@ void SpriteSets::remove(int idx) {
delete (*this)[idx];
(*this)[idx] = nullptr;
} else {
- while (size() > 0 && (*this)[size() - 1] == nullptr) {
+ do {
remove_at(size() - 1);
- }
+ } while (size() > 0 && (*this)[size() - 1] == nullptr);
}
if (_assetCount > 0)
diff --git a/engines/mads/user_interface.h b/engines/mads/user_interface.h
index f251441e40..89044c9bf1 100644
--- a/engines/mads/user_interface.h
+++ b/engines/mads/user_interface.h
@@ -225,7 +225,7 @@ public:
/**
* Loads an interface from a specified resource
*/
- void load(const Common::String &resName);
+ virtual void load(const Common::String &resName);
/**
* Set up the interface
diff --git a/engines/mortevielle/detection_tables.h b/engines/mortevielle/detection_tables.h
index 0aa27b89eb..d244d15365 100644
--- a/engines/mortevielle/detection_tables.h
+++ b/engines/mortevielle/detection_tables.h
@@ -75,7 +75,7 @@ static const MortevielleGameDescription MortevielleGameDescriptions[] = {
// DOS English version doesn't exist. Technically, they are French or German versions,
// using English strings stored mort.dat
-
+
// English on top of French version
{
{
diff --git a/engines/mortevielle/mortevielle.h b/engines/mortevielle/mortevielle.h
index c3d1e4ae8b..5f7f175c26 100644
--- a/engines/mortevielle/mortevielle.h
+++ b/engines/mortevielle/mortevielle.h
@@ -421,7 +421,7 @@ public:
byte *_curPict;
byte *_curAnim;
byte *_rightFramePict;
-
+
PaletteManager _paletteManager;
GfxSurface _backgroundSurface;
Common::RandomSource _randomSource;
diff --git a/engines/mortevielle/utils.cpp b/engines/mortevielle/utils.cpp
index d5dec6a286..40136ad78b 100644
--- a/engines/mortevielle/utils.cpp
+++ b/engines/mortevielle/utils.cpp
@@ -3097,7 +3097,7 @@ void MortevielleEngine::putObject() {
*/
void MortevielleEngine::addObjectToInventory(int objectId) {
int i;
-
+
for (i = 1; (i <= 5) && (_coreVar._inventory[i] != 0); i++)
;
diff --git a/engines/neverhood/console.cpp b/engines/neverhood/console.cpp
index 91ab3e767a..7ee6b30311 100644
--- a/engines/neverhood/console.cpp
+++ b/engines/neverhood/console.cpp
@@ -55,7 +55,7 @@ bool Console::Cmd_Scene(int argc, const char **argv) {
const char *sceneTypes[] = { "normal", "smacker", "navigation" };
- debugPrintf("Current module: %d, previous module: %d, scene %d (%s scene)\n", currentModule, previousModule, scenenNum, sceneTypes[sceneType]);
+ debugPrintf("Current module: %d, previous module: %d, scene %d (%s scene)\n", currentModule, previousModule, scenenNum, sceneTypes[sceneType]);
if (sceneType == kSceneTypeNormal) {
Scene *scene = (Scene *)((GameModule *)_vm->_gameModule->_childObject)->_childObject;
diff --git a/engines/neverhood/sound.cpp b/engines/neverhood/sound.cpp
index d53243d4ba..b15bea4a64 100644
--- a/engines/neverhood/sound.cpp
+++ b/engines/neverhood/sound.cpp
@@ -560,7 +560,7 @@ int NeverhoodAudioStream::readBuffer(int16 *buffer, const int numSamples) {
} else {
while (samplesRead--) {
*buffer++ = READ_LE_UINT16(src);
- src += 2;
+ src += 2;
}
}
diff --git a/engines/pegasus/energymonitor.cpp b/engines/pegasus/energymonitor.cpp
index 40e54afb89..d3cc208e41 100644
--- a/engines/pegasus/energymonitor.cpp
+++ b/engines/pegasus/energymonitor.cpp
@@ -68,7 +68,9 @@ void Blinker::timeChanged(const TimeValue time) {
}
}
-static const NotificationFlags kEnergyExpiredFlag = 1;
+enum {
+ kEnergyExpiredFlag = 1
+};
EnergyMonitor *g_energyMonitor = 0;
diff --git a/engines/pegasus/input.cpp b/engines/pegasus/input.cpp
index e1b7e25cd5..73c319bd8b 100644
--- a/engines/pegasus/input.cpp
+++ b/engines/pegasus/input.cpp
@@ -57,7 +57,7 @@ InputDeviceManager::InputDeviceManager() {
_keyMap[Common::KEYCODE_p] = false;
_keyMap[Common::KEYCODE_TILDE] = false;
_keyMap[Common::KEYCODE_BACKQUOTE] = false;
- _keyMap[Common::KEYCODE_KP7] = false;
+ _keyMap[Common::KEYCODE_KP7] = false;
_keyMap[Common::KEYCODE_BACKSPACE] = false;
_keyMap[Common::KEYCODE_KP_MULTIPLY] = false;
_keyMap[Common::KEYCODE_KP9] = false;
diff --git a/engines/pegasus/interaction.cpp b/engines/pegasus/interaction.cpp
new file mode 100644
index 0000000000..143bdebaba
--- /dev/null
+++ b/engines/pegasus/interaction.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.
+ *
+ * Additional copyright for this file:
+ * Copyright (C) 1995-1997 Presto Studios, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public 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 "pegasus/interaction.h"
+#include "pegasus/neighborhood/neighborhood.h"
+
+namespace Pegasus {
+
+GameInteraction::GameInteraction(const InteractionID id, Neighborhood *nextHandler) : IDObject(id), InputHandler(nextHandler) {
+ _isInteracting = false;
+ _savedHandler = 0;
+ _owner = nextHandler;
+}
+
+} // End of namespace Pegasus
+
diff --git a/engines/pegasus/interaction.h b/engines/pegasus/interaction.h
index 293ee6be83..ca168b4cb7 100644
--- a/engines/pegasus/interaction.h
+++ b/engines/pegasus/interaction.h
@@ -37,11 +37,7 @@ class Neighborhood;
class GameInteraction : public IDObject, public InputHandler {
public:
- GameInteraction(const InteractionID id, Neighborhood *nextHandler) : IDObject(id), InputHandler((InputHandler *)nextHandler) {
- _isInteracting = false;
- _savedHandler = 0;
- _owner = nextHandler;
- }
+ GameInteraction(const InteractionID id, Neighborhood *nextHandler);
// If the interaction is open (_isInteracting == true), it's too late to do anything
// about it here.
diff --git a/engines/pegasus/module.mk b/engines/pegasus/module.mk
index cb44a04171..6d69d6ea58 100644
--- a/engines/pegasus/module.mk
+++ b/engines/pegasus/module.mk
@@ -12,6 +12,7 @@ MODULE_OBJS = \
graphics.o \
hotspot.o \
input.o \
+ interaction.o \
interface.o \
menu.o \
movie.o \
diff --git a/engines/pegasus/neighborhood/caldoria/caldoria.cpp b/engines/pegasus/neighborhood/caldoria/caldoria.cpp
index 9d2d6723a9..ed52851338 100644
--- a/engines/pegasus/neighborhood/caldoria/caldoria.cpp
+++ b/engines/pegasus/neighborhood/caldoria/caldoria.cpp
@@ -42,109 +42,119 @@
namespace Pegasus {
-static const int16 kVidPhoneAngle = 30;
-static const int16 kReplicatorAngle = 50;
-static const int16 kDrawersAngle = -30;
-static const int16 kCaldoria53Angle = 45;
-static const int16 kCaldoria55Angle = -45;
+enum {
+ kVidPhoneAngle = 30,
+ kReplicatorAngle = 50,
+ kDrawersAngle = -30,
+ kCaldoria53Angle = 45,
+ kCaldoria55Angle = -45
+};
-static const TimeValue kSinclairInterruptionTime1 = 2955;
-static const TimeValue kSinclairInterruptionTime2 = 6835;
-static const TimeValue kSinclairInterruptionTime3 = 9835;
-static const TimeValue kSinclairInterruptionTime4 = 12555;
+enum {
+ kSinclairInterruptionTime1 = 2955,
+ kSinclairInterruptionTime2 = 6835,
+ kSinclairInterruptionTime3 = 9835,
+ kSinclairInterruptionTime4 = 12555
+};
-static const InputBits kPullbackInterruptFilter = kFilterAllInput;
-static const InputBits kRecalibrationInterruptFilter = kFilterAllInput;
+enum {
+ kPullbackInterruptFilter = kFilterAllInput,
+ kRecalibrationInterruptFilter = kFilterAllInput
+};
-static const TimeValue kCaldoriaReplicatorIntroIn = 4933;
-static const TimeValue kCaldoriaReplicatorIntroOut = 6557;
+enum {
+ kCaldoriaReplicatorIntroIn = 4933,
+ kCaldoriaReplicatorIntroOut = 6557,
-static const TimeValue kCaldoriaReplicatorWrongChoiceIn = 6557;
-static const TimeValue kCaldoriaReplicatorWrongChoiceOut = 8586;
+ kCaldoriaReplicatorWrongChoiceIn = 6557,
+ kCaldoriaReplicatorWrongChoiceOut = 8586,
-static const TimeValue kCaldoriaReplicatorOJChoiceIn = 8586;
-static const TimeValue kCaldoriaReplicatorOJChoiceOut = 11687;
+ kCaldoriaReplicatorOJChoiceIn = 8586,
+ kCaldoriaReplicatorOJChoiceOut = 11687,
-static const TimeValue kCaldoriaMessagesIntroIn = 11687;
-static const TimeValue kCaldoriaMessagesIntroOut = 13641;
+ kCaldoriaMessagesIntroIn = 11687,
+ kCaldoriaMessagesIntroOut = 13641,
-static const TimeValue kCaldoriaFirstMessageIn = 13641;
-static const TimeValue kCaldoriaFirstMessageOut = 14203;
+ kCaldoriaFirstMessageIn = 13641,
+ kCaldoriaFirstMessageOut = 14203,
-static const TimeValue kCaldoriaSecondMessageIn = 14203;
-static const TimeValue kCaldoriaSecondMessageOut = 14750;
+ kCaldoriaSecondMessageIn = 14203,
+ kCaldoriaSecondMessageOut = 14750,
-static const TimeValue kCaldoriaDoorCloseIn = 14750;
-static const TimeValue kCaldoriaDoorCloseOut = 15472;
+ kCaldoriaDoorCloseIn = 14750,
+ kCaldoriaDoorCloseOut = 15472,
-static const TimeValue kCaldoriaElevatorCloseIn = 15472;
-static const TimeValue kCaldoriaElevatorCloseOut = 16336;
+ kCaldoriaElevatorCloseIn = 15472,
+ kCaldoriaElevatorCloseOut = 16336,
-static const TimeValue kCaldoriaShowerCloseIn = 16336;
-static const TimeValue kCaldoriaShowerCloseOut = 17101;
+ kCaldoriaShowerCloseIn = 16336,
+ kCaldoriaShowerCloseOut = 17101,
-static const TimeValue kCaldoriaGTDoorCloseIn = 17101;
-static const TimeValue kCaldoriaGTDoorCloseOut = 18523;
+ kCaldoriaGTDoorCloseIn = 17101,
+ kCaldoriaGTDoorCloseOut = 18523,
-static const TimeValue kCaldoriaNobodyHomeIn = 18523;
-static const TimeValue kCaldoriaNobodyHomeOut = 21469;
+ kCaldoriaNobodyHomeIn = 18523,
+ kCaldoriaNobodyHomeOut = 21469,
-static const TimeValue kCaldoriaNoOtherFloorIn = 21469;
-static const TimeValue kCaldoriaNoOtherFloorOut = 28013;
+ kCaldoriaNoOtherFloorIn = 21469,
+ kCaldoriaNoOtherFloorOut = 28013,
-static const TimeValue kCaldoria4DInstructionsIn = 28013;
-static const TimeValue kCaldoria4DInstructionsOut = 29730;
+ kCaldoria4DInstructionsIn = 28013,
+ kCaldoria4DInstructionsOut = 29730,
-static const TimeValue kCaldoriaDrinkOJIn = 33910;
-static const TimeValue kCaldoriaDrinkOJOut = 35846;
+ kCaldoriaDrinkOJIn = 33910,
+ kCaldoriaDrinkOJOut = 35846,
-static const TimeValue kCaldoriaNoOtherDestinationIn = 35846;
-static const TimeValue kCaldoriaNoOtherDestinationOut = 37877;
+ kCaldoriaNoOtherDestinationIn = 35846,
+ kCaldoriaNoOtherDestinationOut = 37877,
-static const TimeValue kCaldoriaUhghIn = 37877;
-static const TimeValue kCaldoriaUhghOut = 38025;
+ kCaldoriaUhghIn = 37877,
+ kCaldoriaUhghOut = 38025,
-static const TimeValue kCaldoriaSinclairShootsOSIn = 38025;
-static const TimeValue kCaldoriaSinclairShootsOSOut = 40649;
+ kCaldoriaSinclairShootsOSIn = 38025,
+ kCaldoriaSinclairShootsOSOut = 40649,
-static const TimeValue kCaldoriaScreamingAfterIn = 40649;
-static const TimeValue kCaldoriaScreamingAfterOut = 47661;
+ kCaldoriaScreamingAfterIn = 40649,
+ kCaldoriaScreamingAfterOut = 47661
+};
-static const TimeValue k4FloorTime = 0;
+enum {
+ k4FloorTime = 0,
-static const TimeValue k4To1Start = 40;
-static const TimeValue k4To1Stop = 7720;
+ k4To1Start = 40,
+ k4To1Stop = 7720,
-static const TimeValue k4To5Start = 7720;
-static const TimeValue k4To5Stop = 10280;
+ k4To5Start = 7720,
+ k4To5Stop = 10280,
-static const TimeValue k4To2Time = 10280;
+ k4To2Time = 10280,
-static const TimeValue k4To3Time = 10320;
+ k4To3Time = 10320,
-static const TimeValue k1FloorTime = 10360;
+ k1FloorTime = 10360,
-static const TimeValue k1To4Start = 10400;
-static const TimeValue k1To4Stop = 18080;
+ k1To4Start = 10400,
+ k1To4Stop = 18080,
-static const TimeValue k1To5Start = 18080;
-static const TimeValue k1To5Stop = 28320;
+ k1To5Start = 18080,
+ k1To5Stop = 28320,
-static const TimeValue k1To2Time = 28320;
+ k1To2Time = 28320,
-static const TimeValue k1To3Time = 28360;
+ k1To3Time = 28360,
-static const TimeValue k5FloorTime = 28400;
+ k5FloorTime = 28400,
-static const TimeValue k5To1Start = 28440;
-static const TimeValue k5To1Stop = 38680;
+ k5To1Start = 28440,
+ k5To1Stop = 38680,
-static const TimeValue k5To4Start = 38680;
-static const TimeValue k5To4Stop = 41240;
+ k5To4Start = 38680,
+ k5To4Stop = 41240,
-static const TimeValue k5To2Time = 41240;
+ k5To2Time = 41240,
-static const TimeValue k5To3Time = 41280;
+ k5To3Time = 41280
+};
// FuseFunction functions...
diff --git a/engines/pegasus/neighborhood/caldoria/caldoria4dsystem.cpp b/engines/pegasus/neighborhood/caldoria/caldoria4dsystem.cpp
index 0494753661..688fb7860d 100644
--- a/engines/pegasus/neighborhood/caldoria/caldoria4dsystem.cpp
+++ b/engines/pegasus/neighborhood/caldoria/caldoria4dsystem.cpp
@@ -30,34 +30,36 @@
namespace Pegasus {
-static const TimeValue kSwitchableSlop = 3 * kCaldoriaFrameDuration;
-// Two seconds - some slop
-static const TimeValue kSwitchableDuration = kCaldoriaMovieScale * 2 - kSwitchableSlop;
-// Twelve frames + some slop
-static const TimeValue kNonswitchableDuration = kCaldoriaFrameDuration * 12 + kSwitchableSlop;
+enum {
+ kSwitchableSlop = 3 * kCaldoriaFrameDuration,
+ // Two seconds - some slop
+ kSwitchableDuration = kCaldoriaMovieScale * 2 - kSwitchableSlop,
+ // Twelve frames + some slop
+ kNonswitchableDuration = kCaldoriaFrameDuration * 12 + kSwitchableSlop,
-static const TimeValue kSwitchable1Start = 0;
-static const TimeValue kSwitchable1Stop = kSwitchable1Start + kSwitchableDuration;
+ kSwitchable1Start = 0,
+ kSwitchable1Stop = kSwitchable1Start + kSwitchableDuration,
-static const TimeValue kSwitchable2Start = kSwitchable1Stop + kNonswitchableDuration;
-static const TimeValue kSwitchable2Stop = kSwitchable2Start + kSwitchableDuration;
+ kSwitchable2Start = kSwitchable1Stop + kNonswitchableDuration,
+ kSwitchable2Stop = kSwitchable2Start + kSwitchableDuration,
-static const TimeValue kSwitchable3Start = kSwitchable2Stop + kNonswitchableDuration;
-static const TimeValue kSwitchable3Stop = kSwitchable3Start + kSwitchableDuration;
+ kSwitchable3Start = kSwitchable2Stop + kNonswitchableDuration,
+ kSwitchable3Stop = kSwitchable3Start + kSwitchableDuration,
-static const NotificationFlags kVidPhoneDoneFlag = 1;
+ kVidPhoneDoneFlag = 1,
-static const TimeValue kRockMusicLoopIn = 0;
-static const TimeValue kRockMusicLoopOut = 2088;
+ kRockMusicLoopIn = 0,
+ kRockMusicLoopOut = 2088,
-static const TimeValue kOrchestralMusicLoopIn = 2088;
-static const TimeValue kOrchestralMusicLoopOut = 4985;
+ kOrchestralMusicLoopIn = 2088,
+ kOrchestralMusicLoopOut = 4985,
-static const TimeValue kRhythmsMusicLoopIn = 4985;
-static const TimeValue kRhythmsMusicLoopOut = 6824;
+ kRhythmsMusicLoopIn = 4985,
+ kRhythmsMusicLoopOut = 6824,
-static const TimeValue kAcousticMusicLoopIn = 6824;
-static const TimeValue kAcousticMusicLoopOut = 9387;
+ kAcousticMusicLoopIn = 6824,
+ kAcousticMusicLoopOut = 9387
+};
enum {
k4DVideoMenu,
diff --git a/engines/pegasus/neighborhood/mars/shuttlehud.cpp b/engines/pegasus/neighborhood/mars/shuttlehud.cpp
index 11e826278b..2d894f7b95 100644
--- a/engines/pegasus/neighborhood/mars/shuttlehud.cpp
+++ b/engines/pegasus/neighborhood/mars/shuttlehud.cpp
@@ -30,26 +30,28 @@
namespace Pegasus {
-static const CoordType kHUDTargetGridLeft = kShuttleWindowLeft + 16;
-static const CoordType kHUDTargetGridTop = kShuttleWindowTop + 8;
-static const CoordType kHUDTargetGridWidth = 328;
-static const CoordType kHUDTargetGridHeight = 206;
-
-static const CoordType kHUDRS232Left = kHUDTargetGridLeft + 264;
-static const CoordType kHUDRS232Top = kHUDTargetGridTop + 2;
-
-static const CoordType kHUDLockLeft = kShuttleWindowLeft + 101;
-static const CoordType kHUDLockTop = kShuttleWindowTop + 49;
-static const CoordType kHUDLockWidth = 145;
-static const CoordType kHUDLockHeight = 124;
-
-static const CoordType kTractorLockWidth = 50;
-static const CoordType kTractorLockHeight = 30;
-
-static const CoordType kTractorLockLeft = kShuttleWindowMidH - kTractorLockWidth / 2;
-static const CoordType kTractorLockTop = kShuttleWindowMidV - kTractorLockHeight / 2;
-static const CoordType kTractorLockRight = kTractorLockLeft + kTractorLockWidth;
-static const CoordType kTractorLockBottom = kTractorLockTop + kTractorLockHeight;
+enum {
+ kHUDTargetGridLeft = kShuttleWindowLeft + 16,
+ kHUDTargetGridTop = kShuttleWindowTop + 8,
+ kHUDTargetGridWidth = 328,
+ kHUDTargetGridHeight = 206,
+
+ kHUDRS232Left = kHUDTargetGridLeft + 264,
+ kHUDRS232Top = kHUDTargetGridTop + 2,
+
+ kHUDLockLeft = kShuttleWindowLeft + 101,
+ kHUDLockTop = kShuttleWindowTop + 49,
+ kHUDLockWidth = 145,
+ kHUDLockHeight = 124,
+
+ kTractorLockWidth = 50,
+ kTractorLockHeight = 30,
+
+ kTractorLockLeft = kShuttleWindowMidH - kTractorLockWidth / 2,
+ kTractorLockTop = kShuttleWindowMidV - kTractorLockHeight / 2,
+ kTractorLockRight = kTractorLockLeft + kTractorLockWidth,
+ kTractorLockBottom = kTractorLockTop + kTractorLockHeight
+};
static const uint16 s_RS232Data[] = {
0xF0E1, 0xCE70,
diff --git a/engines/pegasus/neighborhood/norad/alpha/ecrmonitor.cpp b/engines/pegasus/neighborhood/norad/alpha/ecrmonitor.cpp
index e2a0267231..1478a74744 100644
--- a/engines/pegasus/neighborhood/norad/alpha/ecrmonitor.cpp
+++ b/engines/pegasus/neighborhood/norad/alpha/ecrmonitor.cpp
@@ -45,7 +45,9 @@ static const TimeValue kSection2Start = 26;
static const TimeValue kSection2Stop = 1000;
// Seems to be a good value for a 20 second pan.
-static const CoordType kPanPixelsPerFrame = 8;
+enum {
+ kPanPixelsPerFrame = 8
+};
// Interesting times are in seconds.
static const TimeValue s_ECRInterestingTimes[] = {
diff --git a/engines/pegasus/neighborhood/norad/alpha/fillingstation.cpp b/engines/pegasus/neighborhood/norad/alpha/fillingstation.cpp
index 3491f161c7..e85a3e699f 100644
--- a/engines/pegasus/neighborhood/norad/alpha/fillingstation.cpp
+++ b/engines/pegasus/neighborhood/norad/alpha/fillingstation.cpp
@@ -65,64 +65,66 @@ static const ItemID kCO2Item = 10000;
static const ItemID kHeItem = 10001;
// Interactive points.
-static const TimeValue kFSPowerUpStartStart = 0;
-static const TimeValue kFSPowerUpStartStop = 600;
-static const TimeValue kFSSplashStart = 600;
-static const TimeValue kFSSplashStop = 7800;
-static const TimeValue kFSSplashIntakeStart = 7800;
-static const TimeValue kFSSplashIntakeStop = 18600;
-
-static const TimeValue kFSMainMenu = 18600;
-static const TimeValue kFSIntakeHiliteStart = 19200;
-static const TimeValue kFSIntakeHiliteStop = 19800;
-static const TimeValue kFSDispenseHiliteStart = 19800;
-static const TimeValue kFSDispenseHiliteStop = 20400;
-
-static const TimeValue kFSDispenseMenu = 20400;
-
-static const TimeValue kFSArHiliteStart = 21000;
-static const TimeValue kFSArHiliteStop = 21600;
-static const TimeValue kFSArAttach = 21600;
-static const TimeValue kFSArFilledStart = 22200;
-static const TimeValue kFSArFilledStop = 25200;
-static const TimeValue kFSArIncompatibleStart = 25200;
-static const TimeValue kFSArIncompatibleStop = 30000;
-
-static const TimeValue kFSCO2HiliteStart = 30000;
-static const TimeValue kFSCO2HiliteStop = 30600;
-static const TimeValue kFSCO2Attach = 30600;
-static const TimeValue kFSCO2FilledStart = 31200;
-static const TimeValue kFSCO2FilledStop = 34200;
-static const TimeValue kFSCO2IncompatibleStart = 34200;
-static const TimeValue kFSCO2IncompatibleStop = 39000;
-
-static const TimeValue kFSHeHiliteStart = 39000;
-static const TimeValue kFSHeHiliteStop = 39600;
-static const TimeValue kFSHeAttach = 39600;
-static const TimeValue kFSHeFilledStart = 40200;
-static const TimeValue kFSHeFilledStop = 43200;
-static const TimeValue kFSHeIncompatibleStart = 43200;
-static const TimeValue kFSHeIncompatibleStop = 48000;
-
-static const TimeValue kFSOHiliteStart = 48000;
-static const TimeValue kFSOHiliteStop = 48600;
-static const TimeValue kFSOAttach = 48600;
-static const TimeValue kFSOFilledStart = 49200;
-static const TimeValue kFSOFilledStop = 52200;
-static const TimeValue kFSOIncompatibleStart = 52200;
-static const TimeValue kFSOIncompatibleStop = 57000;
-
-static const TimeValue kFSNHiliteStart = 57000;
-static const TimeValue kFSNHiliteStop = 57600;
-static const TimeValue kFSNAttach = 57600;
-static const TimeValue kFSNFilledStart = 58200;
-static const TimeValue kFSNFilledStop = 61200;
-static const TimeValue kFSNIncompatibleStart = 61200;
-static const TimeValue kFSNIncompatibleStop = 66000;
-
-static const TimeValue kFSIntakeMenu = 66000;
-static const TimeValue kFSIntakeInProgressStart = 66600;
-static const TimeValue kFSIntakeInProgressStop = 69600;
+enum {
+ kFSPowerUpStartStart = 0,
+ kFSPowerUpStartStop = 600,
+ kFSSplashStart = 600,
+ kFSSplashStop = 7800,
+ kFSSplashIntakeStart = 7800,
+ kFSSplashIntakeStop = 18600,
+
+ kFSMainMenu = 18600,
+ kFSIntakeHiliteStart = 19200,
+ kFSIntakeHiliteStop = 19800,
+ kFSDispenseHiliteStart = 19800,
+ kFSDispenseHiliteStop = 20400,
+
+ kFSDispenseMenu = 20400,
+
+ kFSArHiliteStart = 21000,
+ kFSArHiliteStop = 21600,
+ kFSArAttach = 21600,
+ kFSArFilledStart = 22200,
+ kFSArFilledStop = 25200,
+ kFSArIncompatibleStart = 25200,
+ kFSArIncompatibleStop = 30000,
+
+ kFSCO2HiliteStart = 30000,
+ kFSCO2HiliteStop = 30600,
+ kFSCO2Attach = 30600,
+ kFSCO2FilledStart = 31200,
+ kFSCO2FilledStop = 34200,
+ kFSCO2IncompatibleStart = 34200,
+ kFSCO2IncompatibleStop = 39000,
+
+ kFSHeHiliteStart = 39000,
+ kFSHeHiliteStop = 39600,
+ kFSHeAttach = 39600,
+ kFSHeFilledStart = 40200,
+ kFSHeFilledStop = 43200,
+ kFSHeIncompatibleStart = 43200,
+ kFSHeIncompatibleStop = 48000,
+
+ kFSOHiliteStart = 48000,
+ kFSOHiliteStop = 48600,
+ kFSOAttach = 48600,
+ kFSOFilledStart = 49200,
+ kFSOFilledStop = 52200,
+ kFSOIncompatibleStart = 52200,
+ kFSOIncompatibleStop = 57000,
+
+ kFSNHiliteStart = 57000,
+ kFSNHiliteStop = 57600,
+ kFSNAttach = 57600,
+ kFSNFilledStart = 58200,
+ kFSNFilledStop = 61200,
+ kFSNIncompatibleStart = 61200,
+ kFSNIncompatibleStop = 66000,
+
+ kFSIntakeMenu = 66000,
+ kFSIntakeInProgressStart = 66600,
+ kFSIntakeInProgressStop = 69600
+};
NoradAlphaFillingStation::NoradAlphaFillingStation(Neighborhood *owner) : GameInteraction(kNoradFillingStationInteractionID, owner),
_rightSideMovie(kN01RightSideID), _rightSideNotification(kNoradFillingStationNotificationID, ((PegasusEngine *)g_engine)) {
diff --git a/engines/pegasus/neighborhood/norad/delta/globegame.cpp b/engines/pegasus/neighborhood/norad/delta/globegame.cpp
index 5c321a8e8a..9ea3036024 100644
--- a/engines/pegasus/neighborhood/norad/delta/globegame.cpp
+++ b/engines/pegasus/neighborhood/norad/delta/globegame.cpp
@@ -394,20 +394,22 @@ static const NotificationFlags kGlobeNotificationFlags = kGlobeSplash1Finished |
kGlobeTimerExpired |
kMaxDeactivatedFinished;
-static const int16 kSplash1End = 4;
-static const int16 kSplash2End = 5;
-static const int16 kSplash3Start = 8;
-static const int16 kSplash3Stop = 9;
-static const int16 kSplash4Start = 9;
-static const int16 kSplash4Stop = 10;
-static const int16 kNewLaunchSiloTime = 10;
-static const int16 kSiloDeactivatedTime = 11;
-static const int16 kMissileLaunchedTime = 12;
-static const int16 kMaxDeactivatedStart = 13;
-static const int16 kMaxDeactivatedStop = 23;
-
-static const int16 kGamePlaying = 1;
-static const int16 kGameOver = 2;
+enum {
+ kSplash1End = 4,
+ kSplash2End = 5,
+ kSplash3Start = 8,
+ kSplash3Stop = 9,
+ kSplash4Start = 9,
+ kSplash4Stop = 10,
+ kNewLaunchSiloTime = 10,
+ kSiloDeactivatedTime = 11,
+ kMissileLaunchedTime = 12,
+ kMaxDeactivatedStart = 13,
+ kMaxDeactivatedStop = 23,
+
+ kGamePlaying = 1,
+ kGameOver = 2
+};
enum {
kGameIntro,
diff --git a/engines/pegasus/neighborhood/norad/subcontrolroom.cpp b/engines/pegasus/neighborhood/norad/subcontrolroom.cpp
index d48481e925..1b14c529d8 100644
--- a/engines/pegasus/neighborhood/norad/subcontrolroom.cpp
+++ b/engines/pegasus/neighborhood/norad/subcontrolroom.cpp
@@ -34,110 +34,113 @@ namespace Pegasus {
// Right Monitor times
-static const TimeValue kAlphaClawSplashStart = 0;
-static const TimeValue kAlphaClawSplashStop = 4000;
-
-static const TimeValue kDeltaClawSplashStart = 4000;
-static const TimeValue kDeltaClawSplashStop = 8000;
-
-static const TimeValue kClawAtATime = 8000;
-static const TimeValue kClawAtAPinchedTime = 8600;
-static const TimeValue kClawAtATurnedTime = 9200;
-static const TimeValue kClawAtAWithRobotPinchedTime = 9800;
-
-static const TimeValue kClawAtBTime = 10400;
-static const TimeValue kClawAtBPinchedTime = 11000;
-static const TimeValue kClawAtBTurnedTime = 11600;
-static const TimeValue kClawAtBWithRobotTime = 12200;
-static const TimeValue kClawAtBWithRobotPinchedTime = 12800;
-
-static const TimeValue kClawAtCTime = 13400;
-static const TimeValue kClawAtCPinchedTime = 14000;
-static const TimeValue kClawAtCTurnedTime = 14600;
-
-static const TimeValue kClawAtDTime = 15200;
-static const TimeValue kClawAtDPinchedTime = 15800;
-static const TimeValue kClawAtDTurnedTime = 16400;
-
-static const TimeValue kAToBStart = 17000;
-static const TimeValue kAToBStop = 18680;
-static const TimeValue kAPinchStart = 18680;
-static const TimeValue kAPinchStop = 20200;
-static const TimeValue kACCWStart = 20200;
-static const TimeValue kACCWStop = 21600;
-static const TimeValue kACWStart = 21600;
-static const TimeValue kACWStop = 23000;
-
-static const TimeValue kBToAStart = 23000;
-static const TimeValue kBToAStop = 24680;
-static const TimeValue kBToCStart = 24680;
-static const TimeValue kBToCStop = 26520;
-static const TimeValue kBToDStart = 26520;
-static const TimeValue kBToDStop = 28320;
-static const TimeValue kBPinchStart = 28320;
-static const TimeValue kBPinchStop = 29680;
-static const TimeValue kBCCWStart = 29680;
-static const TimeValue kBCCWStop = 31200;
-static const TimeValue kBCWStart = 31200;
-static const TimeValue kBCWStop = 32720;
-
-static const TimeValue kCToBStart = 32720;
-static const TimeValue kCToBStop = 34560;
-static const TimeValue kCPinchStart = 34560;
-static const TimeValue kCPinchStop = 36400;
-static const TimeValue kCCCWStart = 36400;
-static const TimeValue kCCCWStop = 37840;
-static const TimeValue kCCWStart = 37840;
-static const TimeValue kCCWStop = 39280;
-
-static const TimeValue kDToBStart = 39280;
-static const TimeValue kDToBStop = 41080;
-static const TimeValue kDPinchStart = 41080;
-static const TimeValue kDPinchStop = 42600;
-static const TimeValue kDCCWStart = 42600;
-static const TimeValue kDCCWStop = 44000;
-static const TimeValue kDCWStart = 44000;
-static const TimeValue kDCWStop = 45400;
-
-static const TimeValue kRobotApproachStart = 45400;
-static const TimeValue kRobotApproachStop = 56800;
-
-static const TimeValue kCToBWithRobotStart = 56800;
-static const TimeValue kCToBWithRobotStop = 58600;
-
-static const TimeValue kBPinchWithRobotStart = 58600;
-static const TimeValue kBPinchWithRobotStop = 60400;
-static const TimeValue kBToAWithRobotStart = 60400;
-static const TimeValue kBToAWithRobotStop = 62240;
+enum {
+ kAlphaClawSplashStart = 0,
+ kAlphaClawSplashStop = 4000,
+
+ kDeltaClawSplashStart = 4000,
+ kDeltaClawSplashStop = 8000,
+
+ kClawAtATime = 8000,
+ kClawAtAPinchedTime = 8600,
+ kClawAtATurnedTime = 9200,
+ kClawAtAWithRobotPinchedTime = 9800,
+
+ kClawAtBTime = 10400,
+ kClawAtBPinchedTime = 11000,
+ kClawAtBTurnedTime = 11600,
+ kClawAtBWithRobotTime = 12200,
+ kClawAtBWithRobotPinchedTime = 12800,
+
+ kClawAtCTime = 13400,
+ kClawAtCPinchedTime = 14000,
+ kClawAtCTurnedTime = 14600,
+
+ kClawAtDTime = 15200,
+ kClawAtDPinchedTime = 15800,
+ kClawAtDTurnedTime = 16400,
+
+ kAToBStart = 17000,
+ kAToBStop = 18680,
+ kAPinchStart = 18680,
+ kAPinchStop = 20200,
+ kACCWStart = 20200,
+ kACCWStop = 21600,
+ kACWStart = 21600,
+ kACWStop = 23000,
+
+ kBToAStart = 23000,
+ kBToAStop = 24680,
+ kBToCStart = 24680,
+ kBToCStop = 26520,
+ kBToDStart = 26520,
+ kBToDStop = 28320,
+ kBPinchStart = 28320,
+ kBPinchStop = 29680,
+ kBCCWStart = 29680,
+ kBCCWStop = 31200,
+ kBCWStart = 31200,
+ kBCWStop = 32720,
+
+ kCToBStart = 32720,
+ kCToBStop = 34560,
+ kCPinchStart = 34560,
+ kCPinchStop = 36400,
+ kCCCWStart = 36400,
+ kCCCWStop = 37840,
+ kCCWStart = 37840,
+ kCCWStop = 39280,
+
+ kDToBStart = 39280,
+ kDToBStop = 41080,
+ kDPinchStart = 41080,
+ kDPinchStop = 42600,
+ kDCCWStart = 42600,
+ kDCCWStop = 44000,
+ kDCWStart = 44000,
+ kDCWStop = 45400,
+
+ kRobotApproachStart = 45400,
+ kRobotApproachStop = 56800,
+
+ kCToBWithRobotStart = 56800,
+ kCToBWithRobotStop = 58600,
+
+ kBPinchWithRobotStart = 58600,
+ kBPinchWithRobotStop = 60400,
+ kBToAWithRobotStart = 60400,
+ kBToAWithRobotStop = 62240
+};
// As usual, times here are in seconds.
// Left monitor times.
+enum {
+ kAlphaSplashStart = 0,
+ kAlphaSplashStop = 2,
-static const TimeValue kAlphaSplashStart = 0;
-static const TimeValue kAlphaSplashStop = 2;
-
-static const TimeValue kMainMenuTime = 2;
-static const TimeValue kLaunchPrepRolloverTime = 3;
-static const TimeValue kLaunchPrepHighlightStart = 4;
-static const TimeValue kLaunchPrepHighlightStop = 5;
-static const TimeValue kClawControlRolloverTime = 5;
-static const TimeValue kClawControlHighlightStart = 6;
-static const TimeValue kClawControlHighlightStop = 7;
+ kMainMenuTime = 2,
+ kLaunchPrepRolloverTime = 3,
+ kLaunchPrepHighlightStart = 4,
+ kLaunchPrepHighlightStop = 5,
+ kClawControlRolloverTime = 5,
+ kClawControlHighlightStart = 6,
+ kClawControlHighlightStop = 7,
-static const TimeValue kAlphaLaunchPrepStart = 7;
-static const TimeValue kAlphaLaunchPrepStop = 17;
+ kAlphaLaunchPrepStart = 7,
+ kAlphaLaunchPrepStop = 17,
-static const TimeValue kClawMenuStart = 17;
-static const TimeValue kClawMenuStop = 18;
+ kClawMenuStart = 17,
+ kClawMenuStop = 18,
-static const TimeValue kClawMenuTime = 18;
+ kClawMenuTime = 18,
-static const TimeValue kDeltaSplashStart = 19;
-static const TimeValue kDeltaSplashStop = 21;
+ kDeltaSplashStart = 19,
+ kDeltaSplashStop = 21,
-static const TimeValue kDeltaLaunchPrepStart = 21;
-static const TimeValue kDeltaLaunchPrepStop = 30;
+ kDeltaLaunchPrepStart = 21,
+ kDeltaLaunchPrepStop = 30
+};
// Right monitor times.
diff --git a/engines/pegasus/neighborhood/tsa/fulltsa.cpp b/engines/pegasus/neighborhood/tsa/fulltsa.cpp
index 92b79c038e..f7996fabf5 100644
--- a/engines/pegasus/neighborhood/tsa/fulltsa.cpp
+++ b/engines/pegasus/neighborhood/tsa/fulltsa.cpp
@@ -41,41 +41,45 @@ namespace Pegasus {
// TSA PICTs:
-static const ResIDType kTBPCloseBoxPICTID = 800;
-static const ResIDType kTBPRewindPICTID = 801;
-static const ResIDType kUnresolvedPICTID = 802;
-static const ResIDType kResolvedPICTID = 803;
-static const ResIDType kJumpMenuPICTID = 804;
-static const ResIDType kJumpMenuHilitedPICTID = 805;
-static const ResIDType kExitPICTID = 806;
-static const ResIDType kExitHilitedPICTID = 807;
-static const ResIDType kLeftRipPICTID = 808;
-static const ResIDType kComparisonCloseBoxPICTID = 809;
-static const ResIDType kComparisonLeftRewindPICTID = 810;
-static const ResIDType kComparisonRightRewindPICTID = 811;
-static const ResIDType kComparisonHiliteNoradPICTID = 812;
-static const ResIDType kComparisonHiliteMarsPICTID = 813;
-static const ResIDType kComparisonHiliteCaldoriaPICTID = 814;
-static const ResIDType kComparisonHiliteWSCPICTID = 815;
-static const ResIDType kComparisonChancesNoradPICTID = 816;
-static const ResIDType kComparisonChancesMarsPICTID = 817;
-static const ResIDType kComparisonChancesCaldoriaPICTID = 818;
-static const ResIDType kComparisonChancesWSCPICTID = 819;
-static const ResIDType kRedirectionCCRolloverPICTID = 820;
-static const ResIDType kRedirectionRRRolloverPICTID = 821;
-static const ResIDType kRedirectionFDRolloverPICTID = 822;
-static const ResIDType kRedirectionCCDoorPICTID = 823;
-static const ResIDType kRedirectionRRDoorPICTID = 824;
-static const ResIDType kRedirectionFDDoorPICTID = 825;
-static const ResIDType kRedirectionSecuredPICTID = 826;
-static const ResIDType kRedirectionNewTargetPICTID = 827;
-static const ResIDType kRedirectionClosePICTID = 828;
+enum {
+ kTBPCloseBoxPICTID = 800,
+ kTBPRewindPICTID = 801,
+ kUnresolvedPICTID = 802,
+ kResolvedPICTID = 803,
+ kJumpMenuPICTID = 804,
+ kJumpMenuHilitedPICTID = 805,
+ kExitPICTID = 806,
+ kExitHilitedPICTID = 807,
+ kLeftRipPICTID = 808,
+ kComparisonCloseBoxPICTID = 809,
+ kComparisonLeftRewindPICTID = 810,
+ kComparisonRightRewindPICTID = 811,
+ kComparisonHiliteNoradPICTID = 812,
+ kComparisonHiliteMarsPICTID = 813,
+ kComparisonHiliteCaldoriaPICTID = 814,
+ kComparisonHiliteWSCPICTID = 815,
+ kComparisonChancesNoradPICTID = 816,
+ kComparisonChancesMarsPICTID = 817,
+ kComparisonChancesCaldoriaPICTID = 818,
+ kComparisonChancesWSCPICTID = 819,
+ kRedirectionCCRolloverPICTID = 820,
+ kRedirectionRRRolloverPICTID = 821,
+ kRedirectionFDRolloverPICTID = 822,
+ kRedirectionCCDoorPICTID = 823,
+ kRedirectionRRDoorPICTID = 824,
+ kRedirectionFDDoorPICTID = 825,
+ kRedirectionSecuredPICTID = 826,
+ kRedirectionNewTargetPICTID = 827,
+ kRedirectionClosePICTID = 828
+};
static const int16 kCompassShift = 15;
-static const TimeScale kFullTSAMovieScale = 600;
-static const TimeScale kFullTSAFramesPerSecond = 15;
-static const TimeScale kFullTSAFrameDuration = 40;
+enum {
+ kFullTSAMovieScale = 600,
+ kFullTSAFramesPerSecond = 15,
+ kFullTSAFrameDuration = 40
+};
// Alternate IDs.
static const AlternateID kAltTSANormal = 0;
@@ -84,416 +88,425 @@ static const AlternateID kAltTSARobotsAtFrontDoor = 2;
static const AlternateID kAltTSARedAlert = 3;
// Room IDs.
-static const RoomID kTSA01 = 1;
-static const RoomID kTSA02 = 2;
-static const RoomID kTSA03 = 3;
-static const RoomID kTSA04 = 4;
-static const RoomID kTSA05 = 5;
-static const RoomID kTSA0A = 6;
-static const RoomID kTSA06 = 7;
-static const RoomID kTSA07 = 8;
-static const RoomID kTSA08 = 9;
-static const RoomID kTSA09 = 10;
-static const RoomID kTSA10 = 11;
-static const RoomID kTSA11 = 12;
-static const RoomID kTSA12 = 13;
-static const RoomID kTSA13 = 14;
-static const RoomID kTSA14 = 15;
-static const RoomID kTSA15 = 16;
-static const RoomID kTSA16 = 17;
-static const RoomID kTSA17 = 18;
-static const RoomID kTSA18 = 19;
-static const RoomID kTSA19 = 20;
-static const RoomID kTSA0B = 21;
-static const RoomID kTSA21Cyan = 22;
-static const RoomID kTSA22Cyan = 23;
-static const RoomID kTSA23Cyan = 24;
-static const RoomID kTSA24Cyan = 25;
-static const RoomID kTSA25Cyan = 26;
-static const RoomID kTSA21Red = 27;
-static const RoomID kTSA23Red = 29;
-static const RoomID kTSA24Red = 30;
-static const RoomID kTSA25Red = 31;
-static const RoomID kTSA26 = 32;
-static const RoomID kTSA27 = 33;
-static const RoomID kTSA28 = 34;
-static const RoomID kTSA29 = 35;
-static const RoomID kTSA30 = 36;
-static const RoomID kTSA31 = 37;
-static const RoomID kTSA32 = 38;
-static const RoomID kTSA33 = 39;
-static const RoomID kTSA34 = 40;
-static const RoomID kTSA35 = 41;
-static const RoomID kTSADeathRoom = 43;
+enum {
+ kTSA01 = 1,
+ kTSA02 = 2,
+ kTSA03 = 3,
+ kTSA04 = 4,
+ kTSA05 = 5,
+ kTSA0A = 6,
+ kTSA06 = 7,
+ kTSA07 = 8,
+ kTSA08 = 9,
+ kTSA09 = 10,
+ kTSA10 = 11,
+ kTSA11 = 12,
+ kTSA12 = 13,
+ kTSA13 = 14,
+ kTSA14 = 15,
+ kTSA15 = 16,
+ kTSA16 = 17,
+ kTSA17 = 18,
+ kTSA18 = 19,
+ kTSA19 = 20,
+ kTSA0B = 21,
+ kTSA21Cyan = 22,
+ kTSA22Cyan = 23,
+ kTSA23Cyan = 24,
+ kTSA24Cyan = 25,
+ kTSA25Cyan = 26,
+ kTSA21Red = 27,
+ kTSA23Red = 29,
+ kTSA24Red = 30,
+ kTSA25Red = 31,
+ kTSA26 = 32,
+ kTSA27 = 33,
+ kTSA28 = 34,
+ kTSA29 = 35,
+ kTSA30 = 36,
+ kTSA31 = 37,
+ kTSA32 = 38,
+ kTSA33 = 39,
+ kTSA34 = 40,
+ kTSA35 = 41,
+ kTSADeathRoom = 43
+};
// Hot Spot Activation IDs.
-static const HotSpotActivationID kActivateTSAReadyForCard = 1;
-static const HotSpotActivationID kActivateTSAReadyToTransport = 2;
-static const HotSpotActivationID kActivateTSARobotsAwake = 3;
-static const HotSpotActivationID kActivateTSA0BZoomedOut = 4;
-static const HotSpotActivationID kActivateTSA0BZoomedIn = 5;
-static const HotSpotActivationID kActivateTSA0BComparisonVideo = 6;
-static const HotSpotActivationID kActivationLogReaderOpen = 7;
-static const HotSpotActivationID kActivateTSA0BTBPVideo = 8;
-static const HotSpotActivationID kActivationDoesntHaveKey = 9;
-static const HotSpotActivationID kActivationKeyVaultOpen = 10;
-static const HotSpotActivationID kActivationDoesntHaveChips = 11;
-static const HotSpotActivationID kActivationChipVaultOpen = 12;
-static const HotSpotActivationID kActivationJumpToPrehistoric = 13;
-static const HotSpotActivationID kActivationJumpToNorad = 14;
-static const HotSpotActivationID kActivationJumpToMars = 15;
-static const HotSpotActivationID kActivationJumpToWSC = 16;
-static const HotSpotActivationID kActivationReadyToExit = 17;
-static const HotSpotActivationID kActivationReadyForJumpMenu = 18;
-static const HotSpotActivationID kActivationMainJumpMenu = 19;
+enum {
+ kActivateTSAReadyForCard = 1,
+ kActivateTSAReadyToTransport = 2,
+ kActivateTSARobotsAwake = 3,
+ kActivateTSA0BZoomedOut = 4,
+ kActivateTSA0BZoomedIn = 5,
+ kActivateTSA0BComparisonVideo = 6,
+ kActivationLogReaderOpen = 7,
+ kActivateTSA0BTBPVideo = 8,
+ kActivationDoesntHaveKey = 9,
+ kActivationKeyVaultOpen = 10,
+ kActivationDoesntHaveChips = 11,
+ kActivationChipVaultOpen = 12,
+ kActivationJumpToPrehistoric = 13,
+ kActivationJumpToNorad = 14,
+ kActivationJumpToMars = 15,
+ kActivationJumpToWSC = 16,
+ kActivationReadyToExit = 17,
+ kActivationReadyForJumpMenu = 18,
+ kActivationMainJumpMenu = 19
+};
// Hot Spot IDs.
-static const HotSpotID kTSAGTCardDropSpotID = 5000;
-static const HotSpotID kTSAGTTokyoSpotID = 5001;
-static const HotSpotID kTSAGTCaldoriaSpotID = 5002;
-static const HotSpotID kTSAGTBeachSpotID = 5003;
-static const HotSpotID kTSAGTOtherSpotID = 5004;
-static const HotSpotID kTSA02DoorSpotID = 5005;
-static const HotSpotID kTSA03EastJimenezSpotID = 5006;
-static const HotSpotID kTSA03WestCrenshawSpotID = 5007;
-static const HotSpotID kTSA04EastMatsumotoSpotID = 5008;
-static const HotSpotID kTSA04WestCastilleSpotID = 5009;
-static const HotSpotID kTSA05EastSinclairSpotID = 5010;
-static const HotSpotID kTSA05WestWhiteSpotID = 5011;
-static const HotSpotID kTSA0AEastSpotID = 5012;
-static const HotSpotID kTSA0AWastSpotID = 5013;
-static const HotSpotID kTSA0BEastMonitorSpotID = 5014;
-static const HotSpotID kTSA0BEastMonitorOutSpotID = 5015;
-static const HotSpotID kTSA0BEastCompareNoradSpotID = 5016;
-static const HotSpotID kTSA0BEastCompareMarsSpotID = 5017;
-static const HotSpotID kTSA0BEastCompareCaldoriaSpotID = 5018;
-static const HotSpotID kTSA0BEastCompareWSCSpotID = 5019;
-static const HotSpotID kTSA0BEastLeftRewindSpotID = 5020;
-static const HotSpotID kTSA0BEastLeftPlaySpotID = 5021;
-static const HotSpotID kTSA0BEastRightRewindSpotID = 5022;
-static const HotSpotID kTSA0BEastRightPlaySpotID = 5023;
-static const HotSpotID kTSA0BEastCloseVideoSpotID = 5024;
-static const HotSpotID kTSA0BNorthMonitorSpotID = 5025;
-static const HotSpotID kTSA0BNorthMonitorOutSpotID = 5026;
-static const HotSpotID kTSA0BNorthHistLogSpotID = 5027;
-static const HotSpotID kTSA0BNorthRobotsToCommandCenterSpotID = 5028;
-static const HotSpotID kTSA0BNorthRobotsToReadyRoomSpotID = 5029;
-static const HotSpotID kTSA0BNorthRobotsToFrontDoorSpotID = 5030;
-static const HotSpotID kTSA0BWestMonitorSpotID = 5031;
-static const HotSpotID kTSA0BWestMonitorOutSpotID = 5032;
-static const HotSpotID kTSA0BWestTheorySpotID = 5033;
-static const HotSpotID kTSA0BWestBackgroundSpotID = 5034;
-static const HotSpotID kTSA0BWestProcedureSpotID = 5035;
-static const HotSpotID kTSA0BWestCloseVideoSpotID = 5036;
-static const HotSpotID kTSA0BWestPlayVideoSpotID = 5037;
-static const HotSpotID kTSA0BWestRewindVideoSpotID = 5038;
-static const HotSpotID kTSA22EastMonitorSpotID = 5039;
-static const HotSpotID kTSA22EastKeySpotID = 5040;
-static const HotSpotID kTSA23WestMonitorSpotID = 5041;
-static const HotSpotID kTSA23WestChipsSpotID = 5042;
-static const HotSpotID kTSA34NorthDoorSpotID = 5043;
-static const HotSpotID kTSA37NorthJumpToPrehistoricSpotID = 5044;
-static const HotSpotID kTSA37NorthJumpToNoradSpotID = 5045;
-static const HotSpotID kTSA37NorthCancelNoradSpotID = 5046;
-static const HotSpotID kTSA37NorthJumpToMarsSpotID = 5047;
-static const HotSpotID kTSA37NorthCancelMarsSpotID = 5048;
-static const HotSpotID kTSA37NorthJumpToWSCSpotID = 5049;
-static const HotSpotID kTSA37NorthCancelWSCSpotID = 5050;
-static const HotSpotID kTSA37NorthExitSpotID = 5051;
-static const HotSpotID kTSA37NorthJumpMenuSpotID = 5052;
-static const HotSpotID kTSA37NorthNoradMenuSpotID = 5053;
-static const HotSpotID kTSA37NorthMarsMenuSpotID = 5054;
-static const HotSpotID kTSA37NorthWSCMenuSpotID = 5055;
+enum {
+ kTSAGTCardDropSpotID = 5000,
+ kTSAGTTokyoSpotID = 5001,
+ kTSAGTCaldoriaSpotID = 5002,
+ kTSAGTBeachSpotID = 5003,
+ kTSAGTOtherSpotID = 5004,
+ kTSA02DoorSpotID = 5005,
+ kTSA03EastJimenezSpotID = 5006,
+ kTSA03WestCrenshawSpotID = 5007,
+ kTSA04EastMatsumotoSpotID = 5008,
+ kTSA04WestCastilleSpotID = 5009,
+ kTSA05EastSinclairSpotID = 5010,
+ kTSA05WestWhiteSpotID = 5011,
+ kTSA0AEastSpotID = 5012,
+ kTSA0AWastSpotID = 5013,
+ kTSA0BEastMonitorSpotID = 5014,
+ kTSA0BEastMonitorOutSpotID = 5015,
+ kTSA0BEastCompareNoradSpotID = 5016,
+ kTSA0BEastCompareMarsSpotID = 5017,
+ kTSA0BEastCompareCaldoriaSpotID = 5018,
+ kTSA0BEastCompareWSCSpotID = 5019,
+ kTSA0BEastLeftRewindSpotID = 5020,
+ kTSA0BEastLeftPlaySpotID = 5021,
+ kTSA0BEastRightRewindSpotID = 5022,
+ kTSA0BEastRightPlaySpotID = 5023,
+ kTSA0BEastCloseVideoSpotID = 5024,
+ kTSA0BNorthMonitorSpotID = 5025,
+ kTSA0BNorthMonitorOutSpotID = 5026,
+ kTSA0BNorthHistLogSpotID = 5027,
+ kTSA0BNorthRobotsToCommandCenterSpotID = 5028,
+ kTSA0BNorthRobotsToReadyRoomSpotID = 5029,
+ kTSA0BNorthRobotsToFrontDoorSpotID = 5030,
+ kTSA0BWestMonitorSpotID = 5031,
+ kTSA0BWestMonitorOutSpotID = 5032,
+ kTSA0BWestTheorySpotID = 5033,
+ kTSA0BWestBackgroundSpotID = 5034,
+ kTSA0BWestProcedureSpotID = 5035,
+ kTSA0BWestCloseVideoSpotID = 5036,
+ kTSA0BWestPlayVideoSpotID = 5037,
+ kTSA0BWestRewindVideoSpotID = 5038,
+ kTSA22EastMonitorSpotID = 5039,
+ kTSA22EastKeySpotID = 5040,
+ kTSA23WestMonitorSpotID = 5041,
+ kTSA23WestChipsSpotID = 5042,
+ kTSA34NorthDoorSpotID = 5043,
+ kTSA37NorthJumpToPrehistoricSpotID = 5044,
+ kTSA37NorthJumpToNoradSpotID = 5045,
+ kTSA37NorthCancelNoradSpotID = 5046,
+ kTSA37NorthJumpToMarsSpotID = 5047,
+ kTSA37NorthCancelMarsSpotID = 5048,
+ kTSA37NorthJumpToWSCSpotID = 5049,
+ kTSA37NorthCancelWSCSpotID = 5050,
+ kTSA37NorthExitSpotID = 5051,
+ kTSA37NorthJumpMenuSpotID = 5052,
+ kTSA37NorthNoradMenuSpotID = 5053,
+ kTSA37NorthMarsMenuSpotID = 5054,
+ kTSA37NorthWSCMenuSpotID = 5055
+};
// Extra sequence IDs.
-static const ExtraID kTSATransporterArrowLoop = 0;
-static const ExtraID kTSAArriveFromCaldoria = 1;
-static const ExtraID kTSAGTOtherChoice = 2;
-static const ExtraID kTSAGTCardSwipe = 3;
-static const ExtraID kTSAGTSelectCaldoria = 4;
-static const ExtraID kTSAGTGoToCaldoria = 5;
-static const ExtraID kTSAGTSelectBeach = 6;
-static const ExtraID kTSAGTGoToBeach = 7;
-static const ExtraID kTSAGTArriveAtBeach = 8;
-static const ExtraID kTSAGTSelectTokyo = 9;
-static const ExtraID kTSAGTGoToTokyo = 10;
-static const ExtraID kTSAGTArriveAtTokyo = 11;
-static const ExtraID kTSA02NorthZoomIn = 12;
-static const ExtraID kTSA02NorthTenSecondDoor = 13;
-static const ExtraID kTSA02NorthZoomOut = 14;
-static const ExtraID kTSA02NorthDoorWithAgent3 = 15;
-static const ExtraID kTSA03JimenezZoomIn = 16;
-static const ExtraID kTSA03JimenezSpeech = 17;
-static const ExtraID kTSA03JimenezZoomOut = 18;
-static const ExtraID kTSA03CrenshawZoomIn = 19;
-static const ExtraID kTSA03CrenshawSpeech = 20;
-static const ExtraID kTSA03CrenshawZoomOut = 21;
-static const ExtraID kTSA03SouthRobotDeath = 22;
-static const ExtraID kTSA04NorthRobotGreeting = 23;
-static const ExtraID kTSA04MatsumotoZoomIn = 24;
-static const ExtraID kTSA04MatsumotoSpeech = 25;
-static const ExtraID kTSA04MatsumotoZoomOut = 26;
-static const ExtraID kTSA04CastilleZoomIn = 27;
-static const ExtraID kTSA04CastilleSpeech = 28;
-static const ExtraID kTSA04CastilleZoomOut = 29;
-static const ExtraID kTSA05SinclairZoomIn = 30;
-static const ExtraID kTSA05SinclairSpeech = 31;
-static const ExtraID kTSA05SinclairZoomOut = 32;
-static const ExtraID kTSA05WhiteZoomIn = 33;
-static const ExtraID kTSA05WhiteSpeech = 34;
-static const ExtraID kTSA05WhiteZoomOut = 35;
-static const ExtraID kTSA0AEastRobot = 36;
-static const ExtraID kTSA0AWestRobot = 37;
-static const ExtraID kTSA16NorthRobotDeath = 38;
-static const ExtraID kTSA0BEastZoomIn = 39;
-static const ExtraID kTSA0BEastZoomedView = 40;
-static const ExtraID kTSA0BEastZoomOut = 41;
-static const ExtraID kTSA0BEastTurnLeft = 42;
-static const ExtraID kTSA0BComparisonStartup = 43;
-static const ExtraID kTSA0BComparisonView0000 = 44;
-static const ExtraID kTSA0BComparisonView0002 = 45;
-static const ExtraID kTSA0BComparisonView0020 = 46;
-static const ExtraID kTSA0BComparisonView0022 = 47;
-static const ExtraID kTSA0BComparisonView0200 = 48;
-static const ExtraID kTSA0BComparisonView0202 = 49;
-static const ExtraID kTSA0BComparisonView0220 = 50;
-static const ExtraID kTSA0BComparisonView0222 = 51;
-static const ExtraID kTSA0BComparisonView2000 = 52;
-static const ExtraID kTSA0BComparisonView2002 = 53;
-static const ExtraID kTSA0BComparisonView2020 = 54;
-static const ExtraID kTSA0BComparisonView2022 = 55;
-static const ExtraID kTSA0BComparisonView2200 = 56;
-static const ExtraID kTSA0BComparisonView2202 = 57;
-static const ExtraID kTSA0BComparisonView2220 = 58;
-static const ExtraID kTSA0BComparisonView2222 = 59;
-static const ExtraID kTSA0BNoradComparisonView = 60;
-static const ExtraID kTSA0BNoradUnaltered = 61;
-static const ExtraID kTSA0BNoradAltered = 62;
-static const ExtraID kTSA0BMarsComparisonView = 63;
-static const ExtraID kTSA0BMarsUnaltered = 64;
-static const ExtraID kTSA0BMarsAltered = 65;
-static const ExtraID kTSA0BWSCComparisonView = 66;
-static const ExtraID kTSA0BWSCUnaltered = 67;
-static const ExtraID kTSA0BWSCAltered = 68;
-static const ExtraID kTSA0BCaldoriaComparisonView = 69;
-static const ExtraID kTSA0BCaldoriaUnaltered = 70;
-static const ExtraID kTSA0BCaldoriaAltered = 71;
-static const ExtraID kTSA0BNorthZoomIn = 72;
-static const ExtraID kTSA0BNorthZoomedView = 73;
-static const ExtraID kTSA0BNorthZoomOut = 74;
-static const ExtraID kTSA0BNorthTurnLeft = 75;
-static const ExtraID kTSA0BNorthTurnRight = 76;
-static const ExtraID kTSA0BNorthHistLogOpen = 77;
-static const ExtraID kTSA0BNorthHistLogClose = 78;
-static const ExtraID kTSA0BNorthHistLogCloseWithLog = 79;
-static const ExtraID kTSA0BNorthCantChangeHistory = 80;
-static const ExtraID kTSA0BNorthYoureBusted = 81;
-static const ExtraID kTSA0BNorthFinallyHappened = 82;
-static const ExtraID kTSA0BShowRip1 = 83;
-static const ExtraID kTSA0BNorthRipView1 = 84;
-static const ExtraID kTSA0BShowRip2 = 85;
-static const ExtraID kTSA0BShowGuardRobots = 86;
-static const ExtraID kTSA0BAIInterruption = 87;
-static const ExtraID kTSA0BRobotsToCommandCenter = 88;
-static const ExtraID kTSA0BNorthRobotsAtCCView = 89;
-static const ExtraID kTSA0BNorthRobotsAtRRView = 90;
-static const ExtraID kTSA0BNorthRobotsAtFDView = 91;
-static const ExtraID kTSA0BRobotsFromCommandCenterToReadyRoom = 92;
-static const ExtraID kTSA0BRobotsFromReadyRoomToCommandCenter = 93;
-static const ExtraID kTSA0BRobotsFromCommandCenterToFrontDoor = 94;
-static const ExtraID kTSA0BRobotsFromFrontDoorToCommandCenter = 95;
-static const ExtraID kTSA0BRobotsFromFrontDoorToReadyRoom = 96;
-static const ExtraID kTSA0BRobotsFromReadyRoomToFrontDoor = 97;
-static const ExtraID kTSA0BWestZoomIn = 98;
-static const ExtraID kTSA0BWestZoomedView = 99;
-static const ExtraID kTSA0BWestZoomOut = 100;
-static const ExtraID kTSA0BWestTurnRight = 101;
-static const ExtraID kTSA0BTBPTheoryHighlight = 102;
-static const ExtraID kTSA0BTBPBackgroundHighlight = 103;
-static const ExtraID kTSA0BTBPProcedureHighlight = 104;
-static const ExtraID kTSA0BTBPTheory = 105;
-static const ExtraID kTSA0BTBPBackground = 106;
-static const ExtraID kTSA0BTBPProcedure = 107;
-static const ExtraID kTSA0BRipAlarmScreen = 108;
-static const ExtraID kTSA22RedEastZoomInSequence = 109;
-static const ExtraID kTSA22RedEastVaultViewWithKey = 110;
-static const ExtraID kTSA22RedEastVaultViewNoKey = 111;
-static const ExtraID kTSA23RedWestVaultZoomInSequence = 112;
-static const ExtraID kTSA23RedWestVaultViewWithChips = 113;
-static const ExtraID kTSA23RedWestVaultViewNoChips = 114;
-static const ExtraID kTSA25NorthDeniedNoKey = 115;
-static const ExtraID kTSA25NorthDeniedNoChip = 116;
-static const ExtraID kTSA25NorthPutOnSuit = 117;
-static const ExtraID kTSA25NorthAlreadyHaveSuit = 118;
-static const ExtraID kTSA25NorthDescending1 = 119;
-static const ExtraID kTSA25NorthDescending2 = 120;
-static const ExtraID kTSA37HorseToAI1 = 121;
-static const ExtraID kTSA37PegasusAI1 = 122;
-static const ExtraID kTSA37AI1ToCommissioner1 = 123;
-static const ExtraID kTSA37Commissioner1 = 124;
-static const ExtraID kTSA37Commissioner1ToZoom = 125;
-static const ExtraID kTSA37ZoomToPrehistoric = 126;
-static const ExtraID kTSA37PrehistoricToAI2 = 127;
-static const ExtraID kTSA37PegasusAI2 = 128;
-static const ExtraID kTSA37AI2ToPrehistoric = 129;
-static const ExtraID kTSA37PrehistoricToDepart = 130;
-static const ExtraID kTSA37PegasusDepart = 131;
-static const ExtraID kTSA37TimeJumpToPegasus = 132;
-static const ExtraID kTSA37RecallToDownload = 133;
-static const ExtraID kTSA37DownloadToColonel1 = 134;
-static const ExtraID kTSA37Colonel1 = 135;
-static const ExtraID kTSA37Colonel1ToReviewRequired = 136;
-static const ExtraID kTSA37ReviewRequiredToExit = 137;
-static const ExtraID kTSA37ExitHilited = 138;
-static const ExtraID kTSA37ExitToHorse = 139;
-static const ExtraID kTSA37HorseToColonel2 = 140;
-static const ExtraID kTSA37Colonel2 = 141;
-static const ExtraID kTSA37PegasusAI3 = 142;
-static const ExtraID kTSA37AI3ToHorse = 143;
-static const ExtraID kTSA37HorseToZoom = 144;
-static const ExtraID kTSA37ZoomToMainMenu = 145;
-static const ExtraID kTSA37MainMenuToAI4 = 146;
-static const ExtraID kTSA37PegasusAI4 = 147;
-static const ExtraID kTSA37AI4ToMainMenu = 148;
-static const ExtraID kTSA37JumpMenu000 = 149;
-static const ExtraID kTSA37JumpMenu001 = 150;
-static const ExtraID kTSA37JumpMenu010 = 151;
-static const ExtraID kTSA37JumpMenu011 = 152;
-static const ExtraID kTSA37JumpMenu100 = 153;
-static const ExtraID kTSA37JumpMenu101 = 154;
-static const ExtraID kTSA37JumpMenu110 = 155;
-static const ExtraID kTSA37JumpMenu111 = 156;
-static const ExtraID kTSA37JumpToWSCMenu = 157;
-static const ExtraID kTSA37CancelWSC = 158;
-static const ExtraID kTSA37JumpToWSC = 159;
-static const ExtraID kTSA37WSCToAI5 = 160;
-static const ExtraID kTSA37PegasusAI5 = 161;
-static const ExtraID kTSA37AI5ToWSC = 162;
-static const ExtraID kTSA37WSCToDepart = 163;
-static const ExtraID kTSA37JumpToMarsMenu = 164;
-static const ExtraID kTSA37CancelMars = 165;
-static const ExtraID kTSA37JumpToMars = 166;
-static const ExtraID kTSA37MarsToAI6 = 167;
-static const ExtraID kTSA37PegasusAI6 = 168;
-static const ExtraID kTSA37AI6ToMars = 169;
-static const ExtraID kTSA37MarsToDepart = 170;
-static const ExtraID kTSA37JumpToNoradMenu = 171;
-static const ExtraID kTSA37CancelNorad = 172;
-static const ExtraID kTSA37JumpToNorad = 173;
-static const ExtraID kTSA37NoradToAI7 = 174;
-static const ExtraID kTSA37PegasusAI7 = 175;
-static const ExtraID kTSA37AI7ToNorad = 176;
-static const ExtraID kTSA37NoradToDepart = 177;
-static const ExtraID kTSA37EnvironmentalScan = 178;
-static const ExtraID kTSA37DownloadToMainMenu = 179;
-static const ExtraID kTSA37DownloadToOpMemReview = 180;
-static const ExtraID kTSA37OpMemReviewToMainMenu = 181;
-static const ExtraID kTSA37OpMemReviewToAllClear = 182;
-static const ExtraID kTSA37AllClearToCongratulations = 183;
-static const ExtraID kTSA37Congratulations = 184;
-static const ExtraID kTSA37CongratulationsToExit = 185;
+enum {
+ kTSATransporterArrowLoop = 0,
+ kTSAArriveFromCaldoria = 1,
+ kTSAGTOtherChoice = 2,
+ kTSAGTCardSwipe = 3,
+ kTSAGTSelectCaldoria = 4,
+ kTSAGTGoToCaldoria = 5,
+ kTSAGTSelectBeach = 6,
+ kTSAGTGoToBeach = 7,
+ kTSAGTArriveAtBeach = 8,
+ kTSAGTSelectTokyo = 9,
+ kTSAGTGoToTokyo = 10,
+ kTSAGTArriveAtTokyo = 11,
+ kTSA02NorthZoomIn = 12,
+ kTSA02NorthTenSecondDoor = 13,
+ kTSA02NorthZoomOut = 14,
+ kTSA02NorthDoorWithAgent3 = 15,
+ kTSA03JimenezZoomIn = 16,
+ kTSA03JimenezSpeech = 17,
+ kTSA03JimenezZoomOut = 18,
+ kTSA03CrenshawZoomIn = 19,
+ kTSA03CrenshawSpeech = 20,
+ kTSA03CrenshawZoomOut = 21,
+ kTSA03SouthRobotDeath = 22,
+ kTSA04NorthRobotGreeting = 23,
+ kTSA04MatsumotoZoomIn = 24,
+ kTSA04MatsumotoSpeech = 25,
+ kTSA04MatsumotoZoomOut = 26,
+ kTSA04CastilleZoomIn = 27,
+ kTSA04CastilleSpeech = 28,
+ kTSA04CastilleZoomOut = 29,
+ kTSA05SinclairZoomIn = 30,
+ kTSA05SinclairSpeech = 31,
+ kTSA05SinclairZoomOut = 32,
+ kTSA05WhiteZoomIn = 33,
+ kTSA05WhiteSpeech = 34,
+ kTSA05WhiteZoomOut = 35,
+ kTSA0AEastRobot = 36,
+ kTSA0AWestRobot = 37,
+ kTSA16NorthRobotDeath = 38,
+ kTSA0BEastZoomIn = 39,
+ kTSA0BEastZoomedView = 40,
+ kTSA0BEastZoomOut = 41,
+ kTSA0BEastTurnLeft = 42,
+ kTSA0BComparisonStartup = 43,
+ kTSA0BComparisonView0000 = 44,
+ kTSA0BComparisonView0002 = 45,
+ kTSA0BComparisonView0020 = 46,
+ kTSA0BComparisonView0022 = 47,
+ kTSA0BComparisonView0200 = 48,
+ kTSA0BComparisonView0202 = 49,
+ kTSA0BComparisonView0220 = 50,
+ kTSA0BComparisonView0222 = 51,
+ kTSA0BComparisonView2000 = 52,
+ kTSA0BComparisonView2002 = 53,
+ kTSA0BComparisonView2020 = 54,
+ kTSA0BComparisonView2022 = 55,
+ kTSA0BComparisonView2200 = 56,
+ kTSA0BComparisonView2202 = 57,
+ kTSA0BComparisonView2220 = 58,
+ kTSA0BComparisonView2222 = 59,
+ kTSA0BNoradComparisonView = 60,
+ kTSA0BNoradUnaltered = 61,
+ kTSA0BNoradAltered = 62,
+ kTSA0BMarsComparisonView = 63,
+ kTSA0BMarsUnaltered = 64,
+ kTSA0BMarsAltered = 65,
+ kTSA0BWSCComparisonView = 66,
+ kTSA0BWSCUnaltered = 67,
+ kTSA0BWSCAltered = 68,
+ kTSA0BCaldoriaComparisonView = 69,
+ kTSA0BCaldoriaUnaltered = 70,
+ kTSA0BCaldoriaAltered = 71,
+ kTSA0BNorthZoomIn = 72,
+ kTSA0BNorthZoomedView = 73,
+ kTSA0BNorthZoomOut = 74,
+ kTSA0BNorthTurnLeft = 75,
+ kTSA0BNorthTurnRight = 76,
+ kTSA0BNorthHistLogOpen = 77,
+ kTSA0BNorthHistLogClose = 78,
+ kTSA0BNorthHistLogCloseWithLog = 79,
+ kTSA0BNorthCantChangeHistory = 80,
+ kTSA0BNorthYoureBusted = 81,
+ kTSA0BNorthFinallyHappened = 82,
+ kTSA0BShowRip1 = 83,
+ kTSA0BNorthRipView1 = 84,
+ kTSA0BShowRip2 = 85,
+ kTSA0BShowGuardRobots = 86,
+ kTSA0BAIInterruption = 87,
+ kTSA0BRobotsToCommandCenter = 88,
+ kTSA0BNorthRobotsAtCCView = 89,
+ kTSA0BNorthRobotsAtRRView = 90,
+ kTSA0BNorthRobotsAtFDView = 91,
+ kTSA0BRobotsFromCommandCenterToReadyRoom = 92,
+ kTSA0BRobotsFromReadyRoomToCommandCenter = 93,
+ kTSA0BRobotsFromCommandCenterToFrontDoor = 94,
+ kTSA0BRobotsFromFrontDoorToCommandCenter = 95,
+ kTSA0BRobotsFromFrontDoorToReadyRoom = 96,
+ kTSA0BRobotsFromReadyRoomToFrontDoor = 97,
+ kTSA0BWestZoomIn = 98,
+ kTSA0BWestZoomedView = 99,
+ kTSA0BWestZoomOut = 100,
+ kTSA0BWestTurnRight = 101,
+ kTSA0BTBPTheoryHighlight = 102,
+ kTSA0BTBPBackgroundHighlight = 103,
+ kTSA0BTBPProcedureHighlight = 104,
+ kTSA0BTBPTheory = 105,
+ kTSA0BTBPBackground = 106,
+ kTSA0BTBPProcedure = 107,
+ kTSA0BRipAlarmScreen = 108,
+ kTSA22RedEastZoomInSequence = 109,
+ kTSA22RedEastVaultViewWithKey = 110,
+ kTSA22RedEastVaultViewNoKey = 111,
+ kTSA23RedWestVaultZoomInSequence = 112,
+ kTSA23RedWestVaultViewWithChips = 113,
+ kTSA23RedWestVaultViewNoChips = 114,
+ kTSA25NorthDeniedNoKey = 115,
+ kTSA25NorthDeniedNoChip = 116,
+ kTSA25NorthPutOnSuit = 117,
+ kTSA25NorthAlreadyHaveSuit = 118,
+ kTSA25NorthDescending1 = 119,
+ kTSA25NorthDescending2 = 120,
+ kTSA37HorseToAI1 = 121,
+ kTSA37PegasusAI1 = 122,
+ kTSA37AI1ToCommissioner1 = 123,
+ kTSA37Commissioner1 = 124,
+ kTSA37Commissioner1ToZoom = 125,
+ kTSA37ZoomToPrehistoric = 126,
+ kTSA37PrehistoricToAI2 = 127,
+ kTSA37PegasusAI2 = 128,
+ kTSA37AI2ToPrehistoric = 129,
+ kTSA37PrehistoricToDepart = 130,
+ kTSA37PegasusDepart = 131,
+ kTSA37TimeJumpToPegasus = 132,
+ kTSA37RecallToDownload = 133,
+ kTSA37DownloadToColonel1 = 134,
+ kTSA37Colonel1 = 135,
+ kTSA37Colonel1ToReviewRequired = 136,
+ kTSA37ReviewRequiredToExit = 137,
+ kTSA37ExitHilited = 138,
+ kTSA37ExitToHorse = 139,
+ kTSA37HorseToColonel2 = 140,
+ kTSA37Colonel2 = 141,
+ kTSA37PegasusAI3 = 142,
+ kTSA37AI3ToHorse = 143,
+ kTSA37HorseToZoom = 144,
+ kTSA37ZoomToMainMenu = 145,
+ kTSA37MainMenuToAI4 = 146,
+ kTSA37PegasusAI4 = 147,
+ kTSA37AI4ToMainMenu = 148,
+ kTSA37JumpMenu000 = 149,
+ kTSA37JumpMenu001 = 150,
+ kTSA37JumpMenu010 = 151,
+ kTSA37JumpMenu011 = 152,
+ kTSA37JumpMenu100 = 153,
+ kTSA37JumpMenu101 = 154,
+ kTSA37JumpMenu110 = 155,
+ kTSA37JumpMenu111 = 156,
+ kTSA37JumpToWSCMenu = 157,
+ kTSA37CancelWSC = 158,
+ kTSA37JumpToWSC = 159,
+ kTSA37WSCToAI5 = 160,
+ kTSA37PegasusAI5 = 161,
+ kTSA37AI5ToWSC = 162,
+ kTSA37WSCToDepart = 163,
+ kTSA37JumpToMarsMenu = 164,
+ kTSA37CancelMars = 165,
+ kTSA37JumpToMars = 166,
+ kTSA37MarsToAI6 = 167,
+ kTSA37PegasusAI6 = 168,
+ kTSA37AI6ToMars = 169,
+ kTSA37MarsToDepart = 170,
+ kTSA37JumpToNoradMenu = 171,
+ kTSA37CancelNorad = 172,
+ kTSA37JumpToNorad = 173,
+ kTSA37NoradToAI7 = 174,
+ kTSA37PegasusAI7 = 175,
+ kTSA37AI7ToNorad = 176,
+ kTSA37NoradToDepart = 177,
+ kTSA37EnvironmentalScan = 178,
+ kTSA37DownloadToMainMenu = 179,
+ kTSA37DownloadToOpMemReview = 180,
+ kTSA37OpMemReviewToMainMenu = 181,
+ kTSA37OpMemReviewToAllClear = 182,
+ kTSA37AllClearToCongratulations = 183,
+ kTSA37Congratulations = 184,
+ kTSA37CongratulationsToExit = 185
+};
const DisplayOrder kRipTimerOrder = kMonitorLayer;
+enum {
+ kUnresolvedLeft = kNavAreaLeft + 14,
+ kUnresolvedTop = kNavAreaTop + 236,
-const CoordType kUnresolvedLeft = kNavAreaLeft + 14;
-const CoordType kUnresolvedTop = kNavAreaTop + 236;
-
-const CoordType kResolvedLeft = kNavAreaLeft + 36;
-const CoordType kResolvedTop = kNavAreaTop + 236;
+ kResolvedLeft = kNavAreaLeft + 36,
+ kResolvedTop = kNavAreaTop + 236,
-const CoordType kJumpMenuLeft = kNavAreaLeft + 360;
-const CoordType kJumpMenuTop = kNavAreaTop + 202;
+ kJumpMenuLeft = kNavAreaLeft + 360,
+ kJumpMenuTop = kNavAreaTop + 202,
-const CoordType kJumpMenuHilitedLeft = kNavAreaLeft + 354;
-const CoordType kJumpMenuHilitedTop = kNavAreaTop + 196;
+ kJumpMenuHilitedLeft = kNavAreaLeft + 354,
+ kJumpMenuHilitedTop = kNavAreaTop + 196,
-const CoordType kExitLeft = kNavAreaLeft + 360;
-const CoordType kExitTop = kNavAreaTop + 216;
+ kExitLeft = kNavAreaLeft + 360,
+ kExitTop = kNavAreaTop + 216,
-const CoordType kExitHilitedLeft = kNavAreaLeft + 354;
-const CoordType kExitHilitedTop = kNavAreaTop + 210;
+ kExitHilitedLeft = kNavAreaLeft + 354,
+ kExitHilitedTop = kNavAreaTop + 210,
-const CoordType kRipTimerLeft = kNavAreaLeft + 95;
-const CoordType kRipTimerTop = kNavAreaTop + 87;
+ kRipTimerLeft = kNavAreaLeft + 95,
+ kRipTimerTop = kNavAreaTop + 87,
-const CoordType kTBPCloseLeft = kNavAreaLeft + 30;
-const CoordType kTBPCloseTop = kNavAreaTop + 16;
+ kTBPCloseLeft = kNavAreaLeft + 30,
+ kTBPCloseTop = kNavAreaTop + 16,
-const CoordType kTBPRewindLeft = kNavAreaLeft + 86;
-const CoordType kTBPRewindTop = kNavAreaTop + 218;
+ kTBPRewindLeft = kNavAreaLeft + 86,
+ kTBPRewindTop = kNavAreaTop + 218,
-const CoordType kComparisonCloseLeft = kNavAreaLeft + 50;
-const CoordType kComparisonCloseTop = kNavAreaTop + 14;
+ kComparisonCloseLeft = kNavAreaLeft + 50,
+ kComparisonCloseTop = kNavAreaTop + 14,
-const CoordType kComparisonLeftRewindLeft = kNavAreaLeft + 96;
-const CoordType kComparisonLeftRewindTop = kNavAreaTop + 190;
+ kComparisonLeftRewindLeft = kNavAreaLeft + 96,
+ kComparisonLeftRewindTop = kNavAreaTop + 190,
-const CoordType kComparisonRightRewindLeft = kNavAreaLeft + 282;
-const CoordType kComparisonRightRewindTop = kNavAreaTop + 190;
+ kComparisonRightRewindLeft = kNavAreaLeft + 282,
+ kComparisonRightRewindTop = kNavAreaTop + 190,
-const CoordType kComparisonHiliteSpriteLeft = kNavAreaLeft + 45;
-const CoordType kComparisonHiliteSpriteTop = kNavAreaTop + 65;
+ kComparisonHiliteSpriteLeft = kNavAreaLeft + 45,
+ kComparisonHiliteSpriteTop = kNavAreaTop + 65,
-const CoordType kComparisonHiliteNoradLeft = kNavAreaLeft + 45;
-const CoordType kComparisonHiliteNoradTop = kNavAreaTop + 65;
+ kComparisonHiliteNoradLeft = kNavAreaLeft + 45,
+ kComparisonHiliteNoradTop = kNavAreaTop + 65,
-const CoordType kComparisonHiliteMarsLeft = kNavAreaLeft + 45 + 4;
-const CoordType kComparisonHiliteMarsTop = kNavAreaTop + 65 + 23;
+ kComparisonHiliteMarsLeft = kNavAreaLeft + 45 + 4,
+ kComparisonHiliteMarsTop = kNavAreaTop + 65 + 23,
-const CoordType kComparisonHiliteCaldoriaLeft = kNavAreaLeft + 45 + 7;
-const CoordType kComparisonHiliteCaldoriaTop = kNavAreaTop + 65 + 46;
+ kComparisonHiliteCaldoriaLeft = kNavAreaLeft + 45 + 7,
+ kComparisonHiliteCaldoriaTop = kNavAreaTop + 65 + 46,
-const CoordType kComparisonHiliteWSCLeft = kNavAreaLeft + 45 + 11;
-const CoordType kComparisonHiliteWSCTop = kNavAreaTop + 65 + 68;
+ kComparisonHiliteWSCLeft = kNavAreaLeft + 45 + 11,
+ kComparisonHiliteWSCTop = kNavAreaTop + 65 + 68,
-const CoordType kComparisonChancesSpriteLeft = kNavAreaLeft + 148;
-const CoordType kComparisonChancesSpriteTop = kNavAreaTop + 162;
+ kComparisonChancesSpriteLeft = kNavAreaLeft + 148,
+ kComparisonChancesSpriteTop = kNavAreaTop + 162,
-const CoordType kComparisonChancesNoradLeft = kNavAreaLeft + 148;
-const CoordType kComparisonChancesNoradTop = kNavAreaTop + 162;
+ kComparisonChancesNoradLeft = kNavAreaLeft + 148,
+ kComparisonChancesNoradTop = kNavAreaTop + 162,
-const CoordType kComparisonChancesMarsLeft = kNavAreaLeft + 148;
-const CoordType kComparisonChancesMarsTop = kNavAreaTop + 162;
+ kComparisonChancesMarsLeft = kNavAreaLeft + 148,
+ kComparisonChancesMarsTop = kNavAreaTop + 162,
-const CoordType kComparisonChancesCaldoriaLeft = kNavAreaLeft + 148;
-const CoordType kComparisonChancesCaldoriaTop = kNavAreaTop + 162 + 1;
+ kComparisonChancesCaldoriaLeft = kNavAreaLeft + 148,
+ kComparisonChancesCaldoriaTop = kNavAreaTop + 162 + 1,
-const CoordType kComparisonChancesWSCLeft = kNavAreaLeft + 148;
-const CoordType kComparisonChancesWSCTop = kNavAreaTop + 162;
+ kComparisonChancesWSCLeft = kNavAreaLeft + 148,
+ kComparisonChancesWSCTop = kNavAreaTop + 162,
-const CoordType kRedirectionSprite1Left = kNavAreaLeft + 58;
-const CoordType kRedirectionSprite1Top = kNavAreaTop + 16;
+ kRedirectionSprite1Left = kNavAreaLeft + 58,
+ kRedirectionSprite1Top = kNavAreaTop + 16,
-const CoordType kRedirectionSprite2Left = kNavAreaLeft + 36;
-const CoordType kRedirectionSprite2Top = kNavAreaTop + 166;
+ kRedirectionSprite2Left = kNavAreaLeft + 36,
+ kRedirectionSprite2Top = kNavAreaTop + 166,
-const CoordType kRedirectionCCRolloverLeft = kNavAreaLeft + 58;
-const CoordType kRedirectionCCRolloverTop = kNavAreaTop + 16;
+ kRedirectionCCRolloverLeft = kNavAreaLeft + 58,
+ kRedirectionCCRolloverTop = kNavAreaTop + 16,
-const CoordType kRedirectionRRRolloverLeft = kNavAreaLeft + 430;
-const CoordType kRedirectionRRRolloverTop = kNavAreaTop + 30;
+ kRedirectionRRRolloverLeft = kNavAreaLeft + 430,
+ kRedirectionRRRolloverTop = kNavAreaTop + 30,
-const CoordType kRedirectionFDRolloverLeft = kNavAreaLeft + 278;
-const CoordType kRedirectionFDRolloverTop = kNavAreaTop + 160;
+ kRedirectionFDRolloverLeft = kNavAreaLeft + 278,
+ kRedirectionFDRolloverTop = kNavAreaTop + 160,
-const CoordType kRedirectionCCDoorLeft = kNavAreaLeft + 174;
-const CoordType kRedirectionCCDoorTop = kNavAreaTop + 36;
+ kRedirectionCCDoorLeft = kNavAreaLeft + 174,
+ kRedirectionCCDoorTop = kNavAreaTop + 36,
-const CoordType kRedirectionRRDoorLeft = kNavAreaLeft + 418;
-const CoordType kRedirectionRRDoorTop = kNavAreaTop + 32;
+ kRedirectionRRDoorLeft = kNavAreaLeft + 418,
+ kRedirectionRRDoorTop = kNavAreaTop + 32,
-const CoordType kRedirectionFDDoorLeft = kNavAreaLeft + 298;
-const CoordType kRedirectionFDDoorTop = kNavAreaTop + 240;
+ kRedirectionFDDoorLeft = kNavAreaLeft + 298,
+ kRedirectionFDDoorTop = kNavAreaTop + 240,
-const CoordType kRedirectionSecuredLeft = kNavAreaLeft + 36;
-const CoordType kRedirectionSecuredTop = kNavAreaTop + 166;
+ kRedirectionSecuredLeft = kNavAreaLeft + 36,
+ kRedirectionSecuredTop = kNavAreaTop + 166,
-const CoordType kRedirectionNewTargetLeft = kNavAreaLeft + 36;
-const CoordType kRedirectionNewTargetTop = kNavAreaTop + 166;
+ kRedirectionNewTargetLeft = kNavAreaLeft + 36,
+ kRedirectionNewTargetTop = kNavAreaTop + 166,
-const CoordType kRedirectionCloseLeft = kNavAreaLeft + 56;
-const CoordType kRedirectionCloseTop = kNavAreaTop + 220;
+ kRedirectionCloseLeft = kNavAreaLeft + 56,
+ kRedirectionCloseTop = kNavAreaTop + 220
+};
static const TimeValue kTSABumpIntoWallIn = 0;
static const TimeValue kTSABumpIntoWallOut = 148;
@@ -516,10 +529,12 @@ static const TimeValue kTSAVaultCloseOut = 5388;
static const TimeValue kTSAPegasusDoorCloseIn = 5388;
static const TimeValue kTSAPegasusDoorCloseOut = 6457;
-static const bool kPegasusUnresolved = false;
-static const bool kPegasusResolved = true;
-static const bool kPegasusCantExit = false;
-static const bool kPegasusCanExit = true;
+enum {
+ kPegasusUnresolved = false,
+ kPegasusResolved = true,
+ kPegasusCantExit = false,
+ kPegasusCanExit = true
+};
// Monitor modes
enum {
@@ -582,15 +597,17 @@ static const ExtraID s_historicalLogViews[16] = {
kTSA0BComparisonView2222
};
-static const int kRedirectionCCRolloverSprite = 0;
-static const int kRedirectionRRRolloverSprite = 1;
-static const int kRedirectionFDRolloverSprite = 2;
-static const int kRedirectionCCDoorSprite = 3;
-static const int kRedirectionRRDoorSprite = 4;
-static const int kRedirectionFDDoorSprite = 5;
-static const int kRedirectionCloseSprite = 6;
-static const int kRedirectionSecuredSprite = 0;
-static const int kRedirectionNewTargetSprite = 1;
+enum {
+ kRedirectionCCRolloverSprite = 0,
+ kRedirectionRRRolloverSprite = 1,
+ kRedirectionFDRolloverSprite = 2,
+ kRedirectionCCDoorSprite = 3,
+ kRedirectionRRDoorSprite = 4,
+ kRedirectionFDDoorSprite = 5,
+ kRedirectionCloseSprite = 6,
+ kRedirectionSecuredSprite = 0,
+ kRedirectionNewTargetSprite = 1
+};
void RipTimer::initImage() {
_middle = -1;
diff --git a/engines/pegasus/neighborhood/tsa/tinytsa.cpp b/engines/pegasus/neighborhood/tsa/tinytsa.cpp
index c808325b0f..0c29e06f41 100644
--- a/engines/pegasus/neighborhood/tsa/tinytsa.cpp
+++ b/engines/pegasus/neighborhood/tsa/tinytsa.cpp
@@ -38,71 +38,81 @@ namespace Pegasus {
static const int16 kCompassShift = 30;
-static const TimeScale kTinyTSAMovieScale = 600;
-static const TimeScale kTinyTSAFramesPerSecond = 15;
-static const TimeScale kTinyTSAFrameDuration = 40;
+enum {
+ kTinyTSAMovieScale = 600,
+ kTinyTSAFramesPerSecond = 15,
+ kTinyTSAFrameDuration = 40
+};
// Alternate IDs.
-static const AlternateID kAltTinyTSANormal = 0;
+enum {
+ kAltTinyTSANormal = 0
+};
// Hot Spot Activation IDs.
-static const HotSpotActivationID kActivationTinyTSAJumpToNorad = 1;
-static const HotSpotActivationID kActivationTinyTSAJumpToMars = 2;
-static const HotSpotActivationID kActivationTinyTSAJumpToWSC = 3;
-static const HotSpotActivationID kActivationTinyTSAReadyForJumpMenu = 4;
-static const HotSpotActivationID kActivationTinyTSAMainJumpMenu = 5;
+enum {
+ kActivationTinyTSAJumpToNorad = 1,
+ kActivationTinyTSAJumpToMars = 2,
+ kActivationTinyTSAJumpToWSC = 3,
+ kActivationTinyTSAReadyForJumpMenu = 4,
+ kActivationTinyTSAMainJumpMenu = 5
+};
// Hot Spot IDs.
-static const HotSpotID kTinyTSA37NorthJumpToNoradSpotID = 5000;
-static const HotSpotID kTinyTSA37NorthCancelNoradSpotID = 5001;
-static const HotSpotID kTinyTSA37NorthJumpToMarsSpotID = 5002;
-static const HotSpotID kTinyTSA37NorthCancelMarsSpotID = 5003;
-static const HotSpotID kTinyTSA37NorthJumpToWSCSpotID = 5004;
-static const HotSpotID kTinyTSA37NorthCancelWSCSpotID = 5005;
-static const HotSpotID kTinyTSA37NorthJumpMenuSpotID = 5006;
-static const HotSpotID kTinyTSA37NorthNoradMenuSpotID = 5007;
-static const HotSpotID kTinyTSA37NorthMarsMenuSpotID = 5008;
-static const HotSpotID kTinyTSA37NorthWSCMenuSpotID = 5009;
+enum {
+ kTinyTSA37NorthJumpToNoradSpotID = 5000,
+ kTinyTSA37NorthCancelNoradSpotID = 5001,
+ kTinyTSA37NorthJumpToMarsSpotID = 5002,
+ kTinyTSA37NorthCancelMarsSpotID = 5003,
+ kTinyTSA37NorthJumpToWSCSpotID = 5004,
+ kTinyTSA37NorthCancelWSCSpotID = 5005,
+ kTinyTSA37NorthJumpMenuSpotID = 5006,
+ kTinyTSA37NorthNoradMenuSpotID = 5007,
+ kTinyTSA37NorthMarsMenuSpotID = 5008,
+ kTinyTSA37NorthWSCMenuSpotID = 5009
+};
// Extra sequence IDs.
-static const ExtraID kTinyTSA37PegasusDepart = 0;
-static const ExtraID kTinyTSA37TimeJumpToPegasus = 1;
-static const ExtraID kTinyTSA37RecallToDownload = 2;
-static const ExtraID kTinyTSA37ExitHilited = 3;
-static const ExtraID kTinyTSA37ExitToHorse = 4;
-static const ExtraID kTinyTSA37JumpMenu000 = 5;
-static const ExtraID kTinyTSA37JumpMenu001 = 6;
-static const ExtraID kTinyTSA37JumpMenu010 = 7;
-static const ExtraID kTinyTSA37JumpMenu011 = 8;
-static const ExtraID kTinyTSA37JumpMenu100 = 9;
-static const ExtraID kTinyTSA37JumpMenu101 = 10;
-static const ExtraID kTinyTSA37JumpMenu110 = 11;
-static const ExtraID kTinyTSA37JumpMenu111 = 12;
-static const ExtraID kTinyTSA37JumpToWSCMenu = 13;
-static const ExtraID kTinyTSA37CancelWSC = 14;
-static const ExtraID kTinyTSA37JumpToWSC = 15;
-static const ExtraID kTinyTSA37WSCToAI5 = 16;
-static const ExtraID kTinyTSA37PegasusAI5 = 17;
-static const ExtraID kTinyTSA37AI5ToWSC = 18;
-static const ExtraID kTinyTSA37WSCToDepart = 19;
-static const ExtraID kTinyTSA37JumpToMarsMenu = 20;
-static const ExtraID kTinyTSA37CancelMars = 21;
-static const ExtraID kTinyTSA37JumpToMars = 22;
-static const ExtraID kTinyTSA37MarsToAI6 = 23;
-static const ExtraID kTinyTSA37PegasusAI6 = 24;
-static const ExtraID kTinyTSA37AI6ToMars = 25;
-static const ExtraID kTinyTSA37MarsToDepart = 26;
-static const ExtraID kTinyTSA37JumpToNoradMenu = 27;
-static const ExtraID kTinyTSA37CancelNorad = 28;
-static const ExtraID kTinyTSA37JumpToNorad = 29;
-static const ExtraID kTinyTSA37NoradToAI7 = 30;
-static const ExtraID kTinyTSA37PegasusAI7 = 31;
-static const ExtraID kTinyTSA37AI7ToNorad = 32;
-static const ExtraID kTinyTSA37NoradToDepart = 33;
-static const ExtraID kTinyTSA37EnvironmentalScan = 34;
-static const ExtraID kTinyTSA37DownloadToMainMenu = 35;
-static const ExtraID kTinyTSA37DownloadToOpMemReview = 36;
-static const ExtraID kTinyTSA37OpMemReviewToMainMenu = 37;
+enum {
+ kTinyTSA37PegasusDepart = 0,
+ kTinyTSA37TimeJumpToPegasus = 1,
+ kTinyTSA37RecallToDownload = 2,
+ kTinyTSA37ExitHilited = 3,
+ kTinyTSA37ExitToHorse = 4,
+ kTinyTSA37JumpMenu000 = 5,
+ kTinyTSA37JumpMenu001 = 6,
+ kTinyTSA37JumpMenu010 = 7,
+ kTinyTSA37JumpMenu011 = 8,
+ kTinyTSA37JumpMenu100 = 9,
+ kTinyTSA37JumpMenu101 = 10,
+ kTinyTSA37JumpMenu110 = 11,
+ kTinyTSA37JumpMenu111 = 12,
+ kTinyTSA37JumpToWSCMenu = 13,
+ kTinyTSA37CancelWSC = 14,
+ kTinyTSA37JumpToWSC = 15,
+ kTinyTSA37WSCToAI5 = 16,
+ kTinyTSA37PegasusAI5 = 17,
+ kTinyTSA37AI5ToWSC = 18,
+ kTinyTSA37WSCToDepart = 19,
+ kTinyTSA37JumpToMarsMenu = 20,
+ kTinyTSA37CancelMars = 21,
+ kTinyTSA37JumpToMars = 22,
+ kTinyTSA37MarsToAI6 = 23,
+ kTinyTSA37PegasusAI6 = 24,
+ kTinyTSA37AI6ToMars = 25,
+ kTinyTSA37MarsToDepart = 26,
+ kTinyTSA37JumpToNoradMenu = 27,
+ kTinyTSA37CancelNorad = 28,
+ kTinyTSA37JumpToNorad = 29,
+ kTinyTSA37NoradToAI7 = 30,
+ kTinyTSA37PegasusAI7 = 31,
+ kTinyTSA37AI7ToNorad = 32,
+ kTinyTSA37NoradToDepart = 33,
+ kTinyTSA37EnvironmentalScan = 34,
+ kTinyTSA37DownloadToMainMenu = 35,
+ kTinyTSA37DownloadToOpMemReview = 36,
+ kTinyTSA37OpMemReviewToMainMenu = 37
+};
TinyTSA::TinyTSA(InputHandler *nextHandler, PegasusEngine *owner) : Neighborhood(nextHandler, owner, "Tiny TSA", kTinyTSAID) {
}
diff --git a/engines/pegasus/neighborhood/wsc/wsc.cpp b/engines/pegasus/neighborhood/wsc/wsc.cpp
index f009b35cdc..5e35d8ccc1 100644
--- a/engines/pegasus/neighborhood/wsc/wsc.cpp
+++ b/engines/pegasus/neighborhood/wsc/wsc.cpp
@@ -87,81 +87,85 @@ static const int kTimerEventPlasmaHit = 0;
static const int kTimerEventPlayerGawkingAtRobot = 1;
static const int kTimerEventPlayerGawkingAtRobot2 = 2;
-static const TimeValue kWSCMolecule1In = 0;
-static const TimeValue kWSCMolecule1Out = 937;
+enum {
+ kWSCMolecule1In = 0,
+ kWSCMolecule1Out = 937,
-static const TimeValue kWSCMolecule2In = 937;
-static const TimeValue kWSCMolecule2Out = 1864;
+ kWSCMolecule2In = 937,
+ kWSCMolecule2Out = 1864,
-static const TimeValue kWSCMolecule3In = 1864;
-static const TimeValue kWSCMolecule3Out = 2790;
+ kWSCMolecule3In = 1864,
+ kWSCMolecule3Out = 2790,
-static const TimeValue kWSCClick1In = 2790;
-static const TimeValue kWSCClick1Out = 2890;
+ kWSCClick1In = 2790,
+ kWSCClick1Out = 2890,
-static const TimeValue kWSCClick2In = 2890;
-static const TimeValue kWSCClick2Out = 3059;
+ kWSCClick2In = 2890,
+ kWSCClick2Out = 3059,
-static const TimeValue kWSCClick3In = 3059;
-static const TimeValue kWSCClick3Out = 3156;
+ kWSCClick3In = 3059,
+ kWSCClick3Out = 3156,
-static const TimeValue kWSCFlashlightClickIn = 3156;
-static const TimeValue kWSCFlashlightClickOut = 3211;
+ kWSCFlashlightClickIn = 3156,
+ kWSCFlashlightClickOut = 3211,
-static const TimeValue kWSCBumpIntoWallIn = 3211;
-static const TimeValue kWSCBumpIntoWallOut = 3514;
+ kWSCBumpIntoWallIn = 3211,
+ kWSCBumpIntoWallOut = 3514,
-static const TimeValue kWSCCantTransportIn = 3514;
-static const TimeValue kWSCCantTransportOut = 7791;
+ kWSCCantTransportIn = 3514,
+ kWSCCantTransportOut = 7791,
-static const TimeValue kHernandezNotHomeIn = 7791;
-static const TimeValue kHernandezNotHomeOut = 10199;
+ kHernandezNotHomeIn = 7791,
+ kHernandezNotHomeOut = 10199,
-static const TimeValue kWashingtonNotHomeIn = 10199;
-static const TimeValue kWashingtonNotHomeOut = 12649;
+ kWashingtonNotHomeIn = 10199,
+ kWashingtonNotHomeOut = 12649,
-static const TimeValue kSullivanNotHomeIn = 12649;
-static const TimeValue kSullivanNotHomeOut = 15031;
+ kSullivanNotHomeIn = 12649,
+ kSullivanNotHomeOut = 15031,
-static const TimeValue kNakamuraNotHomeIn = 15031;
-static const TimeValue kNakamuraNotHomeOut = 17545;
+ kNakamuraNotHomeIn = 15031,
+ kNakamuraNotHomeOut = 17545,
-static const TimeValue kGrailisNotHomeIn = 17545;
-static const TimeValue kGrailisNotHomeOut = 19937;
+ kGrailisNotHomeIn = 17545,
+ kGrailisNotHomeOut = 19937,
-static const TimeValue kTheriaultNotHomeIn = 19937;
-static const TimeValue kTheriaultNotHomeOut = 22395;
+ kTheriaultNotHomeIn = 19937,
+ kTheriaultNotHomeOut = 22395,
-static const TimeValue kGlennerNotHomeIn = 22395;
-static const TimeValue kGlennerNotHomeOut = 24770;
+ kGlennerNotHomeIn = 22395,
+ kGlennerNotHomeOut = 24770,
-static const TimeValue kSinclairNotHomeIn = 24770;
-static const TimeValue kSinclairNotHomeOut = 27328;
+ kSinclairNotHomeIn = 24770,
+ kSinclairNotHomeOut = 27328,
-static const TimeValue kWSCLabClosedIn = 27328;
-static const TimeValue kWSCLabClosedOut = 28904;
+ kWSCLabClosedIn = 27328,
+ kWSCLabClosedOut = 28904,
-static const TimeValue kSlidingDoorCloseIn = 28904;
-static const TimeValue kSlidingDoorCloseOut = 29295;
+ kSlidingDoorCloseIn = 28904,
+ kSlidingDoorCloseOut = 29295,
-static const TimeValue kSlimyDoorCloseIn = 29295;
-static const TimeValue kSlimyDoorCloseOut = 29788;
+ kSlimyDoorCloseIn = 29295,
+ kSlimyDoorCloseOut = 29788,
-static const TimeValue kPaging1In = 29788;
-static const TimeValue kPaging1Out = 32501;
+ kPaging1In = 29788,
+ kPaging1Out = 32501,
-static const TimeValue kPaging2In = 32501;
-static const TimeValue kPaging2Out = 34892;
+ kPaging2In = 32501,
+ kPaging2Out = 34892,
-static const TimeValue kCheckInIn = 34892;
-static const TimeValue kCheckInOut = 37789;
+ kCheckInIn = 34892,
+ kCheckInOut = 37789,
-static const TimeValue kDrinkAntidoteIn = 37789;
-static const TimeValue kDrinkAntidoteOut = 39725;
+ kDrinkAntidoteIn = 37789,
+ kDrinkAntidoteOut = 39725
+};
-static const TimeScale kWSCMovieScale = 600;
-static const TimeScale kWSCFramesPerSecond = 15;
-static const TimeScale kWSCFrameDuration = 40;
+enum {
+ kWSCMovieScale = 600,
+ kWSCFramesPerSecond = 15,
+ kWSCFrameDuration = 40
+};
// Alternate IDs.
static const AlternateID kAltWSCNormal = 0;
@@ -170,304 +174,312 @@ static const AlternateID kAltWSCW0ZDoorOpen = 2;
static const AlternateID kAltWSCPeopleAtW19North = 3;
// Room IDs.
-static const RoomID kWSC02 = 1;
-static const RoomID kWSC03 = 4;
-static const RoomID kWSC04 = 5;
-static const RoomID kWSC06 = 6;
-static const RoomID kWSC07 = 7;
-static const RoomID kWSC08 = 8;
-static const RoomID kWSC09 = 9;
-static const RoomID kWSC10 = 10;
-static const RoomID kWSC11 = 11;
-static const RoomID kWSC13 = 12;
-static const RoomID kWSC14 = 13;
-static const RoomID kWSC15 = 14;
-static const RoomID kWSC16 = 15;
-static const RoomID kWSC17 = 16;
-static const RoomID kWSC18 = 17;
-static const RoomID kWSC19 = 18;
-static const RoomID kWSC20 = 19;
-static const RoomID kWSC21 = 20;
-static const RoomID kWSC22 = 21;
-static const RoomID kWSC23 = 22;
-static const RoomID kWSC24 = 23;
-static const RoomID kWSC25 = 24;
-static const RoomID kWSC26 = 25;
-static const RoomID kWSC27 = 26;
-static const RoomID kWSC28 = 27;
-static const RoomID kWSC29 = 28;
-static const RoomID kWSC31 = 29;
-static const RoomID kWSC32 = 30;
-static const RoomID kWSC33 = 31;
-static const RoomID kWSC34 = 32;
-static const RoomID kWSC35 = 33;
-static const RoomID kWSC36 = 34;
-static const RoomID kWSC37 = 35;
-static const RoomID kWSC38 = 36;
-static const RoomID kWSC39 = 37;
-static const RoomID kWSC40 = 38;
-static const RoomID kWSC41 = 39;
-static const RoomID kWSC42 = 40;
-static const RoomID kWSC43 = 41;
-static const RoomID kWSC44 = 42;
-static const RoomID kWSC45 = 43;
-static const RoomID kWSC46 = 44;
-static const RoomID kWSC47 = 45;
-static const RoomID kWSC48 = 46;
-static const RoomID kWSC49 = 47;
-static const RoomID kWSC50 = 48;
-static const RoomID kWSC52 = 49;
-static const RoomID kWSC53 = 50;
-static const RoomID kWSC54 = 51;
-static const RoomID kWSC55 = 52;
-static const RoomID kWSC56 = 53;
-static const RoomID kWSC57 = 54;
-static const RoomID kWSC58 = 55;
-static const RoomID kWSC60 = 56;
-static const RoomID kWSC60East = 57;
-static const RoomID kWSC60North = 58;
-static const RoomID kWSC61 = 59;
-static const RoomID kWSC61South = 60;
-static const RoomID kWSC61West = 61;
-static const RoomID kWSC63 = 63;
-static const RoomID kWSC64 = 64;
-static const RoomID kWSC65 = 65;
-static const RoomID kWSC65Screen = 66;
-static const RoomID kWSC66 = 67;
-static const RoomID kWSC67 = 68;
-static const RoomID kWSC68 = 69;
-static const RoomID kWSC69 = 70;
-static const RoomID kWSC70 = 71;
-static const RoomID kWSC71 = 72;
-static const RoomID kWSC72 = 73;
-static const RoomID kWSC73 = 74;
-static const RoomID kWSC74 = 75;
-static const RoomID kWSC75 = 76;
-static const RoomID kWSC0Z = 77;
-static const RoomID kWSC76 = 78;
-static const RoomID kWSC77 = 79;
-static const RoomID kWSC78 = 80;
-static const RoomID kWSC79 = 81;
-static const RoomID kWSC80 = 82;
-static const RoomID kWSC81 = 83;
-static const RoomID kWSC82 = 84;
-static const RoomID kWSC83 = 85;
-static const RoomID kWSC84 = 86;
-static const RoomID kWSC85 = 87;
-static const RoomID kWSC86 = 88;
-static const RoomID kWSC87 = 89;
-static const RoomID kWSC88 = 90;
-static const RoomID kWSC89 = 91;
-static const RoomID kWSC90 = 92;
-static const RoomID kWSC91 = 93;
-static const RoomID kWSC92 = 94;
-static const RoomID kWSC93 = 95;
-static const RoomID kWSC94 = 96;
-static const RoomID kWSC95 = 97;
-static const RoomID kWSC96 = 98;
-static const RoomID kWSC97 = 99;
-static const RoomID kWSC98 = 100;
-static const RoomID kWSCDeathRoom = 101;
+enum {
+ kWSC02 = 1,
+ kWSC03 = 4,
+ kWSC04 = 5,
+ kWSC06 = 6,
+ kWSC07 = 7,
+ kWSC08 = 8,
+ kWSC09 = 9,
+ kWSC10 = 10,
+ kWSC11 = 11,
+ kWSC13 = 12,
+ kWSC14 = 13,
+ kWSC15 = 14,
+ kWSC16 = 15,
+ kWSC17 = 16,
+ kWSC18 = 17,
+ kWSC19 = 18,
+ kWSC20 = 19,
+ kWSC21 = 20,
+ kWSC22 = 21,
+ kWSC23 = 22,
+ kWSC24 = 23,
+ kWSC25 = 24,
+ kWSC26 = 25,
+ kWSC27 = 26,
+ kWSC28 = 27,
+ kWSC29 = 28,
+ kWSC31 = 29,
+ kWSC32 = 30,
+ kWSC33 = 31,
+ kWSC34 = 32,
+ kWSC35 = 33,
+ kWSC36 = 34,
+ kWSC37 = 35,
+ kWSC38 = 36,
+ kWSC39 = 37,
+ kWSC40 = 38,
+ kWSC41 = 39,
+ kWSC42 = 40,
+ kWSC43 = 41,
+ kWSC44 = 42,
+ kWSC45 = 43,
+ kWSC46 = 44,
+ kWSC47 = 45,
+ kWSC48 = 46,
+ kWSC49 = 47,
+ kWSC50 = 48,
+ kWSC52 = 49,
+ kWSC53 = 50,
+ kWSC54 = 51,
+ kWSC55 = 52,
+ kWSC56 = 53,
+ kWSC57 = 54,
+ kWSC58 = 55,
+ kWSC60 = 56,
+ kWSC60East = 57,
+ kWSC60North = 58,
+ kWSC61 = 59,
+ kWSC61South = 60,
+ kWSC61West = 61,
+ kWSC63 = 63,
+ kWSC64 = 64,
+ kWSC65 = 65,
+ kWSC65Screen = 66,
+ kWSC66 = 67,
+ kWSC67 = 68,
+ kWSC68 = 69,
+ kWSC69 = 70,
+ kWSC70 = 71,
+ kWSC71 = 72,
+ kWSC72 = 73,
+ kWSC73 = 74,
+ kWSC74 = 75,
+ kWSC75 = 76,
+ kWSC0Z = 77,
+ kWSC76 = 78,
+ kWSC77 = 79,
+ kWSC78 = 80,
+ kWSC79 = 81,
+ kWSC80 = 82,
+ kWSC81 = 83,
+ kWSC82 = 84,
+ kWSC83 = 85,
+ kWSC84 = 86,
+ kWSC85 = 87,
+ kWSC86 = 88,
+ kWSC87 = 89,
+ kWSC88 = 90,
+ kWSC89 = 91,
+ kWSC90 = 92,
+ kWSC91 = 93,
+ kWSC92 = 94,
+ kWSC93 = 95,
+ kWSC94 = 96,
+ kWSC95 = 97,
+ kWSC96 = 98,
+ kWSC97 = 99,
+ kWSC98 = 100,
+ kWSCDeathRoom = 101
+};
// Hot Spot Activation IDs.
-static const HotSpotActivationID kActivationZoomedInToAnalyzer = 1;
-static const HotSpotActivationID kActivationShotByRobot = 2;
-static const HotSpotActivationID kActivationWarnedAboutPoison = 3;
-static const HotSpotActivationID kActivationMorphScreenOff = 4;
-static const HotSpotActivationID kActivationReadyForMorph = 5;
-static const HotSpotActivationID kActivationMorphLooping = 6;
-static const HotSpotActivationID kActivationMorphInterrupted = 7;
-static const HotSpotActivationID kActivationW03NorthOff = 8;
-static const HotSpotActivationID kActivationW03NorthReadyForInstructions = 9;
-static const HotSpotActivationID kActivationW03NorthSawInstructions = 10;
-static const HotSpotActivationID kActivationW03NorthInGame = 11;
-static const HotSpotActivationID kActivationReadyForSynthesis = 12;
-static const HotSpotActivationID kActivationSynthesizerLooping = 13;
-static const HotSpotActivationID kActivationReadyForMap = 14;
-static const HotSpotActivationID kActivationSinclairOfficeLocked = 15;
-static const HotSpotActivationID kActivationW58SouthDoorLocked = 16;
-static const HotSpotActivationID kActivationW61SouthOff = 17;
-static const HotSpotActivationID kActivationW61SouthOn = 18;
-static const HotSpotActivationID kActivationW61MessagesOff = 19;
-static const HotSpotActivationID kActivationW61MessagesOn = 20;
-static const HotSpotActivationID kActivationWSCRobotHeadOpen = 21;
-static const HotSpotActivationID kActivationRobotTurning = 22;
-static const HotSpotActivationID kActivationRobotDead = 23;
-static const HotSpotActivationID kActivationRobotGone = 24;
+enum {
+ kActivationZoomedInToAnalyzer = 1,
+ kActivationShotByRobot = 2,
+ kActivationWarnedAboutPoison = 3,
+ kActivationMorphScreenOff = 4,
+ kActivationReadyForMorph = 5,
+ kActivationMorphLooping = 6,
+ kActivationMorphInterrupted = 7,
+ kActivationW03NorthOff = 8,
+ kActivationW03NorthReadyForInstructions = 9,
+ kActivationW03NorthSawInstructions = 10,
+ kActivationW03NorthInGame = 11,
+ kActivationReadyForSynthesis = 12,
+ kActivationSynthesizerLooping = 13,
+ kActivationReadyForMap = 14,
+ kActivationSinclairOfficeLocked = 15,
+ kActivationW58SouthDoorLocked = 16,
+ kActivationW61SouthOff = 17,
+ kActivationW61SouthOn = 18,
+ kActivationW61MessagesOff = 19,
+ kActivationW61MessagesOn = 20,
+ kActivationWSCRobotHeadOpen = 21,
+ kActivationRobotTurning = 22,
+ kActivationRobotDead = 23,
+ kActivationRobotGone = 24
+};
// Hot Spot IDs.
-static const HotSpotID kWSCDropDartSpotID = 5000;
-static const HotSpotID kWSCTurnOnAnalyzerSpotID = 5001;
-static const HotSpotID kWSCAnalyzerScreenSpotID = 5002;
-static const HotSpotID kWSCSpinRobotSpotID = 5003;
-static const HotSpotID kWSC01YesSpotID = 5004;
-static const HotSpotID kWSC01NoSpotID = 5005;
-static const HotSpotID kWSC01AcknowledgeWarningSpotID = 5006;
-static const HotSpotID kWSC02SouthMorphSpotID = 5007;
-static const HotSpotID kWSC02SouthMessagesSpotID = 5008;
-static const HotSpotID kWSC02SouthMorphOutSpotID = 5009;
-static const HotSpotID kWSC02ActivateMorphScreenSpotID = 5010;
-static const HotSpotID kWSC02SouthStartMorphSpotID = 5011;
-static const HotSpotID kWSC02SouthInterruptMorphSpotID = 5012;
-static const HotSpotID kWSC02SouthMorphFinishedSpotID = 5013;
-static const HotSpotID kWSC02SouthTakeArgonSpotID = 5014;
-static const HotSpotID kWSC02SouthMessagesOutSpotID = 5015;
-static const HotSpotID kWSC02SouthTakeNitrogenSpotID = 5016;
-static const HotSpotID kWSC02SouthPlayMessagesSpotID = 5017;
-static const HotSpotID kWSC03NorthActivateScreenSpotID = 5018;
-static const HotSpotID kWSC03NorthBuildMoleculeSpotID = 5019;
-static const HotSpotID kWSC03NorthProceedSpotID = 5020;
-static const HotSpotID kWSC03NorthMolecule1SpotID = 5021;
-static const HotSpotID kWSC03NorthMolecule2SpotID = 5022;
-static const HotSpotID kWSC03NorthMolecule3SpotID = 5023;
-static const HotSpotID kWSC03NorthMolecule4SpotID = 5024;
-static const HotSpotID kWSC03NorthMolecule5SpotID = 5025;
-static const HotSpotID kWSC03NorthMolecule6SpotID = 5026;
-static const HotSpotID kWSC03SouthActivateSynthesizerSpotID = 5027;
-static const HotSpotID kWSC03SouthPickUpAntidoteSpotID = 5028;
-static const HotSpotID kWSC07SouthMapSpotID = 5029;
-static const HotSpotID kW42EastUnlockDoorSpotID = 5030;
-static const HotSpotID kW56NorthMapSpotID = 5031;
-static const HotSpotID kW58SouthPryDoorSpotID = 5032;
-static const HotSpotID kWSC60EastSpotID = 5033;
-static const HotSpotID kWSC60NorthSpotID = 5034;
-static const HotSpotID kWSC60EastOutSpotID = 5035;
-static const HotSpotID kWSC60NorthOutSpotID = 5036;
-static const HotSpotID kWSC61EastSpotID = 5037;
-static const HotSpotID kWSC61SouthSpotID = 5038;
-static const HotSpotID kW61SouthMachineGunSpotID = 5039;
-static const HotSpotID kW61SouthDropMachineGunSpotID = 5040;
-static const HotSpotID kWSC61WestSpotID = 5041;
-static const HotSpotID kWSC61SouthOutSpotID = 5042;
-static const HotSpotID kW61SouthActivateSpotID = 5043;
-static const HotSpotID kW61SmartAlloysSpotID = 5044;
-static const HotSpotID kW61MorphingSpotID = 5045;
-static const HotSpotID kW61TimeBendingSpotID = 5046;
-static const HotSpotID kWSC61WestOutSpotID = 5047;
-static const HotSpotID kW61TurnOnMessagesSpotID = 5048;
-static const HotSpotID kW61WhiteMessageSpotID = 5049;
-static const HotSpotID kW61WalchekMessageSpotID = 5050;
-static const HotSpotID kWSC65SouthScreenSpotID = 5051;
-static const HotSpotID kWSC65SouthScreenOutSpotID = 5052;
-static const HotSpotID kW98RetinalChipSpotID = 5053;
-static const HotSpotID kW98MapChipSpotID = 5054;
-static const HotSpotID kW98OpticalChipSpotID = 5055;
-static const HotSpotID kW98DropArgonSpotID = 5056;
-static const HotSpotID kW98GrabCableSpotID = 5057;
-static const HotSpotID kW98OpenRobotSpotID = 5058;
-static const HotSpotID kW98StunGunSpotID = 5059;
+enum {
+ kWSCDropDartSpotID = 5000,
+ kWSCTurnOnAnalyzerSpotID = 5001,
+ kWSCAnalyzerScreenSpotID = 5002,
+ kWSCSpinRobotSpotID = 5003,
+ kWSC01YesSpotID = 5004,
+ kWSC01NoSpotID = 5005,
+ kWSC01AcknowledgeWarningSpotID = 5006,
+ kWSC02SouthMorphSpotID = 5007,
+ kWSC02SouthMessagesSpotID = 5008,
+ kWSC02SouthMorphOutSpotID = 5009,
+ kWSC02ActivateMorphScreenSpotID = 5010,
+ kWSC02SouthStartMorphSpotID = 5011,
+ kWSC02SouthInterruptMorphSpotID = 5012,
+ kWSC02SouthMorphFinishedSpotID = 5013,
+ kWSC02SouthTakeArgonSpotID = 5014,
+ kWSC02SouthMessagesOutSpotID = 5015,
+ kWSC02SouthTakeNitrogenSpotID = 5016,
+ kWSC02SouthPlayMessagesSpotID = 5017,
+ kWSC03NorthActivateScreenSpotID = 5018,
+ kWSC03NorthBuildMoleculeSpotID = 5019,
+ kWSC03NorthProceedSpotID = 5020,
+ kWSC03NorthMolecule1SpotID = 5021,
+ kWSC03NorthMolecule2SpotID = 5022,
+ kWSC03NorthMolecule3SpotID = 5023,
+ kWSC03NorthMolecule4SpotID = 5024,
+ kWSC03NorthMolecule5SpotID = 5025,
+ kWSC03NorthMolecule6SpotID = 5026,
+ kWSC03SouthActivateSynthesizerSpotID = 5027,
+ kWSC03SouthPickUpAntidoteSpotID = 5028,
+ kWSC07SouthMapSpotID = 5029,
+ kW42EastUnlockDoorSpotID = 5030,
+ kW56NorthMapSpotID = 5031,
+ kW58SouthPryDoorSpotID = 5032,
+ kWSC60EastSpotID = 5033,
+ kWSC60NorthSpotID = 5034,
+ kWSC60EastOutSpotID = 5035,
+ kWSC60NorthOutSpotID = 5036,
+ kWSC61EastSpotID = 5037,
+ kWSC61SouthSpotID = 5038,
+ kW61SouthMachineGunSpotID = 5039,
+ kW61SouthDropMachineGunSpotID = 5040,
+ kWSC61WestSpotID = 5041,
+ kWSC61SouthOutSpotID = 5042,
+ kW61SouthActivateSpotID = 5043,
+ kW61SmartAlloysSpotID = 5044,
+ kW61MorphingSpotID = 5045,
+ kW61TimeBendingSpotID = 5046,
+ kWSC61WestOutSpotID = 5047,
+ kW61TurnOnMessagesSpotID = 5048,
+ kW61WhiteMessageSpotID = 5049,
+ kW61WalchekMessageSpotID = 5050,
+ kWSC65SouthScreenSpotID = 5051,
+ kWSC65SouthScreenOutSpotID = 5052,
+ kW98RetinalChipSpotID = 5053,
+ kW98MapChipSpotID = 5054,
+ kW98OpticalChipSpotID = 5055,
+ kW98DropArgonSpotID = 5056,
+ kW98GrabCableSpotID = 5057,
+ kW98OpenRobotSpotID = 5058,
+ kW98StunGunSpotID = 5059
+};
// Extra sequence IDs.
-static const ExtraID kWSCArrivalFromTSA = 0;
-static const ExtraID kWSCShotByRobot = 1;
-static const ExtraID kWSCDartScan1 = 2;
-static const ExtraID kWSCDartScan2 = 3;
-static const ExtraID kWSCDartScanNo = 4;
-static const ExtraID kWSCDartScan3 = 5;
-static const ExtraID kWSCAnalyzerPowerUp = 6;
-static const ExtraID kWSCAnalyzerPowerUpWithDart = 7;
-static const ExtraID kWSCDropDartIntoAnalyzer = 8;
-static const ExtraID kWSCAnalyzeDart = 9;
-static const ExtraID kWSCZoomOutFromAnalyzer = 10;
-static const ExtraID kWSCSpinRobot = 11;
-static const ExtraID kWSC02MorphZoomNoArgon = 12;
-static const ExtraID kWSC02MessagesZoomNoNitrogen = 13;
-static const ExtraID kWSC02ZoomOutNoArgon = 14;
-static const ExtraID kWSC02TurnOnMorphScreen = 15;
-static const ExtraID kWSC02DropToMorphExperiment = 16;
-static const ExtraID kWSC02MorphLoop = 17;
-static const ExtraID kWSC02MorphInterruption = 18;
-static const ExtraID kWSC02MorphFinished = 19;
-static const ExtraID kWSC02TurnOffMorphScreen = 20;
-static const ExtraID kWSC02SouthViewNoArgon = 21;
-static const ExtraID kMessagesMovedToOffice = 22;
-static const ExtraID kMessagesOff = 23;
-static const ExtraID kMessagesZoomOutNoNitrogen = 24;
-static const ExtraID kMessagesMovedToOfficeNoNitrogen = 25;
-static const ExtraID kMessagesOffNoNitrogen = 26;
-static const ExtraID kMessagesViewNoNitrogen = 27;
-static const ExtraID kMessagesViewMachineOnNoNitrogen = 28;
-static const ExtraID kW03NorthActivate = 29;
-static const ExtraID kW03NorthGetData = 30;
-static const ExtraID kW03NorthInstructions = 31;
-static const ExtraID kW03NorthPrepMolecule1 = 32;
-static const ExtraID kW03NorthPrepMolecule2 = 33;
-static const ExtraID kW03NorthPrepMolecule3 = 34;
-static const ExtraID kW03NorthFinishSynthesis = 35;
-static const ExtraID kW03SouthCreateAntidote = 36;
-static const ExtraID kW03SouthAntidoteLoop = 37;
-static const ExtraID kW03SouthDeactivate = 38;
-static const ExtraID kW03SouthViewNoAntidote = 39;
-static const ExtraID kWSC07SouthMap = 40;
-static const ExtraID kW17WestPeopleCrossing = 41;
-static const ExtraID kW17WestPeopleCrossingView = 42;
-static const ExtraID kW21SouthPeopleCrossing = 43;
-static const ExtraID kW24SouthPeopleCrossing = 44;
-static const ExtraID kW34EastPeopleCrossing = 45;
-static const ExtraID kW36WestPeopleCrossing = 46;
-static const ExtraID kW38NorthPeopleCrossing = 47;
-static const ExtraID kW46SouthPeopleCrossing = 48;
-static const ExtraID kW49NorthPeopleCrossing = 49;
-static const ExtraID kW49NorthPeopleCrossingView = 50;
-static const ExtraID kWSC56SouthMap = 51;
-static const ExtraID kNerdAtTheDoor1 = 52;
-static const ExtraID kNerdAtTheDoor2 = 53;
-static const ExtraID kW61SouthZoomInNoGun = 54;
-static const ExtraID kW61Brochure = 55;
-static const ExtraID kW61SouthScreenOnWithGun = 56;
-static const ExtraID kW61SouthScreenOffWithGun = 57;
-static const ExtraID kW61SouthSmartAlloysWithGun = 58;
-static const ExtraID kW61SouthMorphingWithGun = 59;
-static const ExtraID kW61SouthTimeBendingWithGun = 60;
-static const ExtraID kW61SouthZoomOutNoGun = 61;
-static const ExtraID kW61SouthScreenOnNoGun = 62;
-static const ExtraID kW61SouthScreenOffNoGun = 63;
-static const ExtraID kW61SouthSmartAlloysNoGun = 64;
-static const ExtraID kW61SouthMorphingNoGun = 65;
-static const ExtraID kW61SouthTimeBendingNoGun = 66;
-static const ExtraID kW61MessagesOn = 67;
-static const ExtraID kW61MessagesOff = 68;
-static const ExtraID kW61WhiteMessage = 69;
-static const ExtraID kW61WalchekMessage = 70;
-static const ExtraID kW61WalchekEasterEgg1 = 71;
-static const ExtraID kW62SouthPlasmaRobotAppears = 72;
-static const ExtraID kW62ZoomToRobot = 73;
-static const ExtraID kW62ZoomOutFromRobot = 74;
-static const ExtraID kW62PlasmaDodgeSurvive = 75;
-static const ExtraID kW62PlasmaDodgeDie = 76;
-static const ExtraID kW65SouthSinclairLecture = 77;
-static const ExtraID kW73WestPeopleCrossing = 78;
-static const ExtraID kW73WestPeopleCrossingView = 79;
-static const ExtraID kW0ZSpottedByWomen = 80;
-static const ExtraID kW95RobotShoots = 81;
-static const ExtraID kW98MorphsToRobot = 82;
-static const ExtraID kW98RobotShoots = 83;
-static const ExtraID kW98RobotShocked = 84;
-static const ExtraID kW98RobotGassed = 85;
-static const ExtraID kW98RobotHeadOpensDark = 86;
-static const ExtraID kW98RobotHead000Dark = 87;
-static const ExtraID kW98RobotHead001Dark = 88;
-static const ExtraID kW98RobotHead010Dark = 89;
-static const ExtraID kW98RobotHead011Dark = 90;
-static const ExtraID kW98RobotHead100Dark = 91;
-static const ExtraID kW98RobotHead101Dark = 92;
-static const ExtraID kW98RobotHead110Dark = 93;
-static const ExtraID kW98RobotHead111Dark = 94;
-static const ExtraID kW98RobotHeadClosesDark = 95;
-static const ExtraID kW98WestViewWithGunDark = 96;
-static const ExtraID kW98WestViewNoGunDark = 97;
-static const ExtraID kW98RobotHeadOpensLight = 98;
-static const ExtraID kW98RobotHead000Light = 99;
-static const ExtraID kW98RobotHead001Light = 100;
-static const ExtraID kW98RobotHead010Light = 101;
-static const ExtraID kW98RobotHead011Light = 102;
-static const ExtraID kW98RobotHead100Light = 103;
-static const ExtraID kW98RobotHead101Light = 104;
-static const ExtraID kW98RobotHead110Light = 105;
-static const ExtraID kW98RobotHead111Light = 106;
-static const ExtraID kW98RobotHeadClosesLight = 107;
-static const ExtraID kW98WestViewWithGunLight = 108;
-static const ExtraID kW98WestViewNoGunLight = 109;
+enum {
+ kWSCArrivalFromTSA = 0,
+ kWSCShotByRobot = 1,
+ kWSCDartScan1 = 2,
+ kWSCDartScan2 = 3,
+ kWSCDartScanNo = 4,
+ kWSCDartScan3 = 5,
+ kWSCAnalyzerPowerUp = 6,
+ kWSCAnalyzerPowerUpWithDart = 7,
+ kWSCDropDartIntoAnalyzer = 8,
+ kWSCAnalyzeDart = 9,
+ kWSCZoomOutFromAnalyzer = 10,
+ kWSCSpinRobot = 11,
+ kWSC02MorphZoomNoArgon = 12,
+ kWSC02MessagesZoomNoNitrogen = 13,
+ kWSC02ZoomOutNoArgon = 14,
+ kWSC02TurnOnMorphScreen = 15,
+ kWSC02DropToMorphExperiment = 16,
+ kWSC02MorphLoop = 17,
+ kWSC02MorphInterruption = 18,
+ kWSC02MorphFinished = 19,
+ kWSC02TurnOffMorphScreen = 20,
+ kWSC02SouthViewNoArgon = 21,
+ kMessagesMovedToOffice = 22,
+ kMessagesOff = 23,
+ kMessagesZoomOutNoNitrogen = 24,
+ kMessagesMovedToOfficeNoNitrogen = 25,
+ kMessagesOffNoNitrogen = 26,
+ kMessagesViewNoNitrogen = 27,
+ kMessagesViewMachineOnNoNitrogen = 28,
+ kW03NorthActivate = 29,
+ kW03NorthGetData = 30,
+ kW03NorthInstructions = 31,
+ kW03NorthPrepMolecule1 = 32,
+ kW03NorthPrepMolecule2 = 33,
+ kW03NorthPrepMolecule3 = 34,
+ kW03NorthFinishSynthesis = 35,
+ kW03SouthCreateAntidote = 36,
+ kW03SouthAntidoteLoop = 37,
+ kW03SouthDeactivate = 38,
+ kW03SouthViewNoAntidote = 39,
+ kWSC07SouthMap = 40,
+ kW17WestPeopleCrossing = 41,
+ kW17WestPeopleCrossingView = 42,
+ kW21SouthPeopleCrossing = 43,
+ kW24SouthPeopleCrossing = 44,
+ kW34EastPeopleCrossing = 45,
+ kW36WestPeopleCrossing = 46,
+ kW38NorthPeopleCrossing = 47,
+ kW46SouthPeopleCrossing = 48,
+ kW49NorthPeopleCrossing = 49,
+ kW49NorthPeopleCrossingView = 50,
+ kWSC56SouthMap = 51,
+ kNerdAtTheDoor1 = 52,
+ kNerdAtTheDoor2 = 53,
+ kW61SouthZoomInNoGun = 54,
+ kW61Brochure = 55,
+ kW61SouthScreenOnWithGun = 56,
+ kW61SouthScreenOffWithGun = 57,
+ kW61SouthSmartAlloysWithGun = 58,
+ kW61SouthMorphingWithGun = 59,
+ kW61SouthTimeBendingWithGun = 60,
+ kW61SouthZoomOutNoGun = 61,
+ kW61SouthScreenOnNoGun = 62,
+ kW61SouthScreenOffNoGun = 63,
+ kW61SouthSmartAlloysNoGun = 64,
+ kW61SouthMorphingNoGun = 65,
+ kW61SouthTimeBendingNoGun = 66,
+ kW61MessagesOn = 67,
+ kW61MessagesOff = 68,
+ kW61WhiteMessage = 69,
+ kW61WalchekMessage = 70,
+ kW61WalchekEasterEgg1 = 71,
+ kW62SouthPlasmaRobotAppears = 72,
+ kW62ZoomToRobot = 73,
+ kW62ZoomOutFromRobot = 74,
+ kW62PlasmaDodgeSurvive = 75,
+ kW62PlasmaDodgeDie = 76,
+ kW65SouthSinclairLecture = 77,
+ kW73WestPeopleCrossing = 78,
+ kW73WestPeopleCrossingView = 79,
+ kW0ZSpottedByWomen = 80,
+ kW95RobotShoots = 81,
+ kW98MorphsToRobot = 82,
+ kW98RobotShoots = 83,
+ kW98RobotShocked = 84,
+ kW98RobotGassed = 85,
+ kW98RobotHeadOpensDark = 86,
+ kW98RobotHead000Dark = 87,
+ kW98RobotHead001Dark = 88,
+ kW98RobotHead010Dark = 89,
+ kW98RobotHead011Dark = 90,
+ kW98RobotHead100Dark = 91,
+ kW98RobotHead101Dark = 92,
+ kW98RobotHead110Dark = 93,
+ kW98RobotHead111Dark = 94,
+ kW98RobotHeadClosesDark = 95,
+ kW98WestViewWithGunDark = 96,
+ kW98WestViewNoGunDark = 97,
+ kW98RobotHeadOpensLight = 98,
+ kW98RobotHead000Light = 99,
+ kW98RobotHead001Light = 100,
+ kW98RobotHead010Light = 101,
+ kW98RobotHead011Light = 102,
+ kW98RobotHead100Light = 103,
+ kW98RobotHead101Light = 104,
+ kW98RobotHead110Light = 105,
+ kW98RobotHead111Light = 106,
+ kW98RobotHeadClosesLight = 107,
+ kW98WestViewWithGunLight = 108,
+ kW98WestViewNoGunLight = 109
+};
static const CoordType kMoleculesMovieLeft = kNavAreaLeft + 112;
static const CoordType kMoleculesMovieTop = kNavAreaTop + 40;
diff --git a/engines/pegasus/pegasus.cpp b/engines/pegasus/pegasus.cpp
index 0010180d8d..4262ad4c12 100644
--- a/engines/pegasus/pegasus.cpp
+++ b/engines/pegasus/pegasus.cpp
@@ -979,7 +979,7 @@ void PegasusEngine::doGameMenuCommand(const GameMenuCommand command) {
resetIntroTimer();
break;
case kMenuCmdPauseSave:
- result = showSaveDialog();
+ result = showSaveDialog();
if (result.getCode() != Common::kUserCanceled) {
if (result.getCode() != Common::kNoError)
@@ -2514,7 +2514,7 @@ void PegasusEngine::initKeymap() {
{ Common::KEYCODE_t, "TMA", _("Toggle Center Data Display") },
{ Common::KEYCODE_i, "TIN", _("Display/Hide Info Screen") },
{ Common::KEYCODE_ESCAPE, "PM", _("Display/Hide Pause Menu") },
- { Common::KEYCODE_e, "WTF", _("???") } // easter egg key (without being completely upfront about it)
+ { Common::KEYCODE_e, "WTF", "???" } // easter egg key (without being completely upfront about it)
};
for (uint i = 0; i < ARRAYSIZE(keyActionEntries); i++) {
diff --git a/engines/prince/animation.cpp b/engines/prince/animation.cpp
new file mode 100644
index 0000000000..aabdd7a623
--- /dev/null
+++ b/engines/prince/animation.cpp
@@ -0,0 +1,178 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "prince/animation.h"
+#include "prince/decompress.h"
+
+#include "common/debug.h"
+#include "common/endian.h"
+
+namespace Prince {
+
+Animation::Animation() : _loopCount(0), _phaseCount(0), _frameCount(0), _baseX(0), _baseY(0)
+{
+}
+
+Animation::~Animation() {
+ clear();
+}
+
+void Animation::clear() {
+ _phaseList.clear();
+ for (int i = 0; i < _frameCount; i++) {
+ _frameList[i]._surface->free();
+ delete _frameList[i]._surface;
+ _frameList[i]._surface = nullptr;
+ if (_frameList[i]._compressedData != nullptr) {
+ free(_frameList[i]._compressedData);
+ _frameList[i]._compressedData = nullptr;
+ }
+ }
+}
+
+bool Animation::loadStream(Common::SeekableReadStream &stream) {
+ stream.skip(2); // skip not used x and y coord diff
+ _loopCount = stream.readUint16LE();
+ _phaseCount = stream.readUint16LE();
+ stream.skip(2); // skip _frameCount here
+ _baseX = stream.readUint16LE();
+ _baseY = stream.readUint16LE();
+ uint32 phaseTableOffset = stream.readUint32LE();
+ uint32 tableOfFrameOffsets = stream.pos();
+
+ stream.seek(phaseTableOffset);
+ Phase tempPhase;
+ _frameCount = 0;
+ for (int phase = 0; phase < _phaseCount; phase++) {
+ tempPhase._phaseOffsetX = stream.readSint16LE();
+ tempPhase._phaseOffsetY = stream.readSint16LE();
+ tempPhase._phaseToFrameIndex = stream.readUint16LE();
+ if (tempPhase._phaseToFrameIndex > _frameCount) {
+ _frameCount = tempPhase._phaseToFrameIndex;
+ }
+ _phaseList.push_back(tempPhase);
+ stream.skip(2);
+ }
+ if (_phaseCount) {
+ _frameCount++;
+ }
+
+ Frame tempFrame;
+ for (int frame = 0; frame < _frameCount; frame++) {
+ stream.seek(tableOfFrameOffsets + frame * 4);
+ uint32 frameInfoOffset = stream.readUint32LE();
+ stream.seek(frameInfoOffset);
+ uint16 frameWidth = stream.readUint16LE();
+ uint16 frameHeight = stream.readUint16LE();
+ uint32 frameDataPos = stream.pos();
+ uint32 frameDataOffset = stream.readUint32BE();
+
+ tempFrame._surface = new Graphics::Surface();
+ tempFrame._surface->create(frameWidth, frameHeight, Graphics::PixelFormat::createFormatCLUT8());
+ if (frameDataOffset == MKTAG('m', 'a', 's', 'm')) {
+ tempFrame._isCompressed = true;
+ tempFrame._dataSize = stream.readUint32LE();
+ tempFrame._compressedData = (byte *)malloc(tempFrame._dataSize);
+ stream.read(tempFrame._compressedData, tempFrame._dataSize);
+ } else {
+ tempFrame._isCompressed = false;
+ tempFrame._dataSize = 0;
+ tempFrame._compressedData = nullptr;
+ stream.seek(frameDataPos);
+ for (uint16 i = 0; i < frameHeight; i++) {
+ stream.read(tempFrame._surface->getBasePtr(0, i), frameWidth);
+ }
+ }
+ _frameList.push_back(tempFrame);
+ }
+
+ return true;
+}
+
+int16 Animation::getLoopCount() const {
+ return _loopCount;
+}
+
+int32 Animation::getPhaseCount() const {
+ return _phaseCount;
+}
+
+int32 Animation::getFrameCount() const {
+ return _frameCount;
+}
+
+int16 Animation::getBaseX() const {
+ return _baseX;
+}
+
+int16 Animation::getBaseY() const {
+ return _baseY;
+}
+
+int16 Animation::getPhaseOffsetX(int phaseIndex) const {
+ if (phaseIndex < _phaseCount) {
+ return _phaseList[phaseIndex]._phaseOffsetX;
+ } else {
+ error("getPhaseOffsetX() phaseIndex: %d, phaseCount: %d", phaseIndex, _phaseCount);
+ }
+}
+
+int16 Animation::getPhaseOffsetY(int phaseIndex) const {
+ if (phaseIndex < _phaseCount) {
+ return _phaseList[phaseIndex]._phaseOffsetY;
+ } else {
+ error("getPhaseOffsetY() phaseIndex: %d, phaseCount: %d", phaseIndex, _phaseCount);
+ }
+}
+
+int16 Animation::getPhaseFrameIndex(int phaseIndex) const {
+ if (phaseIndex < _phaseCount) {
+ return _phaseList[phaseIndex]._phaseToFrameIndex;
+ } else {
+ error("getPhaseFrameIndex() phaseIndex: %d, phaseCount: %d", phaseIndex, _phaseCount);
+ }
+}
+
+Graphics::Surface *Animation::getFrame(int frameIndex) {
+ if (frameIndex < _frameCount) {
+ if (_frameList[frameIndex]._isCompressed) {
+ Decompressor dec;
+ byte *ddata = (byte *)malloc(_frameList[frameIndex]._dataSize);
+ dec.decompress(_frameList[frameIndex]._compressedData, ddata, _frameList[frameIndex]._dataSize);
+ int frameHeight = _frameList[frameIndex]._surface->h;
+ int frameWidth = _frameList[frameIndex]._surface->w;
+ for (uint16 i = 0; i < frameHeight; i++) {
+ memcpy(_frameList[frameIndex]._surface->getBasePtr(0, i), ddata + frameWidth * i, frameWidth);
+ }
+ free(ddata);
+ free(_frameList[frameIndex]._compressedData);
+ _frameList[frameIndex]._compressedData = nullptr;
+ _frameList[frameIndex]._dataSize = 0;
+ _frameList[frameIndex]._isCompressed = false;
+ }
+ return _frameList[frameIndex]._surface;
+ } else {
+ error("getFrame() frameIndex: %d, frameCount: %d", frameIndex, _frameCount);
+ }
+}
+
+} // End of namespace Prince
diff --git a/engines/prince/animation.h b/engines/prince/animation.h
new file mode 100644
index 0000000000..3471ffa158
--- /dev/null
+++ b/engines/prince/animation.h
@@ -0,0 +1,73 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef PRINCE_ANIMATION_H
+#define PRINCE_ANIMATION_H
+
+#include "common/array.h"
+#include "common/stream.h"
+
+#include "graphics/surface.h"
+
+namespace Prince {
+
+class Animation {
+public:
+ Animation();
+ ~Animation();
+ bool loadStream(Common::SeekableReadStream &stream);
+
+ int16 getLoopCount() const;
+ int32 getPhaseCount() const;
+ int32 getFrameCount() const;
+ int16 getBaseX() const;
+ int16 getBaseY() const;
+ int16 getPhaseOffsetX(int phaseIndex) const;
+ int16 getPhaseOffsetY(int phaseIndex) const;
+ int16 getPhaseFrameIndex(int phaseIndex) const;
+ Graphics::Surface *getFrame(int frameIndex);
+ void clear();
+
+private:
+ struct Phase {
+ int16 _phaseOffsetX;
+ int16 _phaseOffsetY;
+ uint16 _phaseToFrameIndex;
+ };
+ struct Frame {
+ bool _isCompressed;
+ uint32 _dataSize;
+ byte *_compressedData;
+ Graphics::Surface *_surface;
+ };
+ Common::Array<Frame> _frameList;
+ Common::Array<Phase> _phaseList;
+ int16 _loopCount;
+ int16 _phaseCount;
+ int32 _frameCount;
+ int16 _baseX;
+ int16 _baseY;
+};
+
+} // End of namespace Prince
+
+#endif
diff --git a/engines/prince/archive.cpp b/engines/prince/archive.cpp
new file mode 100644
index 0000000000..a01f824df8
--- /dev/null
+++ b/engines/prince/archive.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 "prince/archive.h"
+#include "prince/decompress.h"
+
+#include "common/stream.h"
+#include "common/debug.h"
+#include "common/memstream.h"
+
+namespace Prince {
+
+PtcArchive::PtcArchive() : _stream(nullptr) {
+}
+
+PtcArchive::~PtcArchive() {
+ close();
+}
+
+static void decrypt(byte *buffer, uint32 size) {
+ uint32 key = 0xDEADF00D;
+ while (size--) {
+ *buffer++ += key & 0xFF;
+ key ^= 0x2E84299A;
+ key += MKTAG('B', 'L', 'A', 'H');
+ key = ((key & 1) << 31) | (key >> 1);
+ }
+}
+
+bool PtcArchive::open(const Common::String &filename) {
+ _stream = SearchMan.createReadStreamForMember(filename);
+ if (!_stream)
+ return false;
+
+ _stream->readUint32LE(); // magic
+ uint32 fileTableOffset = _stream->readUint32LE() ^ 0x4D4F4B2D; // MOK-
+ uint32 fileTableSize = _stream->readUint32LE() ^ 0x534F4654; // SOFT
+
+ //debug("fileTableOffset : %08X", fileTableOffset);
+ //debug("fileTableSize: %08X", fileTableSize);
+
+ _stream->seek(fileTableOffset);
+
+ byte *fileTable = (byte *)malloc(fileTableSize);
+ byte *fileTableEnd = fileTable + fileTableSize;
+ _stream->read(fileTable, fileTableSize);
+ decrypt(fileTable, fileTableSize);
+
+ for (byte *fileItem = fileTable; fileItem < fileTableEnd; fileItem += 32) {
+ FileEntry item;
+ Common::String name = (const char*)fileItem;
+ item._offset = READ_LE_UINT32(fileItem + 24);
+ item._size = READ_LE_UINT32(fileItem + 28);
+ //debug("%12s %8X %d", name.c_str(), item._offset, item._size);
+ _items[name] = item;
+ }
+
+ free(fileTable);
+
+ return true;
+}
+
+bool PtcArchive::openTranslation(const Common::String &filename) {
+ _stream = SearchMan.createReadStreamForMember(filename);
+ if (!_stream)
+ return false;
+
+ Common::Array<Common::String> translationNames;
+ Common::String translationFileName;
+ const int kTranslationFiles = 5;
+ for (int i = 0; i < kTranslationFiles; i++) {
+ translationFileName = _stream->readLine();
+ translationNames.push_back(translationFileName);
+ }
+ FileEntry item;
+ for (int i = 0; i < kTranslationFiles; i++) {
+ item._offset = _stream->readUint32LE();
+ item._size = _stream->readUint32LE();
+ _items[translationNames[i]] = item;
+ }
+
+ return true;
+}
+
+void PtcArchive::close() {
+ delete _stream;
+ _stream = nullptr;
+ _items.clear();
+}
+
+bool PtcArchive::hasFile(const Common::String &name) const {
+ // TODO: check if path matching should be added
+ return _items.contains(name);
+}
+
+int PtcArchive::listMembers(Common::ArchiveMemberList &list) const {
+ int matches = 0;
+
+ for (FileMap::const_iterator it = _items.begin(); it != _items.end(); ++it) {
+ list.push_back(Common::ArchiveMemberList::value_type(new Common::GenericArchiveMember(it->_key, this)));
+ matches++;
+ }
+
+ return matches;
+}
+
+const Common::ArchiveMemberPtr PtcArchive::getMember(const Common::String &name) const {
+ if (!_items.contains(name)) {
+ Common::ArchiveMemberPtr();
+ }
+ return Common::ArchiveMemberList::value_type(new Common::GenericArchiveMember(name, this));
+}
+
+Common::SeekableReadStream *PtcArchive::createReadStreamForMember(const Common::String &name) const {
+ if (!_items.contains(name)) {
+ return 0;
+ }
+
+ const FileEntry &entryHeader = _items[name];
+
+ if (entryHeader._size < 4)
+ return 0;
+
+ uint32 size = entryHeader._size;
+
+ _stream->seek(entryHeader._offset);
+
+ // This *HAS* to be malloc (not new[]) because MemoryReadStream uses free() to free the memory
+ byte *buffer = (byte *)malloc(size);
+ _stream->read(buffer, size);
+
+ if (READ_BE_UINT32(buffer) == MKTAG('M', 'A', 'S', 'M')) {
+ Decompressor dec;
+ uint32 decompLen = READ_BE_UINT32(buffer + 14);
+ byte *decompData = (byte *)malloc(decompLen);
+ dec.decompress(buffer + 18, decompData, decompLen);
+ free(buffer);
+ size = decompLen;
+ buffer = decompData;
+ }
+
+ //debug("PtcArchive::createReadStreamForMember name %s", name.c_str());
+
+ return new Common::MemoryReadStream(buffer, size, DisposeAfterUse::YES);
+}
+
+} // End of namespace Prince
diff --git a/engines/prince/archive.h b/engines/prince/archive.h
new file mode 100644
index 0000000000..a640b77911
--- /dev/null
+++ b/engines/prince/archive.h
@@ -0,0 +1,62 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef PRINCE_ARCHIVE_H
+#define PRINCE_ARCHIVE_H
+
+#include "common/archive.h"
+#include "common/hashmap.h"
+#include "common/hash-str.h"
+
+namespace Prince {
+
+class PtcArchive : public Common::Archive {
+public:
+ PtcArchive();
+ ~PtcArchive();
+
+ bool open(const Common::String &filename);
+ bool openTranslation(const Common::String &filename);
+ void close();
+ bool isOpen() const { return _stream != 0; }
+
+ // Common::Archive API implementation
+ bool hasFile(const Common::String &name) const;
+ int listMembers(Common::ArchiveMemberList &list) const;
+ const Common::ArchiveMemberPtr getMember(const Common::String &name) const;
+ Common::SeekableReadStream *createReadStreamForMember(const Common::String &name) const;
+
+private:
+ struct FileEntry {
+ uint32 _offset;
+ uint32 _size;
+ };
+
+ Common::SeekableReadStream *_stream;
+
+ typedef Common::HashMap<Common::String, FileEntry, Common::IgnoreCase_Hash, Common::IgnoreCase_EqualTo> FileMap;
+ FileMap _items;
+};
+
+} // End of namespace Prince
+
+#endif
diff --git a/engines/prince/common.h b/engines/prince/common.h
new file mode 100644
index 0000000000..c846f9a751
--- /dev/null
+++ b/engines/prince/common.h
@@ -0,0 +1,45 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef PRINCE_COMMON_H
+#define PRINCE_COMMON_H
+
+namespace Prince {
+
+enum Direction {
+ kDirLD,
+ kDirL,
+ kDirLU,
+ kDirRD,
+ kDirR,
+ kDirRU,
+ kDirUL,
+ kDirU,
+ kDirUR,
+ kDirDL,
+ kDirD,
+ kDirDR
+};
+
+} // End of namespace Prince
+
+#endif
diff --git a/engines/prince/configure.engine b/engines/prince/configure.engine
new file mode 100644
index 0000000000..50740d9f41
--- /dev/null
+++ b/engines/prince/configure.engine
@@ -0,0 +1,3 @@
+# This file is included from the main "configure" script
+# add_engine [name] [desc] [build-by-default] [subengines] [base games] [deps]
+add_engine prince "The Prince and The Coward" no
diff --git a/engines/prince/cursor.cpp b/engines/prince/cursor.cpp
new file mode 100644
index 0000000000..ddcabbd28f
--- /dev/null
+++ b/engines/prince/cursor.cpp
@@ -0,0 +1,54 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "prince/cursor.h"
+
+#include "common/debug.h"
+
+namespace Prince {
+
+Cursor::Cursor() : _surface(nullptr) {
+}
+
+Cursor::~Cursor() {
+ if (_surface != nullptr) {
+ _surface->free();
+ delete _surface;
+ _surface = nullptr;
+ }
+}
+
+bool Cursor::loadStream(Common::SeekableReadStream &stream) {
+ stream.skip(4);
+ uint16 width = stream.readUint16LE();
+ uint16 height = stream.readUint16LE();
+
+ _surface = new Graphics::Surface();
+ _surface->create(width, height, Graphics::PixelFormat::createFormatCLUT8());
+
+ for (int h = 0; h < height; h++) {
+ stream.read(_surface->getBasePtr(0, h), width);
+ }
+ return true;
+}
+
+} // End of namespace Prince
diff --git a/engines/prince/cursor.h b/engines/prince/cursor.h
new file mode 100644
index 0000000000..fb07d01729
--- /dev/null
+++ b/engines/prince/cursor.h
@@ -0,0 +1,46 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef CURSOR_PRINCE_H
+#define CURSOR_PRINCE_H
+
+#include "graphics/surface.h"
+
+#include "common/stream.h"
+
+namespace Prince {
+
+class Cursor {
+public:
+ Cursor();
+ ~Cursor();
+
+ bool loadStream(Common::SeekableReadStream &stream);
+ const Graphics::Surface *getSurface() const { return _surface; }
+
+private:
+ Graphics::Surface *_surface;
+};
+
+} // End of namespace Prince
+
+#endif
diff --git a/engines/prince/curve_values.h b/engines/prince/curve_values.h
new file mode 100644
index 0000000000..d72f11fd36
--- /dev/null
+++ b/engines/prince/curve_values.h
@@ -0,0 +1,45 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+namespace Prince {
+
+const int curveValues[17][4] = {
+ { 32768, 0, 0, 0 },
+ { 25200, 7200, 480, -112 },
+ { 18816, 12544, 1792, -384 },
+ { 13520, 16224, 3744, -720 },
+ { 9216, 18432, 6144, -1024 },
+ { 5808, 19360, 8800, -1200 },
+ { 3200, 19200, 11520, -1152 },
+ { 1296, 18144, 14112, -784 },
+ { 0, 16384, 16384, 0 },
+ { -784, 14112, 18144, 1296 },
+ { -1152, 11520, 19200, 3200 },
+ { -1200, 8800, 19360, 5808 },
+ { -1024, 6144, 18432, 9216 },
+ { -720, 3744, 16224, 13520 },
+ { -384, 1792, 12544, 18816 },
+ { -112, 480, 7200, 25200 },
+ { 0, 0, 0, 32768 }
+};
+
+} // End of namespace Prince
diff --git a/engines/prince/debugger.cpp b/engines/prince/debugger.cpp
new file mode 100644
index 0000000000..fc216e0cfb
--- /dev/null
+++ b/engines/prince/debugger.cpp
@@ -0,0 +1,174 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "prince/debugger.h"
+#include "prince/prince.h"
+#include "prince/flags.h"
+#include "prince/script.h"
+
+namespace Prince {
+
+Debugger::Debugger(PrinceEngine *vm, InterpreterFlags *flags) : GUI::Debugger(), _vm(vm), _locationNr(0), _flags(flags) {
+ registerCmd("continue", WRAP_METHOD(Debugger, cmdExit));
+ registerCmd("level", WRAP_METHOD(Debugger, Cmd_DebugLevel));
+ registerCmd("setflag", WRAP_METHOD(Debugger, Cmd_SetFlag));
+ registerCmd("getflag", WRAP_METHOD(Debugger, Cmd_GetFlag));
+ registerCmd("clearflag", WRAP_METHOD(Debugger, Cmd_ClearFlag));
+ registerCmd("viewflc", WRAP_METHOD(Debugger, Cmd_ViewFlc));
+ registerCmd("initroom", WRAP_METHOD(Debugger, Cmd_InitRoom));
+ registerCmd("changecursor", WRAP_METHOD(Debugger, Cmd_ChangeCursor));
+ registerCmd("additem", WRAP_METHOD(Debugger, Cmd_AddItem));
+}
+
+static int strToInt(const char *s) {
+ if (!*s)
+ // No string at all
+ return 0;
+ else if (toupper(s[strlen(s) - 1]) != 'H')
+ // Standard decimal string
+ return atoi(s);
+
+ // Hexadecimal string
+ uint tmp = 0;
+ int read = sscanf(s, "%xh", &tmp);
+ if (read < 1)
+ error("strToInt failed on string \"%s\"", s);
+ return (int)tmp;
+}
+
+bool Debugger::Cmd_DebugLevel(int argc, const char **argv) {
+ if (argc == 1) {
+ debugPrintf("Debugging is currently set at level %d\n", gDebugLevel);
+ } else { // set level
+ gDebugLevel = atoi(argv[1]);
+ if (0 <= gDebugLevel && gDebugLevel < 11) {
+ debugPrintf("Debug level set to level %d\n", gDebugLevel);
+ } else if (gDebugLevel < 0) {
+ debugPrintf("Debugging is now disabled\n");
+ } else
+ debugPrintf("Not a valid debug level (0 - 10)\n");
+ }
+
+ return true;
+}
+
+/*
+ * This command sets a flag
+ */
+bool Debugger::Cmd_SetFlag(int argc, const char **argv) {
+ // Check for a flag to set
+ if (argc != 3) {
+ debugPrintf("Usage: %s <flag number> <value>\n", argv[0]);
+ return true;
+ }
+
+ int flagNum = strToInt(argv[1]);
+ uint16 value = strToInt(argv[2]);
+ _flags->setFlagValue((Flags::Id)flagNum, value);
+ return true;
+}
+
+/*
+ * This command gets the value of a flag
+ */
+bool Debugger::Cmd_GetFlag(int argc, const char **argv) {
+ // Check for an flag to display
+ if (argc != 2) {
+ debugPrintf("Usage: %s <flag number>\n", argv[0]);
+ return true;
+ }
+
+ int flagNum = strToInt(argv[1]);
+ debugPrintf("Value: %d\n", _flags->getFlagValue((Flags::Id)flagNum));
+ return true;
+}
+
+/*
+ * This command clears a flag
+ */
+bool Debugger::Cmd_ClearFlag(int argc, const char **argv) {
+ // Check for a flag to clear
+ if (argc != 2) {
+ debugPrintf("Usage: %s <flag number>\n", argv[0]);
+ return true;
+ }
+
+ int flagNum = strToInt(argv[1]);
+ _flags->setFlagValue((Flags::Id)flagNum, 0);
+ return true;
+}
+
+/*
+ * This command starts new flc anim
+ */
+bool Debugger::Cmd_ViewFlc(int argc, const char **argv) {
+ // Check for a flag to clear
+ if (argc != 2) {
+ debugPrintf("Usage: %s <anim number>\n", argv[0]);
+ return true;
+ }
+
+ int flagNum = strToInt(argv[1]);
+ _vm->loadAnim(flagNum, false);
+ return true;
+}
+
+bool Debugger::Cmd_InitRoom(int argc, const char **argv) {
+ // Check for a flag to clear
+ if (argc != 2) {
+ debugPrintf("Usage: %s <anim number>\n", argv[0]);
+ return true;
+ }
+
+ _locationNr = strToInt(argv[1]);
+ return true;
+}
+
+bool Debugger::Cmd_ChangeCursor(int argc, const char **argv) {
+ // Check for a flag to clear
+ if (argc != 2) {
+ debugPrintf("Usage: %s <curId>\n", argv[0]);
+ return true;
+ }
+
+ _cursorNr = strToInt(argv[1]);
+
+ return true;
+}
+
+bool Debugger::Cmd_AddItem(int argc, const char **argv) {
+ if (argc != 2) {
+ debugPrintf("Usage: %s <itemId>\n", argv[0]);
+ return true;
+ }
+ if (!strcmp(argv[1], "map")) {
+ _vm->addInv(0, 29, true);
+ _vm->_flags->setFlagValue(Flags::MapaUsable, 1);
+ } else {
+ int itemId = strToInt(argv[1]);
+ _vm->addInv(0, itemId, true);
+ }
+
+ return true;
+}
+
+} // End of namespace Prince
diff --git a/engines/prince/debugger.h b/engines/prince/debugger.h
new file mode 100644
index 0000000000..a4467e63d5
--- /dev/null
+++ b/engines/prince/debugger.h
@@ -0,0 +1,58 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef PRINCE_DEBUGGER_H
+#define PRINCE_DEBUGGER_H
+
+#include "common/scummsys.h"
+#include "gui/debugger.h"
+
+namespace Prince {
+
+class PrinceEngine;
+class InterpreterFlags;
+
+class Debugger : public GUI::Debugger {
+public:
+ Debugger(PrinceEngine *vm, InterpreterFlags *flags);
+ virtual ~Debugger() {} // we need this for __SYMBIAN32__ archaic gcc/UIQ
+
+ uint8 _locationNr;
+ uint8 _cursorNr;
+
+private:
+ bool Cmd_DebugLevel(int argc, const char **argv);
+ bool Cmd_SetFlag(int argc, const char **argv);
+ bool Cmd_GetFlag(int argc, const char **argv);
+ bool Cmd_ClearFlag(int argc, const char **argv);
+ bool Cmd_ViewFlc(int argc, const char **argv);
+ bool Cmd_InitRoom(int argc, const char **argv);
+ bool Cmd_ChangeCursor(int argc, const char **argv);
+ bool Cmd_AddItem(int argc, const char **argv);
+
+ PrinceEngine *_vm;
+ InterpreterFlags *_flags;
+};
+
+} // End of namespace Prince
+
+#endif
diff --git a/engines/prince/decompress.cpp b/engines/prince/decompress.cpp
new file mode 100644
index 0000000000..7fba179541
--- /dev/null
+++ b/engines/prince/decompress.cpp
@@ -0,0 +1,171 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+// John_Doe's implementation
+
+#include "prince/decompress.h"
+
+namespace Prince {
+
+static const uint16 table1[] = {
+ 0x8000, 0x0002,
+ 0x4000, 0x0004,
+ 0x2000, 0x0008,
+ 0x1000, 0x0010,
+ 0x0800, 0x0020,
+ 0x0400, 0x0040,
+ 0x0200, 0x0080,
+ 0x0100, 0x0100,
+ 0x0080, 0x0200,
+ 0x0040, 0x0400
+};
+
+static const uint32 table2[] = {
+ 0x0000F000,
+ 0x0020FC00,
+ 0x00A0FF00,
+ 0x02A0FF80,
+ 0x06A0FFC0,
+ 0x0EA0FFE0,
+ 0x1EA0FFF0,
+ 0x3EA0FFF8
+};
+
+static const uint16 table3[] = {
+ 0x8000, 0x0000,
+ 0x4000, 0x0002,
+ 0x2000, 0x0006,
+ 0x1000, 0x000E,
+ 0x0800, 0x001E,
+ 0x0400, 0x003E,
+ 0x0200, 0x007E,
+ 0x0100, 0x00FE,
+ 0x0080, 0x01FE,
+ 0x0040, 0x03FE,
+ 0x0020, 0x07FE,
+ 0x0010, 0x0FFE,
+ 0x0008, 0x1FFE,
+ 0x0004, 0x3FFE,
+ 0x0002, 0x7FFE,
+ 0x0001, 0xFFFE
+};
+
+void Decompressor::decompress(byte *source, byte *dest, uint32 destSize) {
+ byte *destEnd = dest + destSize;
+ int more;
+ _src = source;
+ _dst = dest;
+ _bitBuffer = 0x80;
+ while (_dst < destEnd) {
+ uint32 ebp;
+ uint16 offset, length;
+ if (getBit()) {
+ if (getBit()) {
+ if (getBit()) {
+ if (getBit()) {
+ if (getBit()) {
+ if (getBit()) {
+ uint32 tableIndex = 0;
+ while (getBit())
+ tableIndex++;
+ length = table3[tableIndex * 2 + 0];
+ do {
+ more = !(length & 0x8000);
+ length = (length << 1) | getBit();
+ } while (more);
+ length += table3[tableIndex * 2 + 1];
+ length++;
+ memcpy(_dst, _src, length);
+ _src += length;
+ _dst += length;
+ }
+ *_dst++ = *_src++;
+ }
+ *_dst++ = *_src++;
+ }
+ *_dst++ = *_src++;
+ }
+ *_dst++ = *_src++;
+ }
+ *_dst++ = *_src++;
+ }
+ if (!getBit()) {
+ if (getBit()) {
+ uint32 tableIndex = getBit();
+ tableIndex = (tableIndex << 1) | getBit();
+ tableIndex = (tableIndex << 1) | getBit();
+ ebp = table2[tableIndex];
+ length = 1;
+ } else {
+ ebp = 0x0000FF00;
+ length = 0;
+ }
+ } else {
+ uint32 tableIndex = 0;
+ while (getBit())
+ tableIndex++;
+ length = table1[tableIndex * 2 + 0];
+ do {
+ more = !(length & 0x8000);
+ length = (length << 1) | getBit();
+ } while (more);
+ length += table1[tableIndex * 2 + 1];
+ tableIndex = getBit();
+ tableIndex = (tableIndex << 1) | getBit();
+ tableIndex = (tableIndex << 1) | getBit();
+ ebp = table2[tableIndex];
+ }
+ offset = ebp & 0xFFFF;
+ do {
+ if (_bitBuffer == 0x80) {
+ if (offset >= 0xFF00) {
+ offset = (offset << 8) | *_src++;
+ }
+ }
+ more = offset & 0x8000;
+ offset = (offset << 1) | getBit();
+ } while (more);
+ offset += (ebp >> 16);
+ length += 2;
+ while (length--) {
+ if (_dst >= destEnd) {
+ return;
+ }
+ *_dst = *(_dst - offset);
+ _dst++;
+ }
+ }
+}
+
+int Decompressor::getBit() {
+ int bit = (_bitBuffer & 0x80) >> 7;
+ _bitBuffer <<= 1;
+ if (_bitBuffer == 0) {
+ _bitBuffer = *_src++;
+ bit = (_bitBuffer & 0x80) >> 7;
+ _bitBuffer <<= 1;
+ _bitBuffer |= 1;
+ }
+ return bit;
+}
+
+} // End of namespace Prince
diff --git a/engines/prince/decompress.h b/engines/prince/decompress.h
new file mode 100644
index 0000000000..ef495db65e
--- /dev/null
+++ b/engines/prince/decompress.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.
+ *
+ */
+
+// John_Doe's implementation
+
+#ifndef PRINCE_DECOMPRESS_H
+#define PRINCE_DECOMPRESS_H
+
+#include "engines/util.h"
+
+namespace Prince {
+
+class Decompressor {
+public:
+ void decompress(byte *source, byte *dest, uint32 destSize);
+protected:
+ byte *_src, *_dst;
+ byte _bitBuffer;
+ int _bitsLeft;
+ int getBit();
+};
+
+} // End of namespace Prince
+
+#endif
diff --git a/engines/prince/detection.cpp b/engines/prince/detection.cpp
new file mode 100644
index 0000000000..3fe7993fdb
--- /dev/null
+++ b/engines/prince/detection.cpp
@@ -0,0 +1,75 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "prince/detection.h"
+
+namespace Prince {
+
+int PrinceEngine::getGameType() const {
+ return _gameDescription->gameType;
+}
+
+const char *PrinceEngine::getGameId() const {
+ return _gameDescription->desc.gameid;
+}
+
+uint32 PrinceEngine::getFeatures() const {
+ return _gameDescription->desc.flags;
+}
+
+Common::Language PrinceEngine::getLanguage() const {
+ return _gameDescription->desc.language;
+}
+
+bool PrinceMetaEngine::createInstance(OSystem *syst, Engine **engine, const ADGameDescription *desc) const {
+ using namespace Prince;
+ const PrinceGameDescription *gd = (const PrinceGameDescription *)desc;
+ if (gd) {
+ *engine = new PrinceEngine(syst, gd);
+ }
+ return gd != 0;
+}
+
+bool PrinceMetaEngine::hasFeature(MetaEngineFeature f) const {
+ return
+ (f == kSupportsDeleteSave) ||
+ (f == kSavesSupportMetaInfo) ||
+ (f == kSavesSupportThumbnail) ||
+ (f == kSavesSupportCreationDate) ||
+ (f == kSupportsListSaves) ||
+ (f == kSupportsLoadingDuringStartup);
+}
+
+bool Prince::PrinceEngine::hasFeature(EngineFeature f) const {
+ return
+ (f == kSupportsLoadingDuringRuntime) ||
+ (f == kSupportsSavingDuringRuntime) ||
+ (f == kSupportsRTL);
+}
+
+} // End of namespace Prince
+
+#if PLUGIN_ENABLED_DYNAMIC(PRINCE)
+REGISTER_PLUGIN_DYNAMIC(PRINCE, PLUGIN_TYPE_ENGINE, Prince::PrinceMetaEngine);
+#else
+REGISTER_PLUGIN_STATIC(PRINCE, PLUGIN_TYPE_ENGINE, Prince::PrinceMetaEngine);
+#endif
diff --git a/engines/prince/detection.h b/engines/prince/detection.h
new file mode 100644
index 0000000000..7e5bdd6b7b
--- /dev/null
+++ b/engines/prince/detection.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 PRINCE_DETECTION_H
+#define PRINCE_DETECTION_H
+
+#include "prince/prince.h"
+#include "engines/advancedDetector.h"
+
+namespace Prince {
+
+enum PrinceGameType {
+ kPrinceDataUNK,
+ kPrinceDataDE,
+ kPrinceDataPL
+};
+
+struct PrinceGameDescription {
+ ADGameDescription desc;
+ PrinceGameType gameType;
+};
+
+static const PlainGameDescriptor princeGames[] = {
+ {"prince", "Prince Game"},
+ {0, 0}
+};
+
+static const PrinceGameDescription gameDescriptions[] = {
+ {
+ {
+ "prince",
+ "Galador",
+ AD_ENTRY1s("databank.ptc", "5fa03833177331214ec1354761b1d2ee", 3565031),
+ Common::DE_DEU,
+ Common::kPlatformWindows,
+ ADGF_TESTING,
+ GUIO1(GUIO_NONE)
+ },
+ kPrinceDataDE
+ },
+ {
+ {
+ "prince",
+ "Ksiaze i Tchorz",
+ AD_ENTRY1s("databank.ptc", "48ec9806bda9d152acbea8ce31c93c49", 3435298),
+ Common::PL_POL,
+ Common::kPlatformWindows,
+ ADGF_TESTING,
+ GUIO1(GUIO_NONE)
+ },
+ kPrinceDataPL
+ },
+ {
+ {
+ "prince",
+ "The Prince and the Coward",
+ AD_ENTRY1s("databank.ptc", "5fa03833177331214ec1354761b1d2ee", 3565031),
+ Common::EN_ANY,
+ Common::kPlatformWindows,
+ ADGF_TESTING,
+ GUIO1(GUIO_NONE)
+ },
+ kPrinceDataDE
+ },
+ {
+ {
+ "prince",
+ "The Prince and the Coward",
+ AD_ENTRY1s("databank.ptc", "48ec9806bda9d152acbea8ce31c93c49", 3435298),
+ Common::EN_ANY,
+ Common::kPlatformWindows,
+ ADGF_TESTING,
+ GUIO1(GUIO_NONE)
+ },
+ kPrinceDataPL
+ },
+ { AD_TABLE_END_MARKER, kPrinceDataUNK }
+};
+
+const static char *directoryGlobs[] = {
+ "all",
+ 0
+};
+
+class PrinceMetaEngine : public AdvancedMetaEngine {
+public:
+ PrinceMetaEngine() : AdvancedMetaEngine(Prince::gameDescriptions, sizeof(Prince::PrinceGameDescription), princeGames) {
+ _singleid = "prince";
+ _maxScanDepth = 2;
+ _directoryGlobs = directoryGlobs;
+ }
+
+ virtual const char *getName() const {
+ return "Prince Engine";
+ }
+
+ virtual const char *getOriginalCopyright() const {
+ return "The Prince and the Coward (C) 1996-97 Metropolis";
+ }
+
+ virtual bool createInstance(OSystem *syst, Engine **engine, const ADGameDescription *desc) const;
+ virtual bool hasFeature(MetaEngineFeature f) const;
+ virtual int getMaximumSaveSlot() const;
+ virtual SaveStateList listSaves(const char *target) const;
+ SaveStateDescriptor querySaveMetaInfos(const char *target, int slot) const;
+ virtual void removeSaveState(const char *target, int slot) const;
+};
+
+} // End of namespace Prince
+
+#endif
diff --git a/engines/prince/flags.cpp b/engines/prince/flags.cpp
new file mode 100644
index 0000000000..f1a05bd4df
--- /dev/null
+++ b/engines/prince/flags.cpp
@@ -0,0 +1,420 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "prince/flags.h"
+#include "prince/script.h"
+
+namespace Prince {
+
+const char *Flags::getFlagName(uint16 flagId) {
+ FlagDebug *flagd = nullptr;
+ flagd = (FlagDebug *)bsearch(&flagId, _flagNames, kFlagDebugAmount, sizeof(FlagDebug), Flags::compareFlagDebug);
+ if (flagd != nullptr) {
+ return flagd->flagName;
+ } else {
+ return "unknown_flag";
+ }
+}
+
+int Flags::compareFlagDebug(const void *a, const void *b) {
+ const uint32 *flagId = (const uint32 *)a;
+ const FlagDebug *entry = (const FlagDebug *)b;
+ if (*flagId < (uint32)entry->id) {
+ return -1;
+ } else if (*flagId > (uint32)entry->id) {
+ return 1;
+ }
+ return 0;
+}
+
+const Flags::FlagDebug Flags::_flagNames[Flags::kFlagDebugAmount] = {
+ { Flags::FLAGA1, "FLAGA1" },
+ { Flags::FLAGA2, "FLAGA2" },
+ { Flags::FLAGA3, "FLAGA3" },
+ { Flags::DESTX, "DESTX" },
+ { Flags::DESTY, "DESTY" },
+ { Flags::DESTD, "DESTD" },
+ { Flags::DwarfDone, "DwarfDone" },
+ { Flags::GRABARZCOUNTER, "GRABARZCOUNTER" },
+ { Flags::KIERUNEK, "KIERUNEK" },
+ { Flags::BACKFLAG1, "BACKFLAG1" },
+ { Flags::BACKFLAG2, "BACKFLAG2" },
+ { Flags::BACKFLAG3, "BACKFLAG3" },
+ { Flags::BACKFLAG4, "BACKFLAG4" },
+ { Flags::MACROFLAG1, "MACROFLAG1" },
+ { Flags::MACROFLAG2, "MACROFLAG2" },
+ { Flags::MACROFLAG3, "MACROFLAG3" },
+ { Flags::HEROLDDONE, "HEROLDDONE" },
+ { Flags::BRIDGESET, "BRIDGESET" },
+ { Flags::U_BT_1, "U_BT_1" },
+ { Flags::U_BT_2, "U_BT_2" },
+ { Flags::U_BT_3, "U_BT_3" },
+ { Flags::U_BT_4, "U_BT_4" },
+ { Flags::U_BT_5, "U_BT_5" },
+ { Flags::U_BT_6, "U_BT_6" },
+ { Flags::U_BT_7, "U_BT_7" },
+ { Flags::U_BT_8, "U_BT_8" },
+ { Flags::U_BT_9, "U_BT_9" },
+ { Flags::U_BT_COUNTER, "U_BT_COUNTER" },
+ { Flags::ARIVALDALIVE, "ARIVALDALIVE" },
+ { Flags::TALKCHAR1, "TALKCHAR1" },
+ { Flags::TalkType1, "TalkType1" },
+ { Flags::TALKROUT1, "TALKROUT1" },
+ { Flags::TALKROUT2, "TALKROUT2" },
+ { Flags::TALKROUT3, "TALKROUT3" },
+ { Flags::TALKROUT4, "TALKROUT4" },
+ { Flags::TALKANIM1, "TALKANIM1" },
+ { Flags::TALKANIM2, "TALKANIM2" },
+ { Flags::TALKCOLOR1, "TALKCOLOR1" },
+ { Flags::TALKCOLOR2, "TALKCOLOR2" },
+ { Flags::KapciuchTaken, "KapciuchTaken" },
+ { Flags::CurrentBeggarA, "CurrentBeggarA" },
+ { Flags::TempKapc, "TempKapc" },
+ { Flags::HomTaken, "HomTaken" },
+ { Flags::WizardTalk, "WizardTalk" },
+ { Flags::SunlordTalk, "SunlordTalk" },
+ { Flags::HermitTalk, "HermitTalk" },
+ { Flags::RunyMode, "RunyMode" },
+ { Flags::FatMerchantTalk, "FatMerchantTalk" },
+ { Flags::HotDogTalk, "HotDogTalk" },
+ { Flags::ThiefTalk, "ThiefTalk" },
+ { Flags::BeggarTalk, "BeggarTalk" },
+ { Flags::MonkTalk, "MonkTalk" },
+ { Flags::BardTalk, "BardTalk" },
+ { Flags::BarmanTalk, "BarmanTalk" },
+ { Flags::LeftPlayerTalk, "LeftPlayerTalk" },
+ { Flags::OczySowy, "OczySowy" },
+ { Flags::CzachySpeed1, "CzachySpeed1" },
+ { Flags::CzachySpeed2, "CzachySpeed2" },
+ { Flags::CzachySpeed3, "CzachySpeed3" },
+ { Flags::CzachySlowDown1, "CzachySlowDown1" },
+ { Flags::CzachySlowDown2, "CzachySlowDown2" },
+ { Flags::CzachySlowDown3, "CzachySlowDown3" },
+ { Flags::FjordDane, "FjordDane" },
+ { Flags::GKopany1, "GKopany1" },
+ { Flags::GKopany2, "GKopany2" },
+ { Flags::GKopany3, "GKopany3" },
+ { Flags::GKopany4, "GKopany4" },
+ { Flags::KnowGodWord, "KnowGodWord" },
+ { Flags::TALKROUT21, "TALKROUT21" },
+ { Flags::TALKROUT22, "TALKROUT22" },
+ { Flags::TALKROUT23, "TALKROUT23" },
+ { Flags::TALKROUT24, "TALKROUT24" },
+ { Flags::TalkType2, "TalkType2" },
+ { Flags::GrabarzTalk, "GrabarzTalk" },
+ { Flags::LastTalker, "LastTalker" },
+ { Flags::MapaPustelniaEnabled, "MapaPustelniaEnabled" },
+ { Flags::MapaTempleEnabled, "MapaTempleEnabled" },
+ { Flags::MapaFjordEnabled, "MapaFjordEnabled" },
+ { Flags::MapaSilmanionaEnabled, "MapaSilmanionaEnabled" },
+ { Flags::MapaKurhanEnabled, "MapaKurhanEnabled" },
+ { Flags::MapaDragonEnabled, "MapaDragonEnabled" },
+ { Flags::MapaMillEnabled, "MapaMillEnabled" },
+ { Flags::DwarfRunning, "DwarfRunning" },
+ { Flags::DwarfTalk, "DwarfTalk" },
+ { Flags::CurseLift, "CurseLift" },
+ { Flags::KosciSwapped, "KosciSwapped" },
+ { Flags::BookStolen, "BookStolen" },
+ { Flags::MapaUsable, "MapaUsable" },
+ { Flags::FjordBoss, "FjordBoss" },
+ { Flags::FjordHotDog, "FjordHotDog" },
+ { Flags::FjordLewy, "FjordLewy" },
+ { Flags::FjordPrawy, "FjordPrawy" },
+ { Flags::TalkArivald, "TalkArivald" },
+ { Flags::ShootDone, "ShootDone" },
+ { Flags::ShootRunning, "ShootRunning" },
+ { Flags::ShootKnow, "ShootKnow" },
+ { Flags::MirrorKnow, "MirrorKnow" },
+ { Flags::Gar1stTime, "Gar1stTime" },
+ { Flags::KosciTaken, "KosciTaken" },
+ { Flags::ArivGotSpell, "ArivGotSpell" },
+ { Flags::BookGiven, "BookGiven" },
+ { Flags::Wywieszka, "Wywieszka" },
+ { Flags::TalkSheila, "TalkSheila" },
+ { Flags::TalkSheila2, "TalkSheila2" },
+ { Flags::BackHuman, "BackHuman" },
+ { Flags::SkarbiecOpen, "SkarbiecOpen" },
+ { Flags::LustroTaken, "LustroTaken" },
+ { Flags::GargoyleHom, "GargoyleHom" },
+ { Flags::GargoyleBroken, "GargoyleBroken" },
+ { Flags::FjordDzien, "FjordDzien" },
+ { Flags::GargoyleHom2, "GargoyleHom2" },
+ { Flags::RunMonstersRunning, "RunMonstersRunning" },
+ { Flags::FoundPaperInCoffin, "FoundPaperInCoffin" },
+ { Flags::KnowSunlord, "KnowSunlord" },
+ { Flags::KnowSunlordTalk, "KnowSunlordTalk" },
+ { Flags::ArivaldCzyta, "ArivaldCzyta" },
+ { Flags::TelepX, "TelepX" },
+ { Flags::TelepY, "TelepY" },
+ { Flags::TelepDir, "TelepDir" },
+ { Flags::TelepRoom, "TelepRoom" },
+ { Flags::ListStolen, "ListStolen" },
+ { Flags::WifeInDoor, "WifeInDoor" },
+ { Flags::TalkWifeFlag, "TalkWifeFlag" },
+ { Flags::LetterGiven, "LetterGiven" },
+ { Flags::LutniaTaken, "LutniaTaken" },
+ { Flags::BardHomeOpen, "BardHomeOpen" },
+ { Flags::FjordNoMonsters, "FjordNoMonsters" },
+ { Flags::ShandriaWallTalking, "ShandriaWallTalking" },
+ { Flags::ShandriaWallCounter, "ShandriaWallCounter" },
+ { Flags::ShandriaWallDone, "ShandriaWallDone" },
+ { Flags::FutureDone, "FutureDone" },
+ { Flags::TalkButch, "TalkButch" },
+ { Flags::GotSzalik, "GotSzalik" },
+ { Flags::GotCzosnek, "GotCzosnek" },
+ { Flags::BearDone, "BearDone" },
+ { Flags::NekrVisited, "NekrVisited" },
+ { Flags::SunRiddle, "SunRiddle" },
+ { Flags::PtaszekAway, "PtaszekAway" },
+ { Flags::KotGadanie, "KotGadanie" },
+ { Flags::SzlafmycaTaken, "SzlafmycaTaken" },
+ { Flags::BabkaTalk, "BabkaTalk" },
+ { Flags::SellerTalk, "SellerTalk" },
+ { Flags::CzosnekDone, "CzosnekDone" },
+ { Flags::PriestCounter, "PriestCounter" },
+ { Flags::PriestGest1, "PriestGest1" },
+ { Flags::PriestGest2, "PriestGest2" },
+ { Flags::PriestGest3, "PriestGest3" },
+ { Flags::PriestGest4, "PriestGest4" },
+ { Flags::PriestAnim, "PriestAnim" },
+ { Flags::HolyWaterTaken, "HolyWaterTaken" },
+ { Flags::AxeTaken, "AxeTaken" },
+ { Flags::BadylTaken1, "BadylTaken1" },
+ { Flags::BadylTaken2, "BadylTaken2" },
+ { Flags::BadylSharpened, "BadylSharpened" },
+ { Flags::PorwanieSmoka, "PorwanieSmoka" },
+ { Flags::ShopReOpen, "ShopReOpen" },
+ { Flags::LuskaShown, "LuskaShown" },
+ { Flags::CudKnow, "CudKnow" },
+ { Flags::VampireDead, "VampireDead" },
+ { Flags::MapaVisible1, "MapaVisible1" },
+ { Flags::MapaVisible2, "MapaVisible2" },
+ { Flags::MapaVisible3, "MapaVisible3" },
+ { Flags::MapaVisible4, "MapaVisible4" },
+ { Flags::MapaVisible5, "MapaVisible5" },
+ { Flags::MapaVisible6, "MapaVisible6" },
+ { Flags::MapaVisible7, "MapaVisible7" },
+ { Flags::MapaVisible8, "MapaVisible8" },
+ { Flags::MapaVisible9, "MapaVisible9" },
+ { Flags::MapaX, "MapaX" },
+ { Flags::MapaY, "MapaY" },
+ { Flags::MapaD, "MapaD" },
+ { Flags::OldMapaX, "OldMapaX" },
+ { Flags::OldMapaY, "OldMapaY" },
+ { Flags::OldMapaD, "OldMapaD" },
+ { Flags::MovingBack, "MovingBack" },
+ { Flags::MapaCount, "MapaCount" },
+ { Flags::Pustelnia1st, "Pustelnia1st" },
+ { Flags::CzarnePole1st, "CzarnePole1st" },
+ { Flags::TalkArivNum, "TalkArivNum" },
+ { Flags::Pfui, "Pfui" },
+ { Flags::MapaSunlordEnabled, "MapaSunlordEnabled" },
+ { Flags::WebDone, "WebDone" },
+ { Flags::DragonDone, "DragonDone" },
+ { Flags::KanPlay, "KanPlay" },
+ { Flags::OldKanPlay, "OldKanPlay" },
+ { Flags::LapkiWait, "LapkiWait" },
+ { Flags::WebNoCheck, "WebNoCheck" },
+ { Flags::Perfumeria, "Perfumeria" },
+ { Flags::SmokNoCheck, "SmokNoCheck" },
+ { Flags::IluzjaBroken, "IluzjaBroken" },
+ { Flags::IluzjaWorking, "IluzjaWorking" },
+ { Flags::IluzjaCounter, "IluzjaCounter" },
+ { Flags::KurhanOpen1, "KurhanOpen1" },
+ { Flags::KastetTaken, "KastetTaken" },
+ { Flags::KastetDown, "KastetDown" },
+ { Flags::KurhanDone, "KurhanDone" },
+ { Flags::SkelCounter, "SkelCounter" },
+ { Flags::SkelDial1, "SkelDial1" },
+ { Flags::SkelDial2, "SkelDial2" },
+ { Flags::SkelDial3, "SkelDial3" },
+ { Flags::SkelDial4, "SkelDial4" },
+ { Flags::SameTalker, "SameTalker" },
+ { Flags::RunMonstersText, "RunMonstersText" },
+ { Flags::PiwnicaChecked, "PiwnicaChecked" },
+ { Flags::DragonTalked, "DragonTalked" },
+ { Flags::ToldAboutBook, "ToldAboutBook" },
+ { Flags::SilmanionaDone, "SilmanionaDone" },
+ { Flags::ToldBookCount, "ToldBookCount" },
+ { Flags::SmrodNoCheck, "SmrodNoCheck" },
+ { Flags::RopeTaken, "RopeTaken" },
+ { Flags::RopeTime, "RopeTime" },
+ { Flags::LaskaFree, "LaskaFree" },
+ { Flags::ShanSmokTalked, "ShanSmokTalked" },
+ { Flags::SwordTaken, "SwordTaken" },
+ { Flags::Mill1st, "Mill1st" },
+ { Flags::SawRat, "SawRat" },
+ { Flags::KnowRat, "KnowRat" },
+ { Flags::DziuraTimer, "DziuraTimer" },
+ { Flags::LaskaInside, "LaskaInside" },
+ { Flags::HoleBig, "HoleBig" },
+ { Flags::EnableWiedzmin, "EnableWiedzmin" },
+ { Flags::EnableTrucizna, "EnableTrucizna" },
+ { Flags::KnowPoison, "KnowPoison" },
+ { Flags::KufelTaken, "KufelTaken" },
+ { Flags::BojkaEnabled, "BojkaEnabled" },
+ { Flags::BitwaNot1st, "BitwaNot1st" },
+ { Flags::BojkaTimer, "BojkaTimer" },
+ { Flags::BojkaGirl, "BojkaGirl" },
+ { Flags::Look1st, "Look1st" },
+ { Flags::RatTaken, "RatTaken" },
+ { Flags::LaskaTalkedGr, "LaskaTalkedGr" },
+ { Flags::RatusGivus, "RatusGivus" },
+ { Flags::MamObole, "MamObole" },
+ { Flags::Speed1st, "Speed1st" },
+ { Flags::SpeedTimer, "SpeedTimer" },
+ { Flags::ProveIt, "ProveIt" },
+ { Flags::Proven, "Proven" },
+ { Flags::ShowWoalka, "ShowWoalka" },
+ { Flags::PoisonTaken, "PoisonTaken" },
+ { Flags::HellOpened, "HellOpened" },
+ { Flags::HellNoCheck, "HellNoCheck" },
+ { Flags::TalAn1, "TalAn1" },
+ { Flags::TalAn2, "TalAn2" },
+ { Flags::TalAn3, "TalAn3" },
+ { Flags::TalkDevilGuard, "TalkDevilGuard" },
+ { Flags::Sword1st, "Sword1st" },
+ { Flags::IluzjaNoCheck, "IluzjaNoCheck" },
+ { Flags::RozdzielniaNumber, "RozdzielniaNumber" },
+ { Flags::JailChecked, "JailChecked" },
+ { Flags::JailTalked, "JailTalked" },
+ { Flags::TrickFailed, "TrickFailed" },
+ { Flags::WegielVisible, "WegielVisible" },
+ { Flags::WegielTimer1, "WegielTimer1" },
+ { Flags::RandomSample, "RandomSample" },
+ { Flags::RandomSampleTimer, "RandomSampleTimer" },
+ { Flags::SampleTimer, "SampleTimer" },
+ { Flags::ZonaSample, "ZonaSample" },
+ { Flags::HoleTryAgain, "HoleTryAgain" },
+ { Flags::TeleportTimer, "TeleportTimer" },
+ { Flags::RozLezy, "RozLezy" },
+ { Flags::UdkoTimer, "UdkoTimer" },
+ { Flags::ZaworZatkany, "ZaworZatkany" },
+ { Flags::ZaworOpened, "ZaworOpened" },
+ { Flags::DoorExploded, "DoorExploded" },
+ { Flags::SkoraTaken, "SkoraTaken" },
+ { Flags::CiezkieByl, "CiezkieByl" },
+ { Flags::MamWegiel, "MamWegiel" },
+ { Flags::SwiecaAway, "SwiecaAway" },
+ { Flags::ITSAVE, "ITSAVE" },
+ { Flags::RozpadlSie, "RozpadlSie" },
+ { Flags::WegielFullTimer, "WegielFullTimer" },
+ { Flags::WegielDown, "WegielDown" },
+ { Flags::WegielDownTimer, "WegielDownTimer" },
+ { Flags::PaliSie, "PaliSie" },
+ { Flags::DiabGuardTalked, "DiabGuardTalked" },
+ { Flags::GuardsNoCheck, "GuardsNoCheck" },
+ { Flags::TalkedPowloka, "TalkedPowloka" },
+ { Flags::JailOpen, "JailOpen" },
+ { Flags::PrzytulTimer, "PrzytulTimer" },
+ { Flags::JailDone, "JailDone" },
+ { Flags::MamMonety, "MamMonety" },
+ { Flags::LotTimer, "LotTimer" },
+ { Flags::LotObj, "LotObj" },
+ { Flags::PtakTimer, "PtakTimer" },
+ { Flags::BookTimer, "BookTimer" },
+ { Flags::BookGiba, "BookGiba" },
+ { Flags::PtakLata, "PtakLata" },
+ { Flags::Podej, "Podej" },
+ { Flags::GotHint, "GotHint" },
+ { Flags::LawaLeci, "LawaLeci" },
+ { Flags::PowerKlik, "PowerKlik" },
+ { Flags::LucekBad, "LucekBad" },
+ { Flags::LucekBad1st, "LucekBad1st" },
+ { Flags::IntroDial1, "IntroDial1" },
+ { Flags::IntroDial2, "IntroDial2" },
+ { Flags::ItsOutro, "ItsOutro" },
+ { Flags::KamienComment, "KamienComment" },
+ { Flags::KamienSkip, "KamienSkip" },
+ { Flags::TesterFlag, "TesterFlag" },
+ { Flags::RememberLine, "RememberLine" },
+ { Flags::OpisLapek, "OpisLapek" },
+ { Flags::TalWait, "TalWait" },
+ { Flags::OpisKamienia, "OpisKamienia" },
+ { Flags::JumpBox, "JumpBox" },
+ { Flags::JumpBox1, "JumpBox1" },
+ { Flags::JumpBox2, "JumpBox2" },
+ { Flags::JumpBox3, "JumpBox3" },
+ { Flags::SpecPiesek, "SpecPiesek" },
+ { Flags::SpecPiesekCount, "SpecPiesekCount" },
+ { Flags::SpecPiesekGadanie, "SpecPiesekGadanie" },
+ { Flags::ZnikaFlag, "ZnikaFlag" },
+ { Flags::ZnikaTimer, "ZnikaTimer" },
+ { Flags::SowaTimer, "SowaTimer" },
+ { Flags::MamrotanieOff, "MamrotanieOff" },
+ { Flags::CURRMOB, "CURRMOB" },
+ { Flags::KOLOR, "KOLOR" },
+ { Flags::MBFLAG, "MBFLAG" },
+ { Flags::MXFLAG, "MXFLAG" },
+ { Flags::MYFLAG, "MYFLAG" },
+ { Flags::SCROLLTYPE, "SCROLLTYPE" },
+ { Flags::SCROLLVALUE, "SCROLLVALUE" },
+ { Flags::SCROLLVALUE2, "SCROLLVALUE2" },
+ { Flags::TALKEXITCODE, "TALKEXITCODE" },
+ { Flags::SPECROUTFLAG1, "SPECROUTFLAG1" },
+ { Flags::SPECROUTFLAG2, "SPECROUTFLAG2" },
+ { Flags::SPECROUTFLAG3, "SPECROUTFLAG3" },
+ { Flags::TALKFLAGCODE, "TALKFLAGCODE" },
+ { Flags::CURRROOM, "CURRROOM" },
+ { Flags::Talker1Init, "Talker1Init" },
+ { Flags::Talker2Init, "Talker2Init" },
+ { Flags::RESTOREROOM, "RESTOREROOM" },
+ { Flags::INVALLOWED, "INVALLOWED" },
+ { Flags::BOXSEL, "BOXSEL" },
+ { Flags::CURSEBLINK, "CURSEBLINK" },
+ { Flags::EXACTMOVE, "EXACTMOVE" },
+ { Flags::MOVEDESTX, "MOVEDESTX" },
+ { Flags::MOVEDESTY, "MOVEDESTY" },
+ { Flags::NOANTIALIAS, "NOANTIALIAS" },
+ { Flags::ESCAPED, "ESCAPED" },
+ { Flags::ALLOW1OPTION, "ALLOW1OPTION" },
+ { Flags::VOICE_H_LINE, "VOICE_H_LINE" },
+ { Flags::VOICE_A_LINE, "VOICE_A_LINE" },
+ { Flags::VOICE_B_LINE, "VOICE_B_LINE" },
+ { Flags::VOICE_C_LINE, "VOICE_C_LINE" },
+ { Flags::NOHEROATALL, "NOHEROATALL" },
+ { Flags::MOUSEENABLED, "MOUSEENABLED" },
+ { Flags::DIALINES, "DIALINES" },
+ { Flags::SHANWALK, "SHANWALK" },
+ { Flags::SHANDOG, "SHANDOG" },
+ { Flags::GETACTIONBACK, "GETACTIONBACK" },
+ { Flags::GETACTIONDATA, "GETACTIONDATA" },
+ { Flags::GETACTION, "GETACTION" },
+ { Flags::HEROFAST, "HEROFAST" },
+ { Flags::SELITEM, "SELITEM" },
+ { Flags::LMOUSE, "LMOUSE" },
+ { Flags::MINMX, "MINMX" },
+ { Flags::MAXMX, "MAXMX" },
+ { Flags::MINMY, "MINMY" },
+ { Flags::MAXMY, "MAXMY" },
+ { Flags::TORX1, "TORX1" },
+ { Flags::TORY1, "TORY1" },
+ { Flags::TORX2, "TORX2" },
+ { Flags::TORY2, "TORY2" },
+ { Flags::POWER, "POWER" },
+ { Flags::POWERENABLED, "POWERENABLED" },
+ { Flags::FLCRESTORE, "FLCRESTORE" },
+ { Flags::NOCLSTEXT, "NOCLSTEXT" },
+ { Flags::ESCAPED2, "ESCAPED2" },
+};
+
+} // End of namespace Prince
diff --git a/engines/prince/flags.h b/engines/prince/flags.h
new file mode 100644
index 0000000000..8337f82a95
--- /dev/null
+++ b/engines/prince/flags.h
@@ -0,0 +1,421 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public 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 PRINCE_FLAGS_H
+#define PRINCE_FLAGS_H
+
+#include "common/scummsys.h"
+
+namespace Prince {
+
+class Flags {
+public:
+ static int compareFlagDebug(const void *a, const void *b);
+ static const char *getFlagName(uint16 flagId);
+
+ enum Id {
+ FLAGA1 = 0x8000,
+ FLAGA2 = 0x8002,
+ FLAGA3 = 0x8004,
+ DESTX = 0x8006,
+ DESTY = 0x8008,
+ DESTD = 0x800A,
+ DwarfDone = 0x800C,
+ GRABARZCOUNTER = 0x800E,
+ KIERUNEK = 0x8010,
+ BACKFLAG1 = 0x8012,
+ BACKFLAG2 = 0x8014,
+ BACKFLAG3 = 0x8016,
+ BACKFLAG4 = 0x8018,
+ MACROFLAG1 = 0x801A,
+ MACROFLAG2 = 0x801C,
+ MACROFLAG3 = 0x801E,
+ HEROLDDONE = 0x8020,
+ BRIDGESET = 0x8022,
+ U_BT_1 = 0x8024,
+ U_BT_2 = 0x8026,
+ U_BT_3 = 0x8028,
+ U_BT_4 = 0x802A,
+ U_BT_5 = 0x802C,
+ U_BT_6 = 0x802E,
+ U_BT_7 = 0x8030,
+ U_BT_8 = 0x8032,
+ U_BT_9 = 0x8034,
+ U_BT_COUNTER = 0x8036,
+ ARIVALDALIVE = 0x8038,
+ TALKCHAR1 = 0x803A,
+ TalkType1 = 0x803C,
+ TALKROUT1 = 0x803E,
+ TALKROUT2 = 0x8042,
+ TALKROUT3 = 0x8046,
+ TALKROUT4 = 0x804A,
+ TALKANIM1 = 0x804E,
+ TALKANIM2 = 0x8050,
+ TALKCOLOR1 = 0x8052,
+ TALKCOLOR2 = 0x8054,
+ KapciuchTaken = 0x8056,
+ CurrentBeggarA = 0x8058,
+ TempKapc = 0x805A,
+ HomTaken = 0x805C,
+ WizardTalk = 0x805E,
+ SunlordTalk = 0x8060,
+ HermitTalk = 0x8062,
+ RunyMode = 0x8064,
+ FatMerchantTalk = 0x8066,
+ HotDogTalk = 0x8068,
+ ThiefTalk = 0x806A,
+ BeggarTalk = 0x806C,
+ // DwarfTalk = 0x806E, // Redefinition
+ MonkTalk = 0x8070,
+ BardTalk = 0x8072,
+ BarmanTalk = 0x8074,
+ LeftPlayerTalk = 0x8076,
+ OczySowy = 0x8078,
+ CzachySpeed1 = 0x807A,
+ CzachySpeed2 = 0x807C,
+ CzachySpeed3 = 0x807E,
+ CzachySlowDown1 = 0x8080,
+ CzachySlowDown2 = 0x8082,
+ CzachySlowDown3 = 0x8084,
+ FjordDane = 0x8086,
+ GKopany1 = 0x8088,
+ GKopany2 = 0x808A,
+ GKopany3 = 0x808C,
+ GKopany4 = 0x808E,
+ KnowGodWord = 0x8090,
+ TALKROUT21 = 0x8092,
+ TALKROUT22 = 0x8096,
+ TALKROUT23 = 0x809A,
+ TALKROUT24 = 0x809E,
+ TalkType2 = 0x80A2,
+ GrabarzTalk = 0x80A4,
+ LastTalker = 0x80A6,
+ MapaPustelniaEnabled = 0x80A8,
+ MapaTempleEnabled = 0x80AA,
+ MapaFjordEnabled = 0x80AC,
+ MapaSilmanionaEnabled = 0x80AE,
+ MapaKurhanEnabled = 0x80B0,
+ MapaDragonEnabled = 0x80B2,
+ MapaMillEnabled = 0x80B4,
+ DwarfRunning = 0x80B6,
+ DwarfTalk = 0x80B8,
+ CurseLift = 0x80BA,
+ KosciSwapped = 0x80BC,
+ BookStolen = 0x80BE,
+ MapaUsable = 0x80C0,
+ FjordBoss = 0x80C2,
+ FjordHotDog = 0x80C4,
+ FjordLewy = 0x80C6,
+ FjordPrawy = 0x80C8,
+ TalkArivald = 0x80CA,
+ ShootDone = 0x80CC,
+ ShootRunning = 0x80CE,
+ ShootKnow = 0x80D0,
+ MirrorKnow = 0x80D2,
+ Gar1stTime = 0x80D4,
+ KosciTaken = 0x80D6,
+ ArivGotSpell = 0x80D8,
+ BookGiven = 0x80DA,
+ Wywieszka = 0x80DC,
+ TalkSheila = 0x80DE,
+ TalkSheila2 = 0x80E0,
+ BackHuman = 0x80E2,
+ SkarbiecOpen = 0x80E4,
+ LustroTaken = 0x80E6,
+ GargoyleHom = 0x80E8,
+ GargoyleBroken = 0x80EA,
+ FjordDzien = 0x80EC,
+ GargoyleHom2 = 0x80EE,
+ RunMonstersRunning = 0x80F0,
+ FoundPaperInCoffin = 0x80F2,
+ KnowSunlord = 0x80F4,
+ KnowSunlordTalk = 0x80F6,
+ ArivaldCzyta = 0x80F8,
+ TelepX = 0x80FA,
+ TelepY = 0x80FC,
+ TelepDir = 0x80FE,
+ TelepRoom = 0x8100,
+ ListStolen = 0x8102,
+ WifeInDoor = 0x8104,
+ TalkWifeFlag = 0x8106,
+ LetterGiven = 0x8108,
+ LutniaTaken = 0x810A,
+ BardHomeOpen = 0x810C,
+ FjordNoMonsters = 0x810E,
+ ShandriaWallTalking = 0x8110,
+ ShandriaWallCounter = 0x8112,
+ ShandriaWallDone = 0x8114,
+ FutureDone = 0x8116,
+ TalkButch = 0x8118,
+ GotSzalik = 0x811A,
+ GotCzosnek = 0x811C,
+ BearDone = 0x811E,
+ NekrVisited = 0x8120,
+ SunRiddle = 0x8122,
+ PtaszekAway = 0x8124,
+ KotGadanie = 0x8126,
+ SzlafmycaTaken = 0x8128,
+ BabkaTalk = 0x812A,
+ SellerTalk = 0x812C,
+ CzosnekDone = 0x812E,
+ PriestCounter = 0x8130,
+ PriestGest1 = 0x8132,
+ PriestGest2 = 0x8134,
+ PriestGest3 = 0x8136,
+ PriestGest4 = 0x8138,
+ PriestAnim = 0x813A,
+ HolyWaterTaken = 0x813C,
+ AxeTaken = 0x813E,
+ BadylTaken1 = 0x8140,
+ BadylTaken2 = 0x8142,
+ BadylSharpened = 0x8144,
+ PorwanieSmoka = 0x8146,
+ ShopReOpen = 0x8148,
+ LuskaShown = 0x814A,
+ CudKnow = 0x814C,
+ VampireDead = 0x814E,
+ MapaVisible1 = 0x8150,
+ MapaVisible2 = 0x8152,
+ MapaVisible3 = 0x8154,
+ MapaVisible4 = 0x8156,
+ MapaVisible5 = 0x8158,
+ MapaVisible6 = 0x815A,
+ MapaVisible7 = 0x815C,
+ MapaVisible8 = 0x815E,
+ MapaVisible9 = 0x8160,
+ MapaX = 0x8162,
+ MapaY = 0x8164,
+ MapaD = 0x8166,
+ OldMapaX = 0x8168,
+ OldMapaY = 0x816A,
+ OldMapaD = 0x816C,
+ MovingBack = 0x816E,
+ MapaCount = 0x8170,
+ Pustelnia1st = 0x8172,
+ CzarnePole1st = 0x8174,
+ TalkArivNum = 0x8176,
+ Pfui = 0x8178,
+ MapaSunlordEnabled = 0x817A,
+ WebDone = 0x817C,
+ DragonDone = 0x817E,
+ KanPlay = 0x8180,
+ OldKanPlay = 0x8182,
+ LapkiWait = 0x8184,
+ WebNoCheck = 0x8186,
+ Perfumeria = 0x8188,
+ SmokNoCheck = 0x818A,
+ IluzjaBroken = 0x818C,
+ IluzjaWorking = 0x818E,
+ IluzjaCounter = 0x8190,
+ KurhanOpen1 = 0x8192,
+ KastetTaken = 0x8194,
+ KastetDown = 0x8196,
+ KurhanDone = 0x8198,
+ SkelCounter = 0x819A,
+ SkelDial1 = 0x819C,
+ SkelDial2 = 0x819E,
+ SkelDial3 = 0x81A0,
+ SkelDial4 = 0x81A2,
+ SameTalker = 0x81A4,
+ RunMonstersText = 0x81A6,
+ PiwnicaChecked = 0x81A8,
+ DragonTalked = 0x81AA,
+ ToldAboutBook = 0x81AC,
+ SilmanionaDone = 0x81AE,
+ ToldBookCount = 0x81B0,
+ SmrodNoCheck = 0x81B2,
+ RopeTaken = 0x81B4,
+ RopeTime = 0x81B6,
+ LaskaFree = 0x81B8,
+ ShanSmokTalked = 0x81BA,
+ SwordTaken = 0x81BC,
+ Mill1st = 0x81BE,
+ SawRat = 0x81C0,
+ KnowRat = 0x81C2,
+ DziuraTimer = 0x81C4,
+ LaskaInside = 0x81C6,
+ HoleBig = 0x81C8,
+ EnableWiedzmin = 0x81CA,
+ EnableTrucizna = 0x81CC,
+ KnowPoison = 0x81CE,
+ KufelTaken = 0x81D0,
+ BojkaEnabled = 0x81D2,
+ BitwaNot1st = 0x81D4,
+ BojkaTimer = 0x81D6,
+ BojkaGirl = 0x81D8,
+ Look1st = 0x81DA,
+ RatTaken = 0x81DC,
+ LaskaTalkedGr = 0x81DE,
+ RatusGivus = 0x81E0,
+ MamObole = 0x81E2,
+ Speed1st = 0x81E4,
+ SpeedTimer = 0x81E6,
+ ProveIt = 0x81E8,
+ Proven = 0x81EA,
+ ShowWoalka = 0x81EC,
+ PoisonTaken = 0x81EE,
+ HellOpened = 0x81F0,
+ HellNoCheck = 0x81F2,
+ TalAn1 = 0x81F4,
+ TalAn2 = 0x81F6,
+ TalAn3 = 0x81F8,
+ TalkDevilGuard = 0x81fA,
+ Sword1st = 0x81FC,
+ IluzjaNoCheck = 0x81FE,
+ RozdzielniaNumber = 0x8200,
+ JailChecked = 0x8202,
+ JailTalked = 0x8204,
+ TrickFailed = 0x8206,
+ WegielVisible = 0x8208,
+ WegielTimer1 = 0x820A,
+ RandomSample = 0x820C,
+ RandomSampleTimer = 0x820E,
+ SampleTimer = 0x8210,
+ ZonaSample = 0x8212,
+ HoleTryAgain = 0x8214,
+ TeleportTimer = 0x8216,
+ RozLezy = 0x8218,
+ UdkoTimer = 0x821A,
+ ZaworZatkany = 0x821C,
+ ZaworOpened = 0x821E,
+ DoorExploded = 0x8220,
+ SkoraTaken = 0x8222,
+ CiezkieByl = 0x8224,
+ MamWegiel = 0x8226,
+ SwiecaAway = 0x8228,
+ ITSAVE = 0x822A,
+ RozpadlSie = 0x822C,
+ WegielFullTimer = 0x822E,
+ WegielDown = 0x8230,
+ WegielDownTimer = 0x8232,
+ PaliSie = 0x8234,
+ DiabGuardTalked = 0x8236,
+ GuardsNoCheck = 0x8238,
+ TalkedPowloka = 0x823A,
+ JailOpen = 0x823C,
+ PrzytulTimer = 0x823E,
+ JailDone = 0x8240,
+ MamMonety = 0x8242,
+ LotTimer = 0x8244,
+ LotObj = 0x8246,
+ PtakTimer = 0x8248,
+ BookTimer = 0x824A,
+ BookGiba = 0x824C,
+ PtakLata = 0x824E,
+ Podej = 0x8250,
+ GotHint = 0x8252,
+ LawaLeci = 0x8254,
+ PowerKlik = 0x8258,
+ LucekBad = 0x825A,
+ LucekBad1st = 0x825C,
+ IntroDial1 = 0x825E,
+ IntroDial2 = 0x8260,
+ ItsOutro = 0x8262,
+ KamienComment = 0x8264,
+ KamienSkip = 0x8266,
+ TesterFlag = 0x8268,
+ RememberLine = 0x826A,
+ OpisLapek = 0x826C,
+ //OpisKamienia = 0x826E, // Redefinition
+ TalWait = 0x8270,
+ OpisKamienia = 0x8272,
+ JumpBox = 0x8274,
+ JumpBox1 = 0x8276,
+ JumpBox2 = 0x8278,
+ JumpBox3 = 0x827A,
+ SpecPiesek = 0x827C,
+ SpecPiesekCount = 0x827E,
+ SpecPiesekGadanie = 0x8282,
+ ZnikaFlag = 0x8284,
+ ZnikaTimer = 0x8286,
+ SowaTimer = 0x8288,
+ MamrotanieOff = 0x828A,
+ // System flags controlled by script
+ CURRMOB = 0x8400,
+ KOLOR = 0x8402,
+ MBFLAG = 0x8404,
+ MXFLAG = 0x8406,
+ MYFLAG = 0x8408,
+ SCROLLTYPE = 0x840A,
+ SCROLLVALUE = 0x840C,
+ SCROLLVALUE2 = 0x840E,
+ TALKEXITCODE = 0x8410,
+ SPECROUTFLAG1 = 0x8412,
+ SPECROUTFLAG2 = 0x8414,
+ SPECROUTFLAG3 = 0x8416,
+ TALKFLAGCODE = 0x8418,
+ CURRROOM = 0x841A,
+ Talker1Init = 0x841C,
+ Talker2Init = 0x841E,
+ RESTOREROOM = 0x8420,
+ INVALLOWED = 0x8422,
+ BOXSEL = 0x8424,
+ CURSEBLINK = 0x8426,
+ EXACTMOVE = 0x8428,
+ MOVEDESTX = 0x842A,
+ MOVEDESTY = 0x842C,
+ NOANTIALIAS = 0x842E,
+ ESCAPED = 0x8430,
+ ALLOW1OPTION = 0x8432,
+ VOICE_H_LINE = 0x8434,
+ VOICE_A_LINE = 0x8436,
+ VOICE_B_LINE = 0x8438,
+ VOICE_C_LINE = 0x843A,
+ NOHEROATALL = 0x843C,
+ MOUSEENABLED = 0x843E,
+ DIALINES = 0x8440,
+ //SELITEM = 0x8442, // Redefinition
+ SHANWALK = 0x8444,
+ SHANDOG = 0x8446,
+ GETACTIONBACK = 0x8448,
+ GETACTIONDATA = 0x844C,
+ GETACTION = 0x8450,
+ HEROFAST = 0x8452,
+ SELITEM = 0x8454,
+ LMOUSE = 0x8456,
+ MINMX = 0x8458,
+ MAXMX = 0x845A,
+ MINMY = 0x845C,
+ MAXMY = 0x845E,
+ TORX1 = 0x8460,
+ TORY1 = 0x8462,
+ TORX2 = 0x8464,
+ TORY2 = 0x8466,
+ POWER = 0x8468,
+ POWERENABLED = 0x846A,
+ FLCRESTORE = 0x846C,
+ NOCLSTEXT = 0x846E,
+ ESCAPED2 = 0x8470
+ };
+
+ struct FlagDebug {
+ Id id;
+ char flagName[30];
+ };
+
+ static const int kFlagDebugAmount = 368;
+ static const FlagDebug _flagNames[kFlagDebugAmount];
+};
+
+} // End of namespace Prince
+
+#endif
diff --git a/engines/prince/font.cpp b/engines/prince/font.cpp
new file mode 100644
index 0000000000..e81a93d1a1
--- /dev/null
+++ b/engines/prince/font.cpp
@@ -0,0 +1,94 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "common/archive.h"
+#include "common/debug.h"
+#include "common/stream.h"
+
+#include "prince/font.h"
+#include "prince/prince.h"
+
+namespace Prince {
+
+Font::Font() : _fontData(nullptr) {
+}
+
+Font::~Font() {
+ if (_fontData != nullptr) {
+ free(_fontData);
+ _fontData = nullptr;
+ }
+}
+
+bool Font::loadStream(Common::SeekableReadStream &stream) {
+ stream.seek(0);
+ uint32 dataSize = stream.size();
+ _fontData = (byte *)malloc(dataSize);
+ stream.read(_fontData, stream.size());
+ return true;
+}
+
+int Font::getFontHeight() const {
+ return _fontData[5];
+}
+
+int Font::getMaxCharWidth() const {
+ return 0;
+}
+
+Font::ChrData Font::getChrData(byte chr) const {
+ chr -= 32;
+ uint16 chrOffset = 4 * chr + 6;
+
+ ChrData chrData;
+ chrData._width = _fontData[chrOffset + 2];
+ chrData._height = _fontData[chrOffset + 3];
+ chrData._pixels = _fontData + READ_LE_UINT16(_fontData + chrOffset);
+
+ return chrData;
+}
+
+int Font::getCharWidth(uint32 chr) const {
+ return getChrData(chr)._width;
+}
+
+void Font::drawChar(Graphics::Surface *dst, uint32 chr, int posX, int posY, uint32 color) const {
+ const ChrData chrData = getChrData(chr);
+ Common::Rect screenRect(0, 0, PrinceEngine::kNormalWidth, PrinceEngine::kNormalHeight);
+
+ for (int y = 0; y < chrData._height; y++) {
+ for (int x = 0; x < chrData._width; x++) {
+ byte d = chrData._pixels[x + (chrData._width * y)];
+ if (d == 0) d = 255;
+ else if (d == 1) d = 0;
+ else if (d == 2) d = color;
+ else if (d == 3) d = 0;
+ if (d != 255) {
+ if (screenRect.contains(posX + x, posY + y)) {
+ *(byte *)dst->getBasePtr(posX + x, posY + y) = d;
+ }
+ }
+ }
+ }
+}
+
+} // End of namespace Prince
diff --git a/engines/prince/font.h b/engines/prince/font.h
new file mode 100644
index 0000000000..b03849a4aa
--- /dev/null
+++ b/engines/prince/font.h
@@ -0,0 +1,64 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef PRINCE_FONT_H
+#define PRINCE_FONT_H
+
+#include "graphics/font.h"
+#include "graphics/surface.h"
+
+#include "common/str.h"
+#include "common/rect.h"
+
+namespace Prince {
+
+class Font : public Graphics::Font {
+public:
+ Font();
+ virtual ~Font();
+
+ bool loadStream(Common::SeekableReadStream &stream);
+
+ virtual int getFontHeight() const override;
+
+ virtual int getMaxCharWidth() const override;
+
+ virtual int getCharWidth(uint32 chr) const override;
+
+ virtual void drawChar(Graphics::Surface *dst, uint32 chr, int x, int y, uint32 color) const override;
+
+ virtual int getKerningOffset(uint32 left, uint32 right) const override { return -2; }
+
+private:
+ struct ChrData {
+ byte *_pixels;
+ byte _width;
+ byte _height;
+ };
+
+ ChrData getChrData(byte chr) const;
+
+ byte *_fontData;
+};
+
+} // End of namespace Prince
+
+#endif
diff --git a/engines/prince/graphics.cpp b/engines/prince/graphics.cpp
new file mode 100644
index 0000000000..f556d81eab
--- /dev/null
+++ b/engines/prince/graphics.cpp
@@ -0,0 +1,474 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "prince/graphics.h"
+#include "prince/prince.h"
+#include "prince/mhwanh.h"
+
+#include "graphics/palette.h"
+
+#include "common/memstream.h"
+
+namespace Prince {
+
+GraphicsMan::GraphicsMan(PrinceEngine *vm) : _vm(vm), _changed(false) {
+ initGraphics(640, 480, true);
+
+ _frontScreen = new Graphics::Surface();
+ _frontScreen->create(640, 480, Graphics::PixelFormat::createFormatCLUT8());
+
+ _screenForInventory = new Graphics::Surface();
+ _screenForInventory->create(640, 480, Graphics::PixelFormat::createFormatCLUT8());
+
+ _mapScreen = new Graphics::Surface();
+ _mapScreen->create(640, 480, Graphics::PixelFormat::createFormatCLUT8());
+
+ _shadowTable70 = (byte *)malloc(256);
+ _shadowTable50 = (byte *)malloc(256);
+}
+
+GraphicsMan::~GraphicsMan() {
+ _frontScreen->free();
+ delete _frontScreen;
+
+ _screenForInventory->free();
+ delete _screenForInventory;
+
+ _mapScreen->free();
+ delete _mapScreen;
+
+ free(_shadowTable70);
+ free(_shadowTable50);
+}
+
+void GraphicsMan::update(Graphics::Surface *screen) {
+ if (_changed) {
+ _vm->_system->copyRectToScreen((byte *)screen->getBasePtr(0, 0), 640, 0, 0, 640, 480);
+
+ _vm->_system->updateScreen();
+ _changed = false;
+ }
+}
+
+void GraphicsMan::setPalette(const byte *palette) {
+ _vm->_system->getPaletteManager()->setPalette(palette, 0, 256);
+}
+
+void GraphicsMan::change() {
+ _changed = true;
+}
+
+void GraphicsMan::draw(Graphics::Surface *screen, const Graphics::Surface *s) {
+ uint16 w = MIN(screen->w, s->w);
+ const byte *src = (const byte *)s->getBasePtr(0, 0);
+ byte *dst = (byte *)screen->getBasePtr(0, 0);
+ for (uint y = 0; y < s->h; y++) {
+ if (y < screen->h) {
+ memcpy(dst, src, w);
+ }
+ src += s->pitch;
+ dst += screen->pitch;
+ }
+ change();
+}
+
+// Black (value = 0) as a primary transparent color, fix for FLC animations
+void GraphicsMan::drawTransparentSurface(Graphics::Surface *screen, int32 posX, int32 posY, const Graphics::Surface *s, int secondTransColor) {
+ const byte *src1 = (const byte *)s->getBasePtr(0, 0);
+ byte *dst1 = (byte *)screen->getBasePtr(posX, posY);
+ for (int y = 0; y < s->h; y++) {
+ if (y + posY < screen->h && y + posY >= 0) {
+ const byte *src2 = src1;
+ byte *dst2 = dst1;
+ for (int x = 0; x < s->w; x++, src2++, dst2++) {
+ if (*src2 && *src2 != secondTransColor) {
+ if (x + posX < screen->w && x + posX >= 0) {
+ *dst2 = *src2;
+ }
+ }
+ }
+ }
+ src1 += s->pitch;
+ dst1 += screen->pitch;
+ }
+ change();
+}
+
+/**
+ * Similar to drawTransparentSurface but with use of shadowTable for color recalculation
+ * and kShadowColor (191) as a transparent color.
+ */
+void GraphicsMan::drawAsShadowSurface(Graphics::Surface *screen, int32 posX, int32 posY, const Graphics::Surface *s, byte *shadowTable) {
+ const byte *src1 = (const byte *)s->getBasePtr(0, 0);
+ byte *dst1 = (byte *)screen->getBasePtr(posX, posY);
+ for (int y = 0; y < s->h; y++) {
+ if (y + posY < screen->h && y + posY >= 0) {
+ const byte *src2 = src1;
+ byte *dst2 = dst1;
+ for (int x = 0; x < s->w; x++, src2++, dst2++) {
+ if (*src2 == kShadowColor) {
+ if (x + posX < screen->w && x + posX >= 0) {
+ *dst2 = *(shadowTable + *dst2);
+ }
+ }
+ }
+ }
+ src1 += s->pitch;
+ dst1 += screen->pitch;
+ }
+}
+
+/**
+ * Used in glowing animation for inventory items. Creates special blendTable array of colors,
+ * use black (0) as a transparent color.
+ */
+void GraphicsMan::drawTransparentWithBlendSurface(Graphics::Surface *screen, int32 posX, int32 posY, const Graphics::Surface *s) {
+ const byte *src1 = (const byte *)s->getBasePtr(0, 0);
+ byte *dst1 = (byte *)screen->getBasePtr(posX, posY);
+ byte *blendTable = (byte *)malloc(256);
+ for (int i = 0; i < 256; i++) {
+ blendTable[i] = 255;
+ }
+ for (int y = 0; y < s->h; y++) {
+ if (y + posY < screen->h && y + posY >= 0) {
+ const byte *src2 = src1;
+ byte *dst2 = dst1;
+ for (int x = 0; x < s->w; x++, src2++, dst2++) {
+ if (*src2) {
+ if (x + posX < screen->w && x + posX >= 0) {
+ *dst2 = getBlendTableColor(*src2, *dst2, blendTable);
+ }
+ }
+ }
+ }
+ src1 += s->pitch;
+ dst1 += screen->pitch;
+ }
+ free(blendTable);
+ change();
+}
+
+/**
+ * Similar to drawTransparentSurface but with with use of DrawNode as argument for Z axis sorting
+ * and white (255) as transparent color.
+ */
+void GraphicsMan::drawTransparentDrawNode(Graphics::Surface *screen, DrawNode *drawNode) {
+ byte *src1 = (byte *)drawNode->s->getBasePtr(0, 0);
+ byte *dst1 = (byte *)screen->getBasePtr(drawNode->posX, drawNode->posY);
+ for (int y = 0; y < drawNode->s->h; y++) {
+ if (y + drawNode->posY < screen->h && y + drawNode->posY >= 0) {
+ byte *src2 = src1;
+ byte *dst2 = dst1;
+ for (int x = 0; x < drawNode->s->w; x++, src2++, dst2++) {
+ if (*src2 != 255) {
+ if (x + drawNode->posX < screen->w && x + drawNode->posX >= 0) {
+ *dst2 = *src2;
+ }
+ }
+ }
+ }
+ src1 += drawNode->s->pitch;
+ dst1 += screen->pitch;
+ }
+}
+
+/**
+ * Similar to drawTransparentDrawNode but with additional anti-aliasing code for sprite drawing.
+ * Edge smoothing is based on 256 x 256 table of colors transition.
+ * Algorithm is checking if currently drawing pixel is located next to the edge of sprite and if it makes jagged line.
+ * If it does then this pixel is set with color from transition table calculated of original background pixel color
+ * and sprite's edge pixel color.
+ */
+void GraphicsMan::drawTransparentWithTransDrawNode(Graphics::Surface *screen, DrawNode *drawNode) {
+ // pos of first pixel for each row of source sprite
+ byte *src1 = (byte *)drawNode->s->getBasePtr(0, 0);
+ // pos of drawing first pixel for each row on screen surface
+ byte *dst1 = (byte *)screen->getBasePtr(drawNode->posX, drawNode->posY);
+ // trasition table for calculating new color value
+ byte *transTableData = (byte *)drawNode->data;
+ for (int y = 0; y < drawNode->s->h; y++) {
+ if (y + drawNode->posY < screen->h && y + drawNode->posY >= 0) {
+ // current pixel in row of source sprite
+ byte *src2 = src1;
+ // current pixel in row of screen surface
+ byte *dst2 = dst1;
+ for (int x = 0; x < drawNode->s->w; x++, src2++, dst2++) {
+ if (x + drawNode->posX < screen->w && x + drawNode->posX >= 0) {
+ if (*src2 != 255) {
+ // if source sprite pixel is not mask color than draw it normally
+ *dst2 = *src2;
+ } else {
+ // check for making jagged line
+ if (x) {
+ // not first pixel in row
+ if (*(src2 - 1) == 255) {
+ // if it has mask color to the left - check right
+ if (x != drawNode->s->w - 1) {
+ // not last pixel in row
+ if (*(src2 + 1) == 255) {
+ // pixel to the right with mask color - no anti-alias
+ continue;
+ }
+ // it's not mask color to the right - we continue checking
+ } else {
+ // last pixel in row, no right check - no anti-alias
+ continue;
+ }
+ }
+ // it's not mask color to the left - we continue checking
+ } else if (x != drawNode->s->w - 1) {
+ // first pixel in row but not last - just right pixel checking
+ if (*(src2 + 1) == 255) {
+ // pixel to the right with mask color - no anti-alias
+ continue;
+ }
+ // it's not mask color to the right - we continue checking
+ } else {
+ // it's first and last pixel in row at the same time (width = 1) - no anti-alias
+ continue;
+ }
+ byte value = 0;
+ if (y != drawNode->s->h - 1) {
+ // not last row
+ // check pixel below of current src2 pixel
+ value = *(src2 + drawNode->s->pitch);
+ if (value == 255) {
+ // pixel below with mask color - check above
+ if (y) {
+ // not first row
+ value = *(src2 - drawNode->s->pitch);
+ if (value == 255) {
+ // pixel above with mask color - no anti-alias
+ continue;
+ }
+ // it's not mask color above - we draw as transition color
+ } else {
+ // first row - no anti-alias
+ continue;
+ }
+ }
+ // it's not mask color below - we draw as transition color
+ } else if (y) {
+ // last row - just check above
+ value = *(src2 - drawNode->s->pitch);
+ if (value == 255) {
+ // pixel above with mask color - no anti-alias
+ continue;
+ }
+ // it's not mask color above - we draw as transition color
+ } else {
+ // first and last row at the same time (height = 1) - no anti-alias
+ continue;
+ }
+ // new color value based on orginal screen surface color and sprite's edge pixel color
+ *dst2 = transTableData[*dst2 * 256 + value];
+ }
+ }
+ }
+ }
+ // adding pitch to jump to next row of pixels
+ src1 += drawNode->s->pitch;
+ dst1 += screen->pitch;
+ }
+}
+
+void GraphicsMan::drawMaskDrawNode(Graphics::Surface *screen, DrawNode *drawNode) {
+ byte *maskData = (byte *)drawNode->data;
+ byte *src1 = (byte *)drawNode->originalRoomSurface->getBasePtr(drawNode->posX, drawNode->posY);
+ byte *dst1 = (byte *)screen->getBasePtr(drawNode->posX, drawNode->posY);
+ int maskWidth = drawNode->width >> 3;
+ int maskPostion = 0;
+ int maskCounter = 128;
+ for (int y = 0; y < drawNode->height; y++) {
+ if (y + drawNode->posY < screen->h && y + drawNode->posY >= 0) {
+ byte *src2 = src1;
+ byte *dst2 = dst1;
+ int tempMaskPostion = maskPostion;
+ for (int x = 0; x < drawNode->width; x++, src2++, dst2++) {
+ if (x + drawNode->posX < screen->w && x + drawNode->posX >= 0) {
+ if ((maskData[tempMaskPostion] & maskCounter) != 0) {
+ *dst2 = *src2;
+ }
+ }
+ maskCounter >>= 1;
+ if (maskCounter == 0) {
+ maskCounter = 128;
+ tempMaskPostion++;
+ }
+ }
+ }
+ src1 += drawNode->originalRoomSurface->pitch;
+ dst1 += screen->pitch;
+ maskPostion += maskWidth;
+ maskCounter = 128;
+ }
+}
+
+void GraphicsMan::drawAsShadowDrawNode(Graphics::Surface *screen, DrawNode *drawNode) {
+ byte *shadowData = (byte *)drawNode->data;
+ byte *src1 = (byte *)drawNode->s->getBasePtr(0, 0);
+ byte *dst1 = (byte *)screen->getBasePtr(drawNode->posX, drawNode->posY);
+ for (int y = 0; y < drawNode->s->h; y++) {
+ if (y + drawNode->posY < screen->h && y + drawNode->posY >= 0) {
+ byte *src2 = src1;
+ byte *dst2 = dst1;
+ for (int x = 0; x < drawNode->s->w; x++, src2++, dst2++) {
+ if (*src2 == kShadowColor) {
+ if (x + drawNode->posX < screen->w && x + drawNode->posX >= 0) {
+ *dst2 = *(shadowData + *dst2);
+ }
+ }
+ }
+ }
+ src1 += drawNode->s->pitch;
+ dst1 += screen->pitch;
+ }
+}
+
+void GraphicsMan::drawBackSpriteDrawNode(Graphics::Surface *screen, DrawNode *drawNode) {
+ byte *src1 = (byte *)drawNode->s->getBasePtr(0, 0);
+ byte *dst1 = (byte *)screen->getBasePtr(drawNode->posX, drawNode->posY);
+ for (int y = 0; y < drawNode->s->h; y++) {
+ if (y + drawNode->posY < screen->h && y + drawNode->posY >= 0) {
+ byte *src2 = src1;
+ byte *dst2 = dst1;
+ for (int x = 0; x < drawNode->s->w; x++, src2++, dst2++) {
+ if (*src2 != 255) {
+ if (x + drawNode->posX < screen->w && x + drawNode->posX >= 0) {
+ if (*dst2 == 255) {
+ *dst2 = *src2;
+ }
+ }
+ }
+ }
+ }
+ src1 += drawNode->s->pitch;
+ dst1 += screen->pitch;
+ }
+}
+
+byte GraphicsMan::getBlendTableColor(byte pixelColor, byte backgroundPixelColor, byte *blendTable) {
+ int currColor = 0;
+
+ if (blendTable[pixelColor] != 255) {
+ currColor = blendTable[pixelColor];
+ } else {
+ const byte *originalPalette = _vm->_roomBmp->getPalette();
+
+ int redFirstOrg = originalPalette[pixelColor * 3] * _vm->_mst_shadow / 256;
+ CLIP(redFirstOrg, 0, 255);
+ if (_vm->_mst_shadow <= 256) {
+ int redFirstBack = originalPalette[backgroundPixelColor * 3] * (256 - _vm->_mst_shadow) / 256;
+ CLIP(redFirstBack, 0, 255);
+ redFirstOrg += redFirstBack;
+ CLIP(redFirstOrg, 0, 255);
+ }
+
+ int greenFirstOrg = originalPalette[pixelColor * 3 + 1] * _vm->_mst_shadow / 256;
+ CLIP(greenFirstOrg, 0, 255);
+ if (_vm->_mst_shadow <= 256) {
+ int greenFirstBack = originalPalette[backgroundPixelColor * 3 + 1] * (256 - _vm->_mst_shadow) / 256;
+ CLIP(greenFirstBack, 0, 255);
+ greenFirstOrg += greenFirstBack;
+ CLIP(greenFirstOrg, 0, 255);
+ }
+
+ int blueFirstOrg = originalPalette[pixelColor * 3 + 2] * _vm->_mst_shadow / 256;
+ CLIP(blueFirstOrg, 0, 255);
+ if (_vm->_mst_shadow <= 256) {
+ int blueFirstBack = originalPalette[backgroundPixelColor * 3 + 2] * (256 - _vm->_mst_shadow) / 256;
+ CLIP(blueFirstBack, 0, 255);
+ blueFirstOrg += blueFirstBack;
+ CLIP(blueFirstOrg, 0, 255);
+ }
+
+ int bigValue = PrinceEngine::kIntMax; // infinity
+ for (int j = 0; j < 256; j++) {
+ int redSecondOrg = originalPalette[3 * j];
+ int redNew = redFirstOrg - redSecondOrg;
+ redNew = redNew * redNew;
+
+ int greenSecondOrg = originalPalette[3 * j + 1];
+ int greenNew = greenFirstOrg - greenSecondOrg;
+ greenNew = greenNew * greenNew;
+
+ int blueSecondOrg = originalPalette[3 * j + 2];
+ int blueNew = blueFirstOrg - blueSecondOrg;
+ blueNew = blueNew * blueNew;
+
+ int sumOfColorValues = redNew + greenNew + blueNew;
+
+ if (sumOfColorValues < bigValue) {
+ bigValue = sumOfColorValues;
+ currColor = j;
+ }
+
+ if (sumOfColorValues == 0) {
+ break;
+ }
+ }
+ blendTable[pixelColor] = currColor;
+ }
+ return currColor;
+}
+
+void GraphicsMan::makeShadowTable(int brightness, byte *shadowPalette) {
+ int shadow = brightness * 256 / 100;
+ const byte *originalPalette = _vm->_roomBmp->getPalette();
+
+ for (int i = 0; i < 256; i++) {
+ int redFirstOrg = originalPalette[3 * i] * shadow / 256;
+ int greenFirstOrg = originalPalette[3 * i + 1] * shadow / 256;
+ int blueFirstOrg = originalPalette[3 * i + 2] * shadow / 256;
+
+ int currColor = 0;
+ int bigValue = 999999999; // infinity
+
+ for (int j = 0; j < 256; j++) {
+ int redSecondOrg = originalPalette[3 * j];
+ int redNew = redFirstOrg - redSecondOrg;
+ redNew = redNew * redNew;
+
+ int greenSecondOrg = originalPalette[3 * j + 1];
+ int greenNew = greenFirstOrg - greenSecondOrg;
+ greenNew = greenNew * greenNew;
+
+ int blueSecondOrg = originalPalette[3 * j + 2];
+ int blueNew = blueFirstOrg - blueSecondOrg;
+ blueNew = blueNew * blueNew;
+
+ int sumOfColorValues = redNew + greenNew + blueNew;
+
+ if (sumOfColorValues < bigValue) {
+ bigValue = sumOfColorValues;
+ currColor = j;
+ }
+
+ if (sumOfColorValues == 0) {
+ break;
+ }
+ }
+ shadowPalette[i] = currColor;
+ }
+}
+
+} // End of namespace Prince
diff --git a/engines/prince/graphics.h b/engines/prince/graphics.h
new file mode 100644
index 0000000000..1a1737f976
--- /dev/null
+++ b/engines/prince/graphics.h
@@ -0,0 +1,76 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef PRINCE_GRAPHICS_H
+#define PRINCE_GRAPHICS_H
+
+#include "graphics/surface.h"
+
+namespace Prince {
+
+class PrinceEngine;
+class MhwanhDecoder;
+struct DrawNode;
+
+class GraphicsMan {
+public:
+ GraphicsMan(PrinceEngine *vm);
+ ~GraphicsMan();
+
+ void update(Graphics::Surface *screen);
+
+ void change();
+
+ void setPalette(const byte *palette);
+ void makeShadowTable(int brightness, byte *shadowTable);
+
+ void draw(Graphics::Surface *screen, const Graphics::Surface *s);
+ void drawTransparentSurface(Graphics::Surface *screen, int32 posX, int32 posY, const Graphics::Surface *s, int secondTransColor = 0);
+ void drawAsShadowSurface(Graphics::Surface *screen, int32 posX, int32 posY, const Graphics::Surface *s, byte *shadowTable);
+ void drawTransparentWithBlendSurface(Graphics::Surface *screen, int32 posX, int32 posY, const Graphics::Surface *s);
+
+ static void drawTransparentDrawNode(Graphics::Surface *screen, DrawNode *drawNode);
+ static void drawTransparentWithTransDrawNode(Graphics::Surface *screen, DrawNode *drawNode);
+ static void drawAsShadowDrawNode(Graphics::Surface *screen, DrawNode *drawNode);
+ static void drawMaskDrawNode(Graphics::Surface *screen, DrawNode *drawNode);
+ static void drawBackSpriteDrawNode(Graphics::Surface *screen, DrawNode *drawNode);
+
+ byte getBlendTableColor(byte pixelColor, byte backgroundPixelColor, byte *blendTable);
+
+ Graphics::Surface *_frontScreen;
+ Graphics::Surface *_screenForInventory;
+ Graphics::Surface *_mapScreen;
+ const Graphics::Surface *_roomBackground;
+
+ byte *_shadowTable70;
+ byte *_shadowTable50;
+
+ static const byte kShadowColor = 191;
+
+private:
+ PrinceEngine *_vm;
+ bool _changed;
+};
+
+} // End of namespace Prince
+
+#endif
diff --git a/engines/prince/hero.cpp b/engines/prince/hero.cpp
new file mode 100644
index 0000000000..b873e83360
--- /dev/null
+++ b/engines/prince/hero.cpp
@@ -0,0 +1,1002 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "common/debug.h"
+#include "common/random.h"
+
+#include "prince/hero.h"
+#include "prince/hero_set.h"
+#include "prince/animation.h"
+#include "prince/resource.h"
+#include "prince/prince.h"
+#include "prince/graphics.h"
+#include "prince/flags.h"
+#include "prince/script.h"
+
+namespace Prince {
+
+Hero::Hero(PrinceEngine *vm, GraphicsMan *graph) : _vm(vm), _graph(graph),
+ _number(0), _visible(false), _state(kHeroStateStay), _middleX(0), _middleY(0),
+ _boreNum(1), _currHeight(0), _moveDelay(0), _shadMinus(0), _moveSetType(0), _zoomedHeroSurface(nullptr),
+ _lastDirection(kHeroDirDown), _destDirection(kHeroDirDown), _talkTime(0), _boredomTime(0), _phase(0),
+ _specAnim(nullptr), _drawX(0), _drawY(0), _drawZ(0),
+ _frameXSize(0), _frameYSize(0), _scaledFrameXSize(0), _scaledFrameYSize(0), _color(0),
+ _coords(nullptr), _dirTab(nullptr), _currCoords(nullptr), _currDirTab(nullptr), _step(0),
+ _maxBoredom(200), _leftRightMainDir(0), _upDownMainDir(0), _animSetNr(0)
+{
+}
+
+Hero::~Hero() {
+ freeHeroAnim();
+ freeOldMove();
+ freeZoomedSurface();
+}
+
+bool Hero::loadAnimSet(uint32 animSetNr) {
+ _animSetNr = animSetNr;
+
+ if (animSetNr >= ARRAYSIZE(heroSetTable)) {
+ return false;
+ }
+
+ _shadMinus = heroSetBack[animSetNr];
+
+ for (uint32 i = 0; i < _moveSet.size(); i++) {
+ delete _moveSet[i];
+ }
+
+ const HeroSetAnimNames &animSet = *heroSetTable[animSetNr];
+
+ _moveSet.resize(kMoveSetSize);
+ for (uint32 i = 0; i < kMoveSetSize; i++) {
+ debug("Anim set item %d %s", i, animSet[i]);
+ Animation *anim = nullptr;
+ if (animSet[i] != nullptr) {
+ anim = new Animation();
+ Resource::loadResource(anim, animSet[i], false);
+ }
+ _moveSet[i] = anim;
+ }
+
+ return true;
+}
+
+Graphics::Surface *Hero::getSurface() {
+ Animation *heroAnim = nullptr;
+ if (_specAnim != nullptr) {
+ heroAnim = _specAnim;
+ } else {
+ heroAnim = _moveSet[_moveSetType];
+ }
+
+ if (heroAnim != nullptr) {
+ int16 phaseFrameIndex = heroAnim->getPhaseFrameIndex(_phase);
+ Graphics::Surface *heroFrame = heroAnim->getFrame(phaseFrameIndex);
+ return heroFrame;
+ }
+ return nullptr;
+}
+
+uint16 Hero::getData(AttrId dataId) {
+ switch (dataId) {
+ case kHeroLastDir:
+ return _lastDirection;
+ case kHeroAnimSet:
+ return _animSetNr;
+ default:
+ assert(false);
+ return 0;
+ }
+}
+
+int Hero::getScaledValue(int size) {
+ int16 initScaleValue = _vm->_scaleValue;
+ if (_vm->_scaleValue != 10000) {
+ int newSize = 0;
+ for (int i = 0; i < size; i++) {
+ initScaleValue -= 100;
+ if (initScaleValue >= 0) {
+ newSize++;
+ } else {
+ initScaleValue += _vm->_scaleValue;
+ }
+ }
+ return newSize;
+ } else {
+ return size;
+ }
+}
+
+Graphics::Surface *Hero::zoomSprite(Graphics::Surface *heroFrame) {
+ Graphics::Surface *zoomedFrame = new Graphics::Surface();
+ zoomedFrame->create(_scaledFrameXSize, _scaledFrameYSize, Graphics::PixelFormat::createFormatCLUT8());
+
+ int sprZoomX;
+ int sprZoomY = _vm->_scaleValue;
+ uint xSource = 0;
+ uint ySource = 0;
+ uint xDest = 0;
+ uint yDest = 0;
+
+ for (int i = 0; i < _scaledFrameYSize; i++) {
+ // linear_loop:
+ while (1) {
+ sprZoomY -= 100;
+ if (sprZoomY >= 0 || _vm->_scaleValue == 10000) {
+ // all_r_y
+ sprZoomX = _vm->_scaleValue;
+ break; // to loop_lin
+ } else {
+ sprZoomY += _vm->_scaleValue;
+ xSource = 0;
+ ySource++;
+ }
+ }
+ // loop_lin:
+ for (int j = 0; j < _scaledFrameXSize; j++) {
+ sprZoomX -= 100;
+ if (sprZoomX >= 0) {
+ // its_all_r
+ memcpy(zoomedFrame->getBasePtr(xDest, yDest), heroFrame->getBasePtr(xSource, ySource), 1);
+ xDest++;
+ } else {
+ sprZoomX += _vm->_scaleValue;
+ j--;
+ }
+ xSource++;
+ }
+ xDest = 0;
+ yDest++;
+ xSource = 0;
+ ySource++;
+ }
+ return zoomedFrame;
+}
+
+void Hero::countDrawPosition() {
+ Animation *heroAnim = nullptr;
+ if (_specAnim != nullptr) {
+ heroAnim = _specAnim;
+ } else {
+ heroAnim = _moveSet[_moveSetType];
+ }
+ if (heroAnim != nullptr) {
+ int phaseFrameIndex = heroAnim->getPhaseFrameIndex(_phase);
+ Graphics::Surface *heroSurface = heroAnim->getFrame(phaseFrameIndex);
+
+ _frameXSize = heroSurface->w;
+ _frameYSize = heroSurface->h;
+ _scaledFrameXSize = getScaledValue(_frameXSize);
+ _scaledFrameYSize = getScaledValue(_frameYSize);
+
+ if (_vm->_scaleValue != 10000) {
+ //notfullSize
+ _drawX = _middleX - _scaledFrameXSize / 2;
+ _drawY = _middleY + 1 - _scaledFrameYSize;
+ _vm->checkMasks(_drawX, _drawY - 1, _scaledFrameXSize, _scaledFrameYSize, _middleY);
+ } else {
+ //fullSize
+ _drawX = _middleX - _frameXSize / 2;
+ _drawY = _middleY + 1 - _frameYSize;
+ _vm->checkMasks(_drawX, _drawY - 1, _frameXSize, _frameYSize, _middleY);
+ }
+ _drawZ = _middleY;
+ }
+}
+
+void Hero::showHeroShadow(Graphics::Surface *screen, DrawNode *drawNode) {
+ PrinceEngine *vm = (PrinceEngine *)drawNode->data;
+ int16 heroSurfaceWidth = drawNode->s->w;
+ int16 heroSurfaceHeight = drawNode->s->h;
+
+ Graphics::Surface *makeShadow = new Graphics::Surface();
+ makeShadow->create(heroSurfaceWidth, heroSurfaceHeight, Graphics::PixelFormat::createFormatCLUT8());
+
+ for (int y = 0; y < heroSurfaceHeight; y++) {
+ byte *src = (byte *)drawNode->s->getBasePtr(0, y);
+ byte *dst = (byte *)makeShadow->getBasePtr(0, y);
+ for (int x = 0; x < heroSurfaceWidth; x++, dst++, src++) {
+ if (*src != 0xFF) {
+ *dst = GraphicsMan::kShadowColor;
+ } else {
+ *dst = *src;
+ }
+ }
+ }
+
+ if (drawNode->posY > 1 && drawNode->posY < PrinceEngine::kMaxPicHeight) {
+ int shadDirection;
+ if (vm->_lightY > drawNode->posY) {
+ shadDirection = 1;
+ } else {
+ shadDirection = 0;
+ }
+
+ vm->_shadLineLen = 0;
+ Graphics::drawLine(vm->_lightX, vm->_lightY, drawNode->posX, drawNode->posY, 0, &vm->plotShadowLinePoint, vm);
+
+ byte *sprShadow = vm->_graph->_shadowTable70;
+
+ int shadDrawX = drawNode->posX - vm->_picWindowX;
+ int shadDrawY = drawNode->posY - vm->_picWindowY;
+
+ int shadPosX = shadDrawX;
+ int shadPosY = shadDrawY;
+ int shadBitAddr = drawNode->posY * PrinceEngine::kMaxPicWidth / 8 + drawNode->posX / 8;
+ int shadBitMask = 128 >> (drawNode->posX % 8);
+
+ int shadZoomY2 = vm->_shadScaleValue;
+ int shadZoomY = drawNode->scaleValue;
+
+ int diffX = 0;
+ int diffY = 0;
+
+ int shadowHeroX = 0;
+ int shadowHeroY = heroSurfaceHeight - 1;
+
+ int shadLastY = 0;
+
+ byte *shadowHero = (byte *)makeShadow->getBasePtr(shadowHeroX, shadowHeroY); // first pixel from last row of shadow hero
+ byte *background = (byte *)screen->getBasePtr(shadDrawX, shadDrawY); // pixel of background where shadow sprite starts
+
+ // banked2
+ byte *shadowLineStart = vm->_shadowLine + 8;
+
+ int shadWallDown = 0;
+ int shadWallBitAddr = 0;
+ int shadWallBitMask = 0;
+ byte *shadWallDestAddr = 0;
+ int shadWallPosY = 0;
+ int shadWallSkipX = 0;
+ int shadWallModulo = 0;
+
+ // linear_loop
+ for (int i = 0; i < heroSurfaceHeight; i++) {
+ int j;
+ //retry_line:
+ for (j = heroSurfaceHeight - i; j > 0; j--) {
+ shadZoomY -= 100;
+ if (shadZoomY < 0 && drawNode->scaleValue != 10000) {
+ shadZoomY += drawNode->scaleValue;
+ shadowHeroY--;
+ if (shadowHeroY < 0) {
+ break;
+ }
+ } else {
+ break;
+ }
+ }
+ if (!j) {
+ break;
+ }
+ if (shadowHeroY < 0) {
+ break;
+ }
+
+ //line_y_ok
+ if (shadLastY != shadPosY && shadPosY >= 0 && shadPosY < 480 && shadPosX < 640) {
+ shadLastY = shadPosY;
+ bool skipLineFlag = false;
+ int shadSkipX = 0;
+ int ctLoop = 0;
+ int sprModulo = 0;
+
+ if (shadPosX < 0) {
+ shadSkipX = -1 * shadPosX;
+ if (heroSurfaceWidth > shadSkipX) {
+ ctLoop = heroSurfaceWidth - shadSkipX;
+ shadowHeroX = shadSkipX;
+ } else {
+ //skip_line
+ skipLineFlag = true;
+ }
+ } else {
+ //x1_ok
+ if (shadPosX + heroSurfaceWidth > 640) {
+ ctLoop = 640 - shadPosX;
+ sprModulo = shadPosX + heroSurfaceWidth - 640;
+ } else {
+ //draw_line
+ ctLoop = heroSurfaceWidth;
+ }
+ }
+
+ if (!skipLineFlag) {
+ //draw_line1
+ //retry_line2
+ int k;
+ for (k = j; k > 0; k--) {
+ shadZoomY2 -= 100;
+ if (shadZoomY2 < 0 && vm->_shadScaleValue != 10000) {
+ shadZoomY2 += vm->_shadScaleValue;
+ shadowHeroY--;
+ if (shadowHeroY < 0) {
+ break;
+ }
+ } else {
+ break;
+ }
+ }
+ if (shadowHeroY < 0) {
+ break;
+ }
+ if (!k) {
+ break;
+ }
+ //line_y_ok_2:
+ //copy_trans
+ bool shadWDFlag = false;
+ int shadZoomX = drawNode->scaleValue;
+ int backgroundDiff = shadSkipX;
+ int shadBitMaskCopyTrans = shadBitMask;
+ int shadBitAddrCopyTrans = shadBitAddr;
+ shadowHero = (byte *)makeShadow->getBasePtr(shadowHeroX, shadowHeroY);
+ background = (byte *)screen->getBasePtr(shadDrawX + diffX + backgroundDiff, shadDrawY + diffY);
+
+ if (shadPosX < 0) {
+ if (heroSurfaceWidth > shadSkipX) {
+ shadBitAddrCopyTrans += shadSkipX / 8;
+ if ((shadSkipX % 8)) {
+ //loop_rotate:
+ for (int a = 0; a < (shadSkipX % 8); a++) {
+ if (shadBitMaskCopyTrans == 1) {
+ shadBitMaskCopyTrans = 128;
+ shadBitAddrCopyTrans++;
+ } else {
+ shadBitMaskCopyTrans >>= 1;
+ }
+ }
+ }
+ }
+ }
+
+ //ct_loop:
+ for (int l = 0; l < ctLoop; l++) {
+ shadZoomX -= 100;
+ if (shadZoomX < 0 && drawNode->scaleValue != 10000) {
+ shadZoomX += drawNode->scaleValue;
+ } else {
+ if (*shadowHero == GraphicsMan::kShadowColor) {
+ if ((shadBitMaskCopyTrans & vm->_shadowBitmap[shadBitAddrCopyTrans])) {
+ if (shadWallDown == 0) {
+ if ((shadBitMaskCopyTrans & vm->_shadowBitmap[shadBitAddrCopyTrans + PrinceEngine::kShadowBitmapSize])) {
+ shadWDFlag = true;
+ //shadow
+ *background = *(sprShadow + *background);
+ }
+ }
+ } else {
+ //shadow
+ *background = *(sprShadow + *background);
+ }
+ }
+ //ct_next
+ if (shadBitMaskCopyTrans == 1) {
+ shadBitMaskCopyTrans = 128;
+ shadBitAddrCopyTrans++;
+ } else {
+ shadBitMaskCopyTrans >>= 1;
+ }
+ //okok
+ backgroundDiff++;
+ background = (byte *)screen->getBasePtr(shadDrawX + diffX + backgroundDiff, shadDrawY + diffY);
+ }
+ shadowHeroX++;
+ shadowHero = (byte *)makeShadow->getBasePtr(shadowHeroX, shadowHeroY);
+ }
+ //byebyebye
+ if (!shadWallDown && shadWDFlag) {
+ shadWallDown = shadPosX;
+ shadWallBitAddr = shadBitAddr;
+ shadWallDestAddr = (byte *)screen->getBasePtr(shadDrawX + diffX, shadDrawY + diffY);
+ shadWallBitMask = shadBitMask;
+ shadWallPosY = shadPosY;
+ shadWallSkipX = shadSkipX;
+ shadWallModulo = sprModulo;
+ }
+ //byebye
+ if (shadDirection && shadWallDown) {
+ int shadBitMaskWallCopyTrans = shadWallBitMask;
+ int shadBitAddrWallCopyTrans = shadWallBitAddr;
+ background = shadWallDestAddr;
+ shadowHero = (byte *)makeShadow->getBasePtr(shadWallSkipX, shadowHeroY);
+
+ if (ctLoop > shadWallSkipX && ctLoop - shadWallSkipX > shadWallModulo) {
+ //WALL_copy_trans
+ shadWDFlag = false;
+ int shadZoomXWall = drawNode->scaleValue;
+ int backgroundDiffWall = 0;
+ int shadowHeroXWall = 0;
+ //ct_loop:
+ for (int m = 0; m < ctLoop; m++) {
+ shadZoomXWall -= 100;
+ if (shadZoomXWall < 0 && drawNode->scaleValue != 10000) {
+ shadZoomXWall += drawNode->scaleValue;
+ } else {
+ //point_ok:
+ if (*shadowHero == GraphicsMan::kShadowColor) {
+ if ((shadBitMaskWallCopyTrans & vm->_shadowBitmap[shadBitAddrWallCopyTrans + PrinceEngine::kShadowBitmapSize])) {
+ *background = *(sprShadow + *background);
+ }
+ }
+ //ct_next
+ if (shadBitMaskWallCopyTrans == 1) {
+ shadBitMaskWallCopyTrans = 128;
+ shadBitAddrWallCopyTrans++;
+ } else {
+ shadBitMaskWallCopyTrans >>= 1;
+ }
+ //okok
+ backgroundDiffWall++;
+ background = shadWallDestAddr + backgroundDiffWall;
+ }
+ shadowHeroXWall++;
+ shadowHero = (byte *)makeShadow->getBasePtr(shadWallSkipX + shadowHeroXWall, shadowHeroY);
+ }
+ }
+ //krap2
+ shadWallDestAddr -= PrinceEngine::kNormalWidth;
+ shadWallBitAddr -= PrinceEngine::kMaxPicWidth / 8;
+ shadWallPosY--;
+ }
+ }
+ }
+ //skip_line
+ //next_line
+ if (READ_LE_UINT16(shadowLineStart + 2) < READ_LE_UINT16(shadowLineStart - 2)) {
+ //minus_y
+ shadBitAddr -= PrinceEngine::kMaxPicWidth / 8;
+ shadPosY--;
+ diffY--;
+ } else if (READ_LE_UINT16(shadowLineStart + 2) > READ_LE_UINT16(shadowLineStart - 2)) {
+ shadBitAddr += PrinceEngine::kMaxPicWidth / 8;
+ shadPosY++;
+ diffY++;
+ }
+ //no_change_y
+ if (READ_LE_UINT16(shadowLineStart) < READ_LE_UINT16(shadowLineStart - 4)) {
+ //minus_x
+ shadPosX--;
+ //rol
+ if (shadBitMask == 128) {
+ shadBitMask = 1;
+ shadBitAddr--;
+ } else {
+ shadBitMask <<= 1;
+ }
+ diffX--;
+ } else if (READ_LE_UINT16(shadowLineStart) > READ_LE_UINT16(shadowLineStart - 4)) {
+ shadPosX++;
+ //ror
+ if (shadBitMask == 1) {
+ shadBitMask = 128;
+ shadBitAddr++;
+ } else {
+ shadBitMask >>= 1;
+ }
+ diffX++;
+ }
+ //no_change_x
+ shadowLineStart += 4;
+ shadowHeroY--;
+ if (shadowHeroY < 0) {
+ break;
+ }
+ shadowHeroX = 0;
+ background = (byte *)screen->getBasePtr(shadDrawX + diffX, shadDrawY + diffY);
+ shadowHero = (byte *)makeShadow->getBasePtr(shadowHeroX, shadowHeroY);
+ }
+ //koniec_bajki - end_of_a_story
+ }
+ makeShadow->free();
+ delete makeShadow;
+}
+
+void Hero::setScale(int8 zoomBitmapValue) {
+ if (!zoomBitmapValue) {
+ _vm->_scaleValue = 10000;
+ } else {
+ _vm->_scaleValue = 10000 / zoomBitmapValue;
+ }
+}
+
+void Hero::selectZoom() {
+ int8 zoomBitmapValue = *(_vm->_zoomBitmap + _middleY / 4 * _vm->kZoomBitmapWidth + _middleX / 4);
+ setScale(zoomBitmapValue);
+}
+
+int Hero::rotateHero(int oldDirection, int newDirection) {
+ switch (oldDirection) {
+ case kHeroDirLeft:
+ switch (newDirection) {
+ case kHeroDirRight:
+ return kMove_MLR;
+ case kHeroDirUp:
+ return kMove_MLU;
+ case kHeroDirDown:
+ return kMove_MLD;
+ }
+ break;
+ case kHeroDirRight:
+ switch (newDirection) {
+ case kHeroDirLeft:
+ return kMove_MRL;
+ case kHeroDirUp:
+ return kMove_MRU;
+ case kHeroDirDown:
+ return kMove_MRD;
+ }
+ break;
+ case kHeroDirUp:
+ switch (newDirection) {
+ case kHeroDirLeft:
+ return kMove_MUL;
+ case kHeroDirRight:
+ return kMove_MUR;
+ case kHeroDirDown:
+ return kMove_MUD;
+ }
+ break;
+ case kHeroDirDown:
+ switch (newDirection) {
+ case kHeroDirLeft:
+ return kMove_MDL;
+ case kHeroDirRight:
+ return kMove_MDR;
+ case kHeroDirUp:
+ return kMove_MDU;
+ }
+ break;
+ }
+ error("rotateHero - wrong directions - old %d, new %d", oldDirection, newDirection);
+}
+
+void Hero::heroStanding() {
+ _phase = 0;
+ switch (_lastDirection) {
+ case kHeroDirLeft:
+ _moveSetType = kMove_SL;
+ break;
+ case kHeroDirRight:
+ _moveSetType = kMove_SR;
+ break;
+ case kHeroDirUp:
+ _moveSetType = kMove_SU;
+ break;
+ case kHeroDirDown:
+ _moveSetType = kMove_SD;
+ break;
+ }
+}
+
+void Hero::showHero() {
+ if (_visible && !_vm->_flags->getFlagValue(Flags::NOHEROATALL)) {
+
+ if (_talkTime != 0) {
+ _talkTime--;
+ }
+
+ // Scale of hero
+ selectZoom();
+
+ if (_state != kHeroStateStay) {
+ _boredomTime = 0;
+ }
+
+ if (_state == kHeroStateSpec) {
+ if (_specAnim != nullptr) {
+ if (_phase < _specAnim->getPhaseCount() - 1) {
+ _phase++;
+ } else {
+ if (!_talkTime) {
+ _state = kHeroStateStay;
+ } else {
+ _state = kHeroStateTalk;
+ }
+ countDrawPosition();
+ return;
+ }
+ } else {
+ _state = kHeroStateStay;
+ }
+ } else {
+ freeHeroAnim();
+ }
+
+ if (_state == kHeroStateTalk) {
+ if (_talkTime) {
+ switch (_lastDirection) {
+ case kHeroDirLeft:
+ _moveSetType = kMove_TL;
+ break;
+ case kHeroDirRight:
+ _moveSetType = kMove_TR;
+ break;
+ case kHeroDirUp:
+ _moveSetType = kMove_TU;
+ break;
+ case kHeroDirDown:
+ _moveSetType = kMove_TD;
+ break;
+ }
+ if (_phase < _moveSet[_moveSetType]->getPhaseCount() - 1) {
+ _phase++;
+ } else {
+ _phase = _moveSet[_moveSetType]->getLoopCount();
+ }
+ } else {
+ _state = kHeroStateStay;
+ }
+ }
+
+ if (_state == kHeroStateBore) {
+ switch (_boreNum) {
+ case 0:
+ _moveSetType = kMove_BORED1;
+ break;
+ case 1:
+ _moveSetType = kMove_BORED2;
+ break;
+ }
+ if (_moveSet[_moveSetType] != nullptr) {
+ if (_phase < _moveSet[_moveSetType]->getPhaseCount() - 1) {
+ _phase++;
+ } else {
+ _phase = 0;
+ _lastDirection = kHeroDirDown;
+ _state = kHeroStateStay;
+ }
+ } else {
+ _state = kHeroStateStay;
+ }
+ }
+
+ if (_state == kHeroStateStay) {
+ if (!_vm->_optionsFlag) {
+ if (!_vm->_interpreter->getLastOPCode() || !_vm->_interpreter->getFgOpcodePC()) {
+ _boredomTime++;
+ if (_boredomTime == _maxBoredom) {
+ _boreNum =_vm->_randomSource.getRandomNumber(1); // rand one of two 'bored' animation
+ _phase = 0;
+ _state = kHeroStateBore;
+ if (_lastDirection == kHeroDirUp) {
+ _lastDirection = kHeroDirLeft;
+ } else {
+ _lastDirection = kHeroDirDown;
+ }
+ }
+ } else {
+ _boredomTime = 0;
+ }
+ } else {
+ _boredomTime = 0;
+ }
+ heroStanding();
+ }
+
+ if (_state == kHeroStateTurn) {
+ if (_destDirection && (_lastDirection != _destDirection)) {
+ _phase = 0;
+ int rotateDir = rotateHero(_lastDirection, _destDirection);
+ _lastDirection = _destDirection;
+ if (rotateDir) {
+ _moveSetType = rotateDir;
+ _state = kHeroStateTran;
+ } else {
+ _state = kHeroStateStay;
+ heroStanding();
+ }
+ } else {
+ _state = kHeroStateStay;
+ heroStanding();
+ }
+ }
+
+ if (_state == kHeroStateTran) {
+ if (_moveSet[_moveSetType] != nullptr) {
+ // only in bear form
+ if (_phase < _moveSet[_moveSetType]->getPhaseCount() - 2) {
+ _phase += 2;
+ } else {
+ _state = kHeroStateStay;
+ heroStanding();
+ }
+ } else {
+ _state = kHeroStateStay;
+ heroStanding();
+ }
+ }
+
+ if (_state == kHeroStateMvan) {
+ if (_moveSet[_moveSetType] != nullptr) {
+ // only in bear form
+ if (_phase < _moveSet[_moveSetType]->getPhaseCount() - 2) {
+ _phase += 2;
+ } else {
+ _state = kHeroStateMove;
+ }
+ } else {
+ _state = kHeroStateMove;
+ }
+ }
+
+ if (_state == kHeroStateDelayMove) {
+ _moveDelay--;
+ if (!_moveDelay) {
+ _state = kHeroStateMove;
+ }
+ }
+
+ if (_state == kHeroStateMove || _state == kHeroStateRun) {
+ //go_for_it:
+ while (1) {
+ if (_currCoords != nullptr) {
+ if (READ_LE_UINT32(_currCoords) != 0xFFFFFFFF) {
+ int x = READ_LE_UINT16(_currCoords);
+ int y = READ_LE_UINT16(_currCoords + 2);
+ _currCoords += 4;
+ int dir = *_currDirTab;
+ _currDirTab++;
+ if (_lastDirection != dir) {
+ _phase = 0;
+ int rotateDir = rotateHero(_lastDirection, dir);
+ _lastDirection = dir;
+ if (_moveSet[rotateDir] != nullptr) {
+ // only in bear form
+ _state = kHeroStateMvan;
+ _moveSetType = rotateDir;
+ if (_phase < _moveSet[_moveSetType]->getPhaseCount() - 2) {
+ _phase += 2;
+ break;
+ } else {
+ _state = kHeroStateMove;
+ continue;
+ }
+ } else {
+ continue;
+ }
+ }
+ //no_need_direction_change
+ if (dir == kHeroDirLeft) {
+ if (_middleX - x >= _step) {
+ heroMoveGotIt(x, y, dir);
+ break;
+ }
+ } else if (dir == kHeroDirRight) {
+ if (x - _middleX >= _step) {
+ heroMoveGotIt(x, y, dir);
+ break;
+ }
+ } else if (dir == kHeroDirUp) {
+ if (_middleY - y >= _step) {
+ heroMoveGotIt(x, y, dir);
+ break;
+ }
+ } else if (dir == kHeroDirDown) {
+ if (y - _middleY >= _step) {
+ heroMoveGotIt(x, y, dir);
+ break;
+ }
+ }
+ } else {
+ //finito
+ _middleX = READ_LE_UINT16(_currCoords - 4);
+ _middleY = READ_LE_UINT16(_currCoords - 2);
+ selectZoom();
+
+ if (_coords != nullptr) {
+ free(_coords);
+ _coords = nullptr;
+ _currCoords = nullptr;
+ }
+
+ if (_dirTab != nullptr) {
+ free(_dirTab);
+ _dirTab = nullptr;
+ _currDirTab = nullptr;
+ }
+
+ _boredomTime = 0;
+ _phase = 0;
+ _state = kHeroStateTurn;
+
+ if (!_destDirection) {
+ _destDirection = _lastDirection;
+ }
+
+ heroStanding();
+
+ break;
+ }
+ } else {
+ heroStanding();
+ break;
+ }
+ }
+ }
+ countDrawPosition();
+ }
+}
+
+void Hero::drawHero() {
+ if (_visible && !_vm->_flags->getFlagValue(Flags::NOHEROATALL)) {
+ freeZoomedSurface();
+ Graphics::Surface *mainHeroSurface = getSurface();
+ if (mainHeroSurface) {
+ DrawNode newDrawNode;
+ newDrawNode.posX = _drawX;
+ newDrawNode.posY = _drawY;
+ newDrawNode.posZ = _drawZ;
+ newDrawNode.width = 0;
+ newDrawNode.height = 0;
+ newDrawNode.originalRoomSurface = nullptr;
+ newDrawNode.data = _vm->_transTable;
+ newDrawNode.drawFunction = &_graph->drawTransparentWithTransDrawNode;
+
+ if (_vm->_scaleValue != 10000) {
+ _zoomedHeroSurface = zoomSprite(mainHeroSurface);
+ newDrawNode.s = _zoomedHeroSurface;
+ } else {
+ newDrawNode.s = mainHeroSurface;
+ }
+ _vm->_drawNodeList.push_back(newDrawNode);
+
+ drawHeroShadow(mainHeroSurface);
+
+ }
+ }
+}
+
+void Hero::drawHeroShadow(Graphics::Surface *heroFrame) {
+ DrawNode newDrawNode;
+ newDrawNode.posX = _middleX - _scaledFrameXSize / 2;
+ newDrawNode.posY = _middleY - _shadMinus - 1;
+ newDrawNode.posZ = kHeroShadowZ;
+ newDrawNode.width = 0;
+ newDrawNode.height = 0;
+ newDrawNode.scaleValue = _vm->_scaleValue;
+ newDrawNode.originalRoomSurface = nullptr;
+ newDrawNode.data = _vm;
+ newDrawNode.drawFunction = &showHeroShadow;
+ newDrawNode.s = heroFrame;
+ _vm->_drawNodeList.push_back(newDrawNode);
+}
+
+void Hero::heroMoveGotIt(int x, int y, int dir) {
+ _middleX = x;
+ _middleY = y;
+ selectZoom();
+
+ switch (dir) {
+ case kHeroDirLeft:
+ _moveSetType = kMove_ML;
+ break;
+ case kHeroDirRight:
+ _moveSetType = kMove_MR;
+ break;
+ case kHeroDirUp:
+ _moveSetType = kMove_MU;
+ break;
+ case kHeroDirDown:
+ _moveSetType = kMove_MD;
+ break;
+ }
+
+ if (_vm->_flags->getFlagValue(Flags::HEROFAST) || _state == kHeroStateRun) {
+ if (_phase < _moveSet[_moveSetType]->getPhaseCount() - 2) {
+ _phase += 2;
+ } else {
+ _phase = 0;
+ }
+ } else {
+ if (_phase < _moveSet[_moveSetType]->getPhaseCount() - 1) {
+ _phase++;
+ } else {
+ _phase = 0;
+ }
+ }
+
+ _step = kStepLeftRight;
+ if (_moveSetType == kMove_MU || _moveSetType == kMove_MD) {
+ _step = kStepUpDown;
+ }
+ if (_vm->_flags->getFlagValue(Flags::HEROFAST)) {
+ _step *= 2.5;
+ } else if (_state == kHeroStateRun) {
+ _step *= 2;
+ }
+}
+
+void Hero::scrollHero() {
+ int scrollType = _vm->_flags->getFlagValue(Flags::SCROLLTYPE);
+ int position = _middleX;
+ int scrollValue, scrollValue2;
+
+ switch (scrollType) {
+ case 0:
+ position = _middleX;
+ break;
+ case 1:
+ scrollValue = _vm->_flags->getFlagValue(Flags::SCROLLVALUE);
+ position = _vm->_normAnimList[scrollValue]._currX + _vm->_normAnimList[scrollValue]._currW / 2;
+ break;
+ case 2:
+ scrollValue = _vm->_flags->getFlagValue(Flags::SCROLLVALUE);
+ scrollValue2 = _vm->_flags->getFlagValue(Flags::SCROLLVALUE2);
+ position = scrollValue;
+ if (scrollValue < scrollValue2) {
+ _vm->_flags->setFlagValue(Flags::SCROLLVALUE, 0);
+ } else {
+ _vm->_flags->setFlagValue(Flags::SCROLLVALUE, scrollValue - scrollValue2);
+ }
+ break;
+ }
+
+ int locationWidth = _vm->_sceneWidth;
+ int difference = locationWidth - _vm->kNormalWidth / 2;
+
+ int destValue = 0;
+ if (position > _vm->kNormalWidth / 2) {
+ destValue = difference - _vm->kNormalWidth / 2;
+ }
+ if (position < difference) {
+ destValue = position - _vm->kNormalWidth / 2;
+ }
+
+ if(destValue < 0) {
+ destValue = 0;
+ }
+ _vm->_picWindowX = destValue;
+ _drawX -= destValue;
+}
+
+void Hero::freeOldMove() {
+ if (_coords != nullptr) {
+ free(_coords);
+ _coords = nullptr;
+ }
+ if (_dirTab != nullptr) {
+ free(_dirTab);
+ _dirTab = nullptr;
+ }
+ _step = 0;
+ _phase = 0;
+ _moveDelay = 0;
+ _state = Hero::kHeroStateStay;
+}
+
+void Hero::freeHeroAnim() {
+ if (_specAnim != nullptr) {
+ delete _specAnim;
+ _specAnim = nullptr;
+ }
+}
+
+void Hero::freeZoomedSurface() {
+ if (_zoomedHeroSurface != nullptr) {
+ _zoomedHeroSurface->free();
+ delete _zoomedHeroSurface;
+ _zoomedHeroSurface = nullptr;
+ }
+}
+
+} // End of namespace Prince
diff --git a/engines/prince/hero.h b/engines/prince/hero.h
new file mode 100644
index 0000000000..703ef0650d
--- /dev/null
+++ b/engines/prince/hero.h
@@ -0,0 +1,184 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef PRINCE_HERO_H
+#define PRINCE_HERO_H
+
+#include "common/scummsys.h"
+#include "common/array.h"
+#include "common/memstream.h"
+
+#include "graphics/surface.h"
+#include "graphics/primitives.h"
+
+namespace Prince {
+
+class Animation;
+class PrinceEngine;
+class GraphicsMan;
+struct InventoryItem;
+struct DrawNode;
+
+class Hero {
+public:
+ static const uint32 kMoveSetSize = 26;
+ static const int16 kStepLeftRight = 8;
+ static const int16 kStepUpDown = 4;
+ static const int16 kHeroShadowZ = 2;
+
+ enum State {
+ kHeroStateStay,
+ kHeroStateTurn,
+ kHeroStateMove,
+ kHeroStateBore,
+ kHeroStateSpec,
+ kHeroStateTalk,
+ kHeroStateMvan,
+ kHeroStateTran,
+ kHeroStateRun,
+ kHeroStateDelayMove
+ };
+
+ enum Direction {
+ kHeroDirLeft = 1,
+ kHeroDirRight = 2,
+ kHeroDirUp = 3,
+ kHeroDirDown = 4
+ };
+
+ enum MoveSet {
+ kMove_SL,
+ kMove_SR,
+ kMove_SU,
+ kMove_SD,
+ kMove_ML,
+ kMove_MR,
+ kMove_MU,
+ kMove_MD,
+ kMove_TL,
+ kMove_TR,
+ kMove_TU,
+ kMove_TD,
+ kMove_MLU,
+ kMove_MLD,
+ kMove_MLR,
+ kMove_MRU,
+ kMove_MRD,
+ kMove_MRL,
+ kMove_MUL,
+ kMove_MUR,
+ kMove_MUD,
+ kMove_MDL,
+ kMove_MDR,
+ kMove_MDU,
+ kMove_BORED1,
+ kMove_BORED2
+ };
+
+ // Used instead of offset in getData
+ enum AttrId {
+ kHeroLastDir = 26,
+ kHeroAnimSet = 120
+ };
+
+ uint16 getData(AttrId dataId);
+
+ Hero(PrinceEngine *vm, GraphicsMan *graph);
+ ~Hero();
+ bool loadAnimSet(uint32 heroAnimNumber);
+
+ Graphics::Surface *getSurface();
+
+ void setPos(int16 x, int16 y) { _middleX = x; _middleY = y; }
+ void setVisible(bool flag) { _visible = flag; }
+
+ void showHero();
+ void drawHero();
+ void freeZoomedSurface();
+ void heroStanding();
+ void heroMoveGotIt(int x, int y, int dir);
+ int rotateHero(int oldDirection, int newDirection);
+ void scrollHero();
+ void setScale(int8 zoomBitmapValue);
+ int getScaledValue(int size);
+ void selectZoom();
+ void countDrawPosition();
+ Graphics::Surface *zoomSprite(Graphics::Surface *heroFrame);
+ void line(int x1, int y1, int x2, int y2);
+ void plotPoint(int x, int y);
+ static void showHeroShadow(Graphics::Surface *screen, DrawNode *drawNode);
+ void drawHeroShadow(Graphics::Surface *heroFrame);
+ void freeOldMove();
+ void freeHeroAnim();
+
+ uint16 _number;
+ uint16 _visible;
+ int16 _state;
+ int16 _middleX; // middle of X
+ int16 _middleY; // lower part of hero
+ int16 _moveSetType;
+
+ int16 _frameXSize;
+ int16 _frameYSize;
+ int16 _scaledFrameXSize;
+ int16 _scaledFrameYSize;
+ int16 _drawX;
+ int16 _drawY;
+ int16 _drawZ;
+
+ byte *_coords; // array of coordinates
+ byte *_dirTab; // array of directions
+ byte *_currCoords; // current coordinations
+ byte *_currDirTab; // current direction
+ int16 _lastDirection; // previous move direction
+ int16 _destDirection;
+ int16 _leftRightMainDir; // left or right - dominant direction
+ int16 _upDownMainDir; // up or down - dominant direction
+ int32 _phase; // Phase animation phase
+ int16 _step; // Step x/y step size depends on direction
+ int16 _maxBoredom; // stand still timeout
+ int16 _boredomTime; // Boredom current boredom time in frames
+ uint16 _boreNum; // Bore anim frame
+ int16 _talkTime; // TalkTime time of talk anim
+ Animation *_specAnim; // additional anim
+ Graphics::Surface *_zoomedHeroSurface;
+
+ uint16 _currHeight; // height of current anim phase
+
+ Common::Array<byte> _inventory; // Inventory array of items
+ Common::Array<byte> _inventory2; // Inventory2 array of items
+ // Font subtitiles font
+ int _color; // subtitles color
+ uint32 _animSetNr; // number of animation set
+ Common::Array<Animation *> _moveSet; // MoveAnims MoveSet
+
+ uint32 _moveDelay;
+ uint32 _shadMinus;
+
+private:
+ PrinceEngine *_vm;
+ GraphicsMan *_graph;
+};
+
+} // End of namespace Prince
+
+#endif
diff --git a/engines/prince/hero_set.h b/engines/prince/hero_set.h
new file mode 100644
index 0000000000..dfe7e50268
--- /dev/null
+++ b/engines/prince/hero_set.h
@@ -0,0 +1,244 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "common/scummsys.h"
+
+namespace Prince {
+
+const int heroSetBack[7] = { 0, 0, 10, 0, 6, 0, 0 };
+
+typedef const char *HeroSetAnimNames[26];
+
+static HeroSetAnimNames heroSet5 = {
+ "SL_DIAB.ANI",
+ "SR_DIAB.ANI",
+ "SU_DIAB.ANI",
+ "SD_DIAB.ANI",
+ nullptr,
+ nullptr,
+ "MU_DIAB.ANI",
+ "MD_DIAB.ANI",
+ "TL_DIAB.ANI",
+ "TR_DIAB.ANI",
+ "TU_DIAB.ANI",
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr
+};
+
+static HeroSetAnimNames heroSet1 = {
+ "SL_HERO1.ANI",
+ "SR_HERO1.ANI",
+ "SU_HERO1.ANI",
+ "SD_HERO1.ANI",
+ "ML_HERO1.ANI",
+ "MR_HERO1.ANI",
+ "MU_HERO1.ANI",
+ "MD_HERO1.ANI",
+ "TL_HERO1.ANI",
+ "TR_HERO1.ANI",
+ "TU_HERO1.ANI",
+ "TD_HERO1.ANI",
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ "KSI_KURZ.ANI",
+ "KS_WLOSY.ANI"
+};
+
+static HeroSetAnimNames heroSet2 = {
+ "SL_HERO2.ANI",
+ "SR_HERO2.ANI",
+ "SU_HERO2.ANI",
+ "SD_HERO2.ANI",
+ "ML_HERO2.ANI",
+ "MR_HERO2.ANI",
+ "MU_HERO2.ANI",
+ "MD_HERO2.ANI",
+ "TL_HERO2.ANI",
+ "TR_HERO2.ANI",
+ "TU_HERO2.ANI",
+ "TD_HERO2.ANI",
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ "KSI_KU_S.ANI",
+ "KS_WLO_S.ANI"
+};
+
+static HeroSetAnimNames heroSet3 = {
+ "SL_BEAR.ANI",
+ "SR_BEAR.ANI",
+ "SU_BEAR.ANI",
+ "SD_BEAR.ANI",
+ "NIED-LEW.ANI",
+ "NIED-PRW.ANI",
+ "NIED-TYL.ANI",
+ "NIED-PRZ.ANI",
+ "SL_BEAR.ANI",
+ "SR_BEAR.ANI",
+ "SU_BEAR.ANI",
+ "SD_BEAR.ANI",
+ "N_LW-TYL.ANI",
+ "N_LW-PRZ.ANI",
+ "N_LW-PR.ANI",
+ "N_PR-TYL.ANI",
+ "N_PR-PRZ.ANI",
+ "N_PR-LW.ANI",
+ "N_TYL-LW.ANI",
+ "N_TYL-PR.ANI",
+ "N_TL-PRZ.ANI",
+ "N_PRZ-LW.ANI",
+ "N_PRZ-PR.ANI",
+ "N_PRZ-TL.ANI",
+ nullptr,
+ nullptr,
+};
+
+static HeroSetAnimNames shanSet1 = {
+ "SL_SHAN.ANI",
+ "SR_SHAN.ANI",
+ "SU_SHAN.ANI",
+ "SD_SHAN.ANI",
+ "ML_SHAN.ANI",
+ "MR_SHAN.ANI",
+ "MU_SHAN.ANI",
+ "MD_SHAN.ANI",
+ "TL_SHAN.ANI",
+ "TR_SHAN.ANI",
+ "TU_SHAN.ANI",
+ "TD_SHAN.ANI",
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ "B1_SHAN.ANI",
+ "B2_SHAN.ANI",
+};
+
+static HeroSetAnimNames shanSet2 = {
+ "SL_SHAN2.ANI",
+ "SR_SHAN2.ANI",
+ "SU_SHAN.ANI",
+ "SD_SHAN2.ANI",
+ "ML_SHAN2.ANI",
+ "MR_SHAN2.ANI",
+ "MU_SHAN.ANI",
+ "MD_SHAN2.ANI",
+ "TL_SHAN2.ANI",
+ "TR_SHAN2.ANI",
+ "TU_SHAN.ANI",
+ "TD_SHAN2.ANI",
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ "B1_SHAN2.ANI",
+ "B2_SHAN2.ANI"
+};
+
+static HeroSetAnimNames arivSet1 = {
+ "SL_ARIV.ANI",
+ "SR_ARIV.ANI",
+ "SU_ARIV.ANI",
+ "SD_ARIV.ANI",
+ "ML_ARIV.ANI",
+ "MR_ARIV.ANI",
+ "MU_ARIV.ANI",
+ "MD_ARIV.ANI",
+ "TL_ARIV.ANI",
+ "TR_ARIV.ANI",
+ "TU_ARIV.ANI",
+ "TD_ARIV.ANI",
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr
+};
+
+const HeroSetAnimNames *heroSetTable[7] = {
+ &heroSet1,
+ &heroSet2,
+ &heroSet3,
+ &shanSet1,
+ &arivSet1,
+ &heroSet5,
+ &shanSet2,
+};
+
+} // End of namespace Prince
diff --git a/engines/prince/mhwanh.cpp b/engines/prince/mhwanh.cpp
new file mode 100644
index 0000000000..608ccc23d7
--- /dev/null
+++ b/engines/prince/mhwanh.cpp
@@ -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.
+ *
+ */
+
+#include "common/stream.h"
+
+#include "graphics/surface.h"
+
+#include "prince/mhwanh.h"
+
+namespace Prince {
+
+MhwanhDecoder::MhwanhDecoder() : _surface(nullptr), _palette(nullptr) {
+}
+
+MhwanhDecoder::~MhwanhDecoder() {
+ destroy();
+}
+
+void MhwanhDecoder::destroy() {
+ if (_surface != nullptr) {
+ _surface->free();
+ delete _surface;
+ _surface = nullptr;
+ }
+ if (_palette != nullptr) {
+ free(_palette);
+ _palette = nullptr;
+ }
+}
+
+bool MhwanhDecoder::loadStream(Common::SeekableReadStream &stream) {
+ destroy();
+ stream.seek(0);
+ stream.skip(0x20);
+ // Read the palette
+ _palette = (byte *)malloc(kPaletteColorCount * 3);
+ for (uint16 i = 0; i < kPaletteColorCount; i++) {
+ _palette[i * 3] = stream.readByte();
+ _palette[i * 3 + 1] = stream.readByte();
+ _palette[i * 3 + 2] = stream.readByte();
+ }
+
+ _surface = new Graphics::Surface();
+ _surface->create(640, 480, Graphics::PixelFormat::createFormatCLUT8());
+ for (int h = 0; h < 480; h++) {
+ stream.read(_surface->getBasePtr(0, h), 640);
+ }
+
+ return true;
+}
+
+} // End of namespace Prince
diff --git a/engines/prince/mhwanh.h b/engines/prince/mhwanh.h
new file mode 100644
index 0000000000..f8165a7666
--- /dev/null
+++ b/engines/prince/mhwanh.h
@@ -0,0 +1,55 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public 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 PRINCE_MHWANH_H
+#define PRINCE_MHWANH_H
+
+#include "image/image_decoder.h"
+#include "image/bmp.h"
+
+#include "graphics/surface.h"
+
+#include "resource.h"
+
+namespace Prince {
+
+class MhwanhDecoder : public Image::ImageDecoder {
+public:
+ MhwanhDecoder();
+ virtual ~MhwanhDecoder();
+
+ // ImageDecoder API
+ void destroy();
+ virtual bool loadStream(Common::SeekableReadStream &stream);
+ virtual Graphics::Surface *getSurface() const { return _surface; }
+ virtual const byte *getPalette() const { return _palette; }
+ uint16 getPaletteCount() const { return kPaletteColorCount; }
+ static const uint16 kPaletteColorCount = 256;
+
+private:
+ Graphics::Surface *_surface;
+ byte *_palette;
+};
+
+} // End of namespace Prince
+
+#endif
diff --git a/engines/prince/mob.cpp b/engines/prince/mob.cpp
new file mode 100644
index 0000000000..de825ef8b2
--- /dev/null
+++ b/engines/prince/mob.cpp
@@ -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.
+ *
+ */
+
+#include "prince/mob.h"
+
+namespace Prince {
+
+bool Mob::loadFromStream(Common::SeekableReadStream &stream) {
+ int32 pos = stream.pos();
+
+ uint16 visible = stream.readUint16LE();
+
+ if (visible == 0xFFFF)
+ return false;
+
+ _visible = visible;
+ _type = stream.readUint16LE();
+ _rect.left = stream.readUint16LE();
+ _rect.top = stream.readUint16LE();
+ _rect.right = stream.readUint16LE();
+ _rect.bottom = stream.readUint16LE();
+
+ _mask = stream.readUint16LE();
+
+ _examPosition.x = stream.readUint16LE();
+ _examPosition.y = stream.readUint16LE();
+ _examDirection = (Direction)stream.readUint16LE();
+
+ _usePosition.x = stream.readByte();
+ _usePosition.y = stream.readByte();
+ _useDirection = (Direction)stream.readUint16LE();
+
+ uint32 nameOffset = stream.readUint32LE();
+ uint32 examTextOffset = stream.readUint32LE();
+
+ byte c;
+ stream.seek(nameOffset);
+ _name.clear();
+ while ((c = stream.readByte()))
+ _name += c;
+
+ stream.seek(examTextOffset);
+ _examText.clear();
+ c = stream.readByte();
+ if (c) {
+ _examText += c;
+ do {
+ c = stream.readByte();
+ _examText += c;
+ } while (c != 255);
+ }
+ stream.seek(pos + 32);
+
+ return true;
+}
+
+void Mob::setData(AttrId dataId, uint16 value) {
+ switch (dataId) {
+ case kMobExamDir:
+ _examDirection = (Direction)value;
+ break;
+ case kMobExamX:
+ _examPosition.x = value;
+ break;
+ case kMobExamY:
+ _examPosition.y = value;
+ break;
+ default:
+ assert(false);
+ }
+}
+
+uint16 Mob::getData(AttrId dataId) {
+ switch (dataId) {
+ case kMobVisible:
+ return _visible;
+ case kMobExamDir:
+ return _examDirection;
+ case kMobExamX:
+ return _examPosition.x;
+ case kMobExamY:
+ return _examPosition.y;
+ default:
+ assert(false);
+ return 0;
+ }
+}
+
+} // End of namespace Prince
diff --git a/engines/prince/mob.h b/engines/prince/mob.h
new file mode 100644
index 0000000000..0ea610dd8f
--- /dev/null
+++ b/engines/prince/mob.h
@@ -0,0 +1,70 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef PRINCE_MOB_H
+#define PRINCE_MOB_H
+
+#include "common/scummsys.h"
+#include "common/rect.h"
+#include "common/str.h"
+#include "common/stream.h"
+
+#include "prince/common.h"
+
+namespace Prince {
+
+class Mob {
+public:
+
+ Mob() : _name(""), _examText("") {}
+
+ bool loadFromStream(Common::SeekableReadStream &stream);
+
+ // Used instead of offset in setData and getData
+ enum AttrId {
+ kMobVisible = 0,
+ kMobExamX = 14,
+ kMobExamY = 16,
+ kMobExamDir = 18
+ };
+
+ void setData(AttrId dataId, uint16 value);
+ uint16 getData(AttrId dataId);
+
+ bool _visible;
+ uint16 _type;
+ uint16 _mask;
+ Common::Rect _rect;
+
+ Common::Point _examPosition;
+ Direction _examDirection;
+
+ Common::Point _usePosition;
+ Direction _useDirection;
+
+ Common::String _name;
+ Common::String _examText;
+};
+
+} // End of namespace Prince
+
+#endif
diff --git a/engines/prince/module.mk b/engines/prince/module.mk
new file mode 100644
index 0000000000..b1be123d4b
--- /dev/null
+++ b/engines/prince/module.mk
@@ -0,0 +1,30 @@
+MODULE := engines/prince
+
+MODULE_OBJS = \
+ animation.o \
+ archive.o \
+ cursor.o \
+ debugger.o \
+ decompress.o \
+ detection.o \
+ flags.o \
+ font.o \
+ graphics.o \
+ hero.o \
+ mhwanh.o \
+ mob.o \
+ object.o \
+ prince.o \
+ pscr.o \
+ saveload.o \
+ script.o \
+ sound.o \
+ variatxt.o
+
+# This module can be built as a plugin
+ifeq ($(ENABLE_PRINCE), DYNAMIC_PLUGIN)
+PLUGIN := 1
+endif
+
+# Include common rules
+include $(srcdir)/rules.mk
diff --git a/engines/prince/musNum.h b/engines/prince/musNum.h
new file mode 100644
index 0000000000..c24cba6ad7
--- /dev/null
+++ b/engines/prince/musNum.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.
+ *
+ */
+
+namespace Prince {
+
+enum RoomMus {
+ ROOM01MUS = 3,
+ ROOM02MUS = 9,
+ ROOM03MUS = 9,
+ ROOM04MUS = 9,
+ ROOM05MUS = 13,
+ ROOM06MUS = 9,
+ ROOM07MUS = 9,
+ ROOM08MUS = 9,
+ ROOM09MUS = 14,
+ ROOM10MUS = 9,
+ ROOM11MUS = 9,
+ ROOM12MUS = 9,
+ ROOM13MUS = 9,
+ ROOM14MUS = 9,
+ ROOM15MUS = 5,
+ ROOM16MUS = 5,
+ ROOM17MUS = 5,
+ ROOM18MUS = 5,
+ ROOM19MUS = 5,
+ ROOM20MUS = 12,
+ ROOM21MUS = 9,
+ ROOM22MUS = 9,
+ ROOM23MUS = 1,
+ ROOM24MUS = 1,
+ ROOM25MUS = 2,
+ ROOM26MUS = 10,
+ ROOM27MUS = 7,
+ ROOM28MUS = 10,
+ ROOM29MUS = 10,
+ ROOM30MUS = 11,
+ ROOM31MUS = 14,
+ ROOM32MUS = 11,
+ ROOM33MUS = 7,
+ ROOM34MUS = 7,
+ ROOM35MUS = 7,
+ ROOM36MUS = 7,
+ ROOM37MUS = 7,
+ ROOM38MUS = 7,
+ ROOM39MUS = 7,
+ ROOM40MUS = 7,
+ ROOM41MUS = 7,
+ ROOM42MUS = 7,
+ ROOM43MUS = 15,
+ ROOM46MUS = 100,
+ ROOM47MUS = 100,
+ ROOM48MUS = 100,
+ ROOM49MUS = 100,
+ ROOM50MUS = 100,
+ ROOM51MUS = 12,
+ ROOM52MUS = 9,
+ ROOM53MUS = 5,
+ ROOM54MUS = 11,
+ ROOM55MUS = 11,
+ ROOM56MUS = 11,
+ ROOM57MUS = 7,
+ ROOM58MUS = 13,
+ ROOM59MUS = 16,
+ ROOM60MUS = 4,
+ ROOM61MUS = 0
+};
+
+} // End of namespace Prince
diff --git a/engines/prince/object.cpp b/engines/prince/object.cpp
new file mode 100644
index 0000000000..2dc5da68e7
--- /dev/null
+++ b/engines/prince/object.cpp
@@ -0,0 +1,113 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "common/archive.h"
+#include "common/debug-channels.h"
+#include "common/debug.h"
+#include "common/stream.h"
+
+#include "graphics/surface.h"
+
+#include "prince/object.h"
+
+namespace Prince {
+
+Object::Object() : _surface(nullptr), _x(0), _y(0), _z(0), _flags(0), _width(0),
+ _height(0), _zoomTime(0), _zoomSurface(nullptr)
+{
+}
+
+Object::~Object() {
+ if (_surface != nullptr) {
+ _surface->free();
+ delete _surface;
+ _surface = nullptr;
+ }
+ if (_zoomSurface != nullptr) {
+ _zoomSurface->free();
+ delete _zoomSurface;
+ _zoomSurface = nullptr;
+ }
+}
+
+void Object::loadSurface(Common::SeekableReadStream &stream) {
+ stream.skip(4);
+ _width = stream.readUint16LE();
+ _height = stream.readUint16LE();
+ _surface = new Graphics::Surface();
+ _surface->create(_width, _height, Graphics::PixelFormat::createFormatCLUT8());
+
+ for (int h = 0; h < _surface->h; h++) {
+ stream.read(_surface->getBasePtr(0, h), _surface->w);
+ }
+}
+
+bool Object::loadFromStream(Common::SeekableReadStream &stream) {
+ int32 pos = stream.pos();
+ uint16 x = stream.readUint16LE();
+ if (x == 0xFFFF) {
+ return false;
+ }
+ _x = x;
+ _y = stream.readSint16LE(); // skull mini-game has some signed y coords
+
+ const Common::String obStreamName = Common::String::format("OB%02d", stream.readUint16LE());
+ Common::SeekableReadStream *obStream = SearchMan.createReadStreamForMember(obStreamName);
+ if (obStream) {
+ loadSurface(*obStream);
+ }
+ delete obStream;
+
+ _flags = stream.readUint16LE();
+ _z = stream.readUint16LE();
+
+ stream.seek(pos + 16);
+
+ return true;
+}
+
+void Object::setData(AttrId dataId, int32 value) {
+ switch (dataId) {
+ case kObjectX:
+ _x = value;
+ break;
+ case kObjectY:
+ _y = value;
+ break;
+ default:
+ assert(false);
+ }
+}
+
+int32 Object::getData(AttrId dataId) {
+ switch (dataId) {
+ case kObjectX:
+ return _x;
+ case kObjectY:
+ return _y;
+ default:
+ assert(false);
+ return 0;
+ }
+}
+
+} // End of namespace Prince
diff --git a/engines/prince/object.h b/engines/prince/object.h
new file mode 100644
index 0000000000..ff22a05805
--- /dev/null
+++ b/engines/prince/object.h
@@ -0,0 +1,70 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef PRINCE_OBJECT_H
+#define PRINCE_OBJECT_H
+
+#include "image/image_decoder.h"
+#include "graphics/surface.h"
+
+namespace Prince {
+
+class Object {
+public:
+ Object();
+ ~Object();
+
+ int32 _x;
+ int32 _y;
+ int32 _z;
+ uint16 _width;
+ uint16 _height;
+ int32 _flags;
+ int32 _zoomTime;
+ Graphics::Surface *_zoomSurface;
+
+ // Used instead of offset in setData and getData
+ enum AttrId {
+ kObjectAddr = 0,
+ kObjectX = 4,
+ kObjectY = 6,
+ kObjectZ = 8,
+ kObjectFlags = 10,
+ kObjectZoomInSource = 12,
+ kObjectZoomInLen = 16,
+ kObjectZoomInAddr = 20,
+ kObjectZoomInTime = 24
+ };
+
+ bool loadFromStream(Common::SeekableReadStream &stream);
+ Graphics::Surface *getSurface() const { return _surface; }
+ int32 getData(AttrId dataId);
+ void setData(AttrId dataId, int32 value);
+
+private:
+ void loadSurface(Common::SeekableReadStream &stream);
+ Graphics::Surface *_surface;
+};
+
+} // End of namespace Prince
+
+#endif
diff --git a/engines/prince/option_text.h b/engines/prince/option_text.h
new file mode 100644
index 0000000000..d4d214c98c
--- /dev/null
+++ b/engines/prince/option_text.h
@@ -0,0 +1,85 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+namespace Prince {
+
+// PL - Mazovia coding
+const char invOptionsTextPL[5][18] = {
+ "Obejrzyj",
+ "U\xa7""yj",
+ "Otw\xa2""rz/Pchnij",
+ "Zamknij/Poci\x86""gnij",
+ "Daj"
+};
+
+const char optionsTextPL[7][18] = {
+ "Podejd\xa6",
+ "Obejrzyj",
+ "Zabierz",
+ "U\xa7""yj",
+ "Otw\xa2""rz/Pchnij",
+ "Zamknij/Poci\x86""gnij",
+ "Porozmawiaj"
+};
+
+// DE - Other font then for PL + ISO 8859-2 or Windows-1250
+// + special letter values changing
+// Normal value: 196, 214, 220, 223, 228, 246, 252
+// Prince change: 131, 132, 133, 127, 128, 129, 130
+char invOptionsTextDE[5][17] = {
+ "Anschauen",
+ "Benutzen",
+ "\x84""ffnen/Sto\x7f""en",
+ "Schlie\x7f""en/Ziehen",
+ "Geben"
+};
+
+const char optionsTextDE[7][17] = {
+ "Hingehen",
+ "Anschauen",
+ "Wegnehmen",
+ "Benutzen",
+ "\x84""ffnen/Sto\x7f""en",
+ "Schlie\x7f""en/Ziehen",
+ "Ansprechen"
+};
+
+// EN
+const char *invOptionsTextEN[] = {
+ "Examine",
+ "Use",
+ "Open/Push",
+ "Close/Pull",
+ "Give"
+};
+
+const char *optionsTextEN[] = {
+ "Walk to",
+ "Examine",
+ "Pick up",
+ "Use",
+ "Open/Push",
+ "Close/Pull",
+ "Talk to"
+};
+
+} // End of namespace Prince
diff --git a/engines/prince/prince.cpp b/engines/prince/prince.cpp
new file mode 100644
index 0000000000..55f12a6560
--- /dev/null
+++ b/engines/prince/prince.cpp
@@ -0,0 +1,4846 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "common/scummsys.h"
+#include "common/config-manager.h"
+#include "common/debug-channels.h"
+#include "common/debug.h"
+#include "common/events.h"
+#include "common/file.h"
+#include "common/random.h"
+#include "common/fs.h"
+#include "common/keyboard.h"
+#include "common/substream.h"
+#include "common/str.h"
+
+#include "graphics/cursorman.h"
+#include "graphics/surface.h"
+#include "graphics/palette.h"
+#include "graphics/pixelformat.h"
+
+#include "engines/util.h"
+#include "engines/advancedDetector.h"
+
+#include "audio/audiostream.h"
+
+#include "prince/prince.h"
+#include "prince/font.h"
+#include "prince/graphics.h"
+#include "prince/script.h"
+#include "prince/debugger.h"
+#include "prince/object.h"
+#include "prince/mob.h"
+#include "prince/sound.h"
+#include "prince/variatxt.h"
+#include "prince/flags.h"
+#include "prince/font.h"
+#include "prince/mhwanh.h"
+#include "prince/cursor.h"
+#include "prince/archive.h"
+#include "prince/hero.h"
+#include "prince/resource.h"
+#include "prince/animation.h"
+#include "prince/option_text.h"
+#include "prince/curve_values.h"
+#include "prince/detection.h"
+
+namespace Prince {
+
+void PrinceEngine::debugEngine(const char *s, ...) {
+ char buf[STRINGBUFLEN];
+ va_list va;
+
+ va_start(va, s);
+ vsnprintf(buf, STRINGBUFLEN, s, va);
+ va_end(va);
+
+ debug("Prince::Engine %s", buf);
+}
+
+PrinceEngine::PrinceEngine(OSystem *syst, const PrinceGameDescription *gameDesc) :
+ Engine(syst), _gameDescription(gameDesc), _graph(nullptr), _script(nullptr), _interpreter(nullptr), _flags(nullptr),
+ _locationNr(0), _debugger(nullptr), _midiPlayer(nullptr), _room(nullptr),
+ _cursor1(nullptr), _cursor2(nullptr), _cursor3(nullptr), _font(nullptr),
+ _suitcaseBmp(nullptr), _roomBmp(nullptr), _cursorNr(0), _picWindowX(0), _picWindowY(0), _randomSource("prince"),
+ _invLineX(134), _invLineY(176), _invLine(5), _invLines(3), _invLineW(70), _invLineH(76), _maxInvW(72), _maxInvH(76),
+ _invLineSkipX(2), _invLineSkipY(3), _showInventoryFlag(false), _inventoryBackgroundRemember(false),
+ _mst_shadow(0), _mst_shadow2(0), _candleCounter(0), _invX1(53), _invY1(18), _invWidth(536), _invHeight(438),
+ _invCurInside(false), _optionsFlag(false), _optionEnabled(0), _invExamY(120), _invMaxCount(2), _invCounter(0),
+ _optionsMob(-1), _currentPointerNumber(1), _selectedMob(-1), _selectedItem(0), _selectedMode(0),
+ _optionsWidth(210), _optionsHeight(170), _invOptionsWidth(210), _invOptionsHeight(130), _optionsStep(20),
+ _invOptionsStep(20), _optionsNumber(7), _invOptionsNumber(5), _optionsColor1(236), _optionsColor2(252),
+ _dialogWidth(600), _dialogHeight(0), _dialogLineSpace(10), _dialogColor1(220), _dialogColor2(223),
+ _dialogFlag(false), _dialogLines(0), _dialogText(nullptr), _mouseFlag(1),
+ _roomPathBitmap(nullptr), _roomPathBitmapTemp(nullptr), _coordsBufEnd(nullptr), _coordsBuf(nullptr), _coords(nullptr),
+ _traceLineLen(0), _rembBitmapTemp(nullptr), _rembBitmap(nullptr), _rembMask(0), _rembX(0), _rembY(0), _fpX(0), _fpY(0),
+ _checkBitmapTemp(nullptr), _checkBitmap(nullptr), _checkMask(0), _checkX(0), _checkY(0), _traceLineFirstPointFlag(false),
+ _tracePointFirstPointFlag(false), _coordsBuf2(nullptr), _coords2(nullptr), _coordsBuf3(nullptr), _coords3(nullptr),
+ _shanLen(0), _directionTable(nullptr), _currentMidi(0), _lightX(0), _lightY(0), _curveData(nullptr), _curvPos(0),
+ _creditsData(nullptr), _creditsDataSize(0), _currentTime(0), _zoomBitmap(nullptr), _shadowBitmap(nullptr), _transTable(nullptr),
+ _flcFrameSurface(nullptr), _shadScaleValue(0), _shadLineLen(0), _scaleValue(0), _dialogImage(nullptr), _mobTranslationData(nullptr),
+ _mobTranslationSize(0) {
+
+ // Debug/console setup
+ DebugMan.addDebugChannel(DebugChannel::kScript, "script", "Prince Script debug channel");
+ DebugMan.addDebugChannel(DebugChannel::kEngine, "engine", "Prince Engine debug channel");
+
+ DebugMan.enableDebugChannel("script");
+
+ memset(_audioStream, 0, sizeof(_audioStream));
+
+ gDebugLevel = 10;
+}
+
+PrinceEngine::~PrinceEngine() {
+ DebugMan.clearAllDebugChannels();
+
+ delete _rnd;
+ delete _debugger;
+ delete _cursor1;
+ delete _cursor3;
+ delete _midiPlayer;
+ delete _script;
+ delete _flags;
+ delete _interpreter;
+ delete _font;
+ delete _roomBmp;
+ delete _suitcaseBmp;
+ delete _variaTxt;
+ free(_talkTxt);
+ free(_invTxt);
+ free(_dialogDat);
+ delete _graph;
+ delete _room;
+
+ if (_cursor2 != nullptr) {
+ _cursor2->free();
+ delete _cursor2;
+ }
+
+ for (uint i = 0; i < _objList.size(); i++) {
+ delete _objList[i];
+ }
+ _objList.clear();
+
+ free(_objSlot);
+
+ for (uint32 i = 0; i < _pscrList.size(); i++) {
+ delete _pscrList[i];
+ }
+ _pscrList.clear();
+
+ for (uint i = 0; i < _maskList.size(); i++) {
+ free(_maskList[i]._data);
+ }
+ _maskList.clear();
+
+ _drawNodeList.clear();
+
+ clearBackAnimList();
+ _backAnimList.clear();
+
+ freeAllNormAnims();
+ _normAnimList.clear();
+
+ for (uint i = 0; i < _allInvList.size(); i++) {
+ _allInvList[i]._surface->free();
+ delete _allInvList[i]._surface;
+ }
+ _allInvList.clear();
+
+ _optionsPic->free();
+ delete _optionsPic;
+
+ _optionsPicInInventory->free();
+ delete _optionsPicInInventory;
+
+ for (uint i = 0; i < _mainHero->_moveSet.size(); i++) {
+ delete _mainHero->_moveSet[i];
+ }
+
+ for (uint i = 0; i < _secondHero->_moveSet.size(); i++) {
+ delete _secondHero->_moveSet[i];
+ }
+
+ delete _mainHero;
+ delete _secondHero;
+
+ free(_roomPathBitmap);
+ free(_roomPathBitmapTemp);
+ free(_coordsBuf);
+
+ _mobPriorityList.clear();
+
+ freeAllSamples();
+
+ free(_zoomBitmap);
+ free(_shadowBitmap);
+ free(_transTable);
+
+ free(_curveData);
+
+ free(_shadowLine);
+
+ free(_creditsData);
+
+ if (_dialogImage != nullptr) {
+ _dialogImage->free();
+ delete _dialogImage;
+ }
+
+ free(_mobTranslationData);
+}
+
+GUI::Debugger *PrinceEngine::getDebugger() {
+ return _debugger;
+}
+
+void PrinceEngine::init() {
+
+ const Common::FSNode gameDataDir(ConfMan.get("path"));
+
+ debugEngine("Adding all path: %s", gameDataDir.getPath().c_str());
+
+ PtcArchive *all = new PtcArchive();
+ if (!all->open("all/databank.ptc"))
+ error("Can't open all/databank.ptc");
+
+ PtcArchive *voices = new PtcArchive();
+ if (!voices->open("data/voices/databank.ptc"))
+ error("Can't open data/voices/databank.ptc");
+
+ PtcArchive *sound = new PtcArchive();
+ if (!sound->open("sound/databank.ptc"))
+ error("Can't open sound/databank.ptc");
+
+ PtcArchive *translation = new PtcArchive();
+ if (getLanguage() != Common::PL_POL && getLanguage() != Common::DE_DEU) {
+ if (!translation->openTranslation("all/prince_translation.dat"))
+ error("Can't open prince_translation.dat");
+ }
+
+ SearchMan.addSubDirectoryMatching(gameDataDir, "all");
+
+ SearchMan.add("all", all);
+ SearchMan.add("voices", voices);
+ SearchMan.add("sound", sound);
+ if (getLanguage() != Common::PL_POL && getLanguage() != Common::DE_DEU) {
+ SearchMan.add("translation", translation);
+ }
+
+ _graph = new GraphicsMan(this);
+
+ _rnd = new Common::RandomSource("prince");
+
+ _midiPlayer = new MusicPlayer(this);
+
+ if (getLanguage() == Common::DE_DEU) {
+ _font = new Font();
+ Resource::loadResource(_font, "font3.raw", true);
+ } else {
+ _font = new Font();
+ Resource::loadResource(_font, "font1.raw", true);
+ }
+
+ _suitcaseBmp = new MhwanhDecoder();
+ Resource::loadResource(_suitcaseBmp, "walizka", true);
+
+ _script = new Script(this);
+ Resource::loadResource(_script, "skrypt.dat", true);
+
+ _flags = new InterpreterFlags();
+ _interpreter = new Interpreter(this, _script, _flags);
+
+ _debugger = new Debugger(this, _flags);
+
+ _variaTxt = new VariaTxt();
+ if (getLanguage() == Common::PL_POL || getLanguage() == Common::DE_DEU) {
+ Resource::loadResource(_variaTxt, "variatxt.dat", true);
+ } else {
+ Resource::loadResource(_variaTxt, "variatxt_translate.dat", true);
+ }
+
+ _cursor1 = new Cursor();
+ Resource::loadResource(_cursor1, "mouse1.cur", true);
+
+ _cursor3 = new Cursor();
+ Resource::loadResource(_cursor3, "mouse2.cur", true);
+
+ Common::SeekableReadStream *talkTxtStream;
+ if (getLanguage() == Common::PL_POL || getLanguage() == Common::DE_DEU) {
+ talkTxtStream = SearchMan.createReadStreamForMember("talktxt.dat");
+ } else {
+ talkTxtStream = SearchMan.createReadStreamForMember("talktxt_translate.dat");
+ }
+ if (!talkTxtStream) {
+ error("Can't load talkTxtStream");
+ return;
+ }
+ _talkTxtSize = talkTxtStream->size();
+ _talkTxt = (byte *)malloc(_talkTxtSize);
+ talkTxtStream->read(_talkTxt, _talkTxtSize);
+
+ delete talkTxtStream;
+
+ Common::SeekableReadStream *invTxtStream;
+ if (getLanguage() == Common::PL_POL || getLanguage() == Common::DE_DEU) {
+ invTxtStream = SearchMan.createReadStreamForMember("invtxt.dat");
+ } else {
+ invTxtStream = SearchMan.createReadStreamForMember("invtxt_translate.dat");
+ }
+ if (!invTxtStream) {
+ error("Can't load invTxtStream");
+ return;
+ }
+ _invTxtSize = invTxtStream->size();
+ _invTxt = (byte *)malloc(_invTxtSize);
+ invTxtStream->read(_invTxt, _invTxtSize);
+
+ delete invTxtStream;
+
+ loadAllInv();
+
+ Common::SeekableReadStream *dialogDatStream = SearchMan.createReadStreamForMember("dialog.dat");
+ if (!dialogDatStream) {
+ error("Can't load dialogDatStream");
+ return;
+ }
+ _dialogDatSize = dialogDatStream->size();
+ _dialogDat = (byte *)malloc(_dialogDatSize);
+ dialogDatStream->read(_dialogDat, _dialogDatSize);
+
+ delete dialogDatStream;
+
+ _optionsPic = new Graphics::Surface();
+ _optionsPic->create(_optionsWidth, _optionsHeight, Graphics::PixelFormat::createFormatCLUT8());
+ Common::Rect picRect(0, 0, _optionsWidth, _optionsHeight);
+ _optionsPic->fillRect(picRect, _graph->kShadowColor);
+
+ _optionsPicInInventory = new Graphics::Surface();
+ _optionsPicInInventory->create(_invOptionsWidth, _invOptionsHeight, Graphics::PixelFormat::createFormatCLUT8());
+ Common::Rect invPicRect(0, 0, _invOptionsWidth, _invOptionsHeight);
+ _optionsPicInInventory->fillRect(invPicRect, _graph->kShadowColor);
+
+ _roomBmp = new Image::BitmapDecoder();
+
+ _room = new Room();
+
+ _mainHero = new Hero(this, _graph);
+ _secondHero = new Hero(this, _graph);
+ _secondHero->_maxBoredom = 140;
+ _secondHero->loadAnimSet(3);
+
+ _roomPathBitmap = (byte *)malloc(kPathBitmapLen);
+ _roomPathBitmapTemp = (byte *)malloc(kPathBitmapLen);
+ _coordsBuf = (byte *)malloc(kTracePts * 4);
+ _coords = _coordsBuf;
+ _coordsBufEnd = _coordsBuf + kTracePts * 4 - 4;
+
+ BackgroundAnim tempBackAnim;
+ tempBackAnim._seq._currRelative = 0;
+ for (int i = 0; i < kMaxBackAnims; i++) {
+ _backAnimList.push_back(tempBackAnim);
+ }
+
+ Anim tempAnim;
+ tempAnim._animData = nullptr;
+ tempAnim._shadowData = nullptr;
+ for (int i = 0; i < kMaxNormAnims; i++) {
+ _normAnimList.push_back(tempAnim);
+ }
+
+ _objSlot = (uint16 *)malloc(kMaxObjects * sizeof(uint16));
+ for (int i = 0; i < kMaxObjects; i++) {
+ _objSlot[i] = 0xFF;
+ }
+
+ _zoomBitmap = (byte *)malloc(kZoomBitmapLen);
+ _shadowBitmap = (byte *)malloc(2 * kShadowBitmapSize);
+ _transTable = (byte *)malloc(kTransTableSize);
+
+ _curveData = (int16 *)malloc(2 * kCurveLen * sizeof(int16));
+
+ _shadowLine = (byte *)malloc(kShadowLineArraySize);
+
+ Common::SeekableReadStream *creditsDataStream;
+ if (getLanguage() == Common::PL_POL || getLanguage() == Common::DE_DEU) {
+ creditsDataStream = SearchMan.createReadStreamForMember("credits.dat");
+ } else {
+ creditsDataStream = SearchMan.createReadStreamForMember("credits_translate.dat");
+ }
+ if (!creditsDataStream) {
+ error("Can't load creditsDataStream");
+ return;
+ }
+ _creditsDataSize = creditsDataStream->size();
+ _creditsData = (byte *)malloc(_creditsDataSize);
+ creditsDataStream->read(_creditsData, _creditsDataSize);
+ delete creditsDataStream;
+
+ if (getLanguage() != Common::PL_POL && getLanguage() != Common::DE_DEU) {
+ loadMobTranslationTexts();
+ }
+}
+
+void PrinceEngine::showLogo() {
+ MhwanhDecoder logo;
+ if (Resource::loadResource(&logo, "logo.raw", true)) {
+ loadSample(0, "LOGO.WAV");
+ playSample(0, 0);
+ _graph->draw(_graph->_frontScreen, logo.getSurface());
+ _graph->change();
+ _graph->update(_graph->_frontScreen);
+ setPalette(logo.getPalette());
+
+ uint32 logoStart = _system->getMillis();
+ while (_system->getMillis() < logoStart + 5000) {
+ Common::Event event;
+ Common::EventManager *eventMan = _system->getEventManager();
+ while (eventMan->pollEvent(event)) {
+ switch (event.type) {
+ case Common::EVENT_KEYDOWN:
+ if (event.kbd.keycode == Common::KEYCODE_ESCAPE) {
+ stopSample(0);
+ return;
+ }
+ break;
+ case Common::EVENT_LBUTTONDOWN:
+ stopSample(0);
+ return;
+ default:
+ break;
+ }
+ }
+
+ if (shouldQuit()) {
+ return;
+ }
+ }
+ }
+}
+
+Common::Error PrinceEngine::run() {
+ syncSoundSettings();
+ int startGameSlot = ConfMan.hasKey("save_slot") ? ConfMan.getInt("save_slot") : -1;
+ init();
+ if (startGameSlot == -1) {
+ showLogo();
+ } else {
+ loadLocation(59); // load intro location - easiest way to set everything up
+ loadGame(startGameSlot);
+ }
+ mainLoop();
+ return Common::kNoError;
+}
+
+void PrinceEngine::pauseEngineIntern(bool pause) {
+ Engine::pauseEngineIntern(pause);
+ if (pause) {
+ _midiPlayer->pause();
+ }
+ else {
+ _midiPlayer->resume();
+ }
+}
+
+bool AnimListItem::loadFromStream(Common::SeekableReadStream &stream) {
+ int32 pos = stream.pos();
+
+ uint16 type = stream.readUint16LE();
+ if (type == 0xFFFF) {
+ return false;
+ }
+ _type = type;
+ _fileNumber = stream.readUint16LE();
+ _startPhase = stream.readUint16LE();
+ _endPhase = stream.readUint16LE();
+ _loopPhase = stream.readUint16LE();
+ _x = stream.readSint16LE();
+ _y = stream.readSint16LE();
+ _loopType = stream.readUint16LE();
+ _nextAnim = stream.readUint16LE();
+ _flags = stream.readUint16LE();
+
+ //debug("AnimListItem type %d, fileNumber %d, x %d, y %d, flags %d", _type, _fileNumber, _x, _y, _flags);
+ //debug("startPhase %d, endPhase %d, loopPhase %d", _startPhase, _endPhase, _loopPhase);
+
+ // 32 byte aligment
+ stream.seek(pos + 32);
+
+ return true;
+}
+
+bool PrinceEngine::loadLocation(uint16 locationNr) {
+
+ blackPalette();
+
+ _flicPlayer.close();
+
+ memset(_textSlots, 0, sizeof(_textSlots));
+ freeAllSamples();
+
+ debugEngine("PrinceEngine::loadLocation %d", locationNr);
+ const Common::FSNode gameDataDir(ConfMan.get("path"));
+ SearchMan.remove(Common::String::format("%02d", _locationNr));
+
+ _locationNr = locationNr;
+ _debugger->_locationNr = locationNr;
+
+ _flags->setFlagValue(Flags::CURRROOM, _locationNr);
+ _interpreter->stopBg();
+
+ changeCursor(0);
+
+ const Common::String locationNrStr = Common::String::format("%02d", _locationNr);
+ debugEngine("loadLocation %s", locationNrStr.c_str());
+
+ PtcArchive *locationArchive = new PtcArchive();
+ if (!locationArchive->open(locationNrStr + "/databank.ptc"))
+ error("Can't open location %s", locationNrStr.c_str());
+
+ SearchMan.add(locationNrStr, locationArchive);
+
+ loadMusic(_locationNr);
+
+ // load location background, replace old one
+ Resource::loadResource(_roomBmp, "room", true);
+ if (_roomBmp->getSurface()) {
+ _sceneWidth = _roomBmp->getSurface()->w;
+ }
+
+ loadZoom(_zoomBitmap, kZoomBitmapLen, "zoom");
+ loadShadow(_shadowBitmap, kShadowBitmapSize, "shadow", "shadow2");
+ loadTrans(_transTable, "trans");
+ loadPath("path");
+
+ for (uint32 i = 0; i < _pscrList.size(); i++) {
+ delete _pscrList[i];
+ }
+ _pscrList.clear();
+ Resource::loadResource(_pscrList, "pscr.lst", false);
+
+ loadMobPriority("mobpri");
+
+ _mobList.clear();
+ if (getGameType() == kPrinceDataDE) {
+ const Common::String mobLstName = Common::String::format("mob%02d.lst", _locationNr);
+ debug("name: %s", mobLstName.c_str());
+ Resource::loadResource(_mobList, mobLstName.c_str(), false);
+ } else if (getGameType() == kPrinceDataPL) {
+ Resource::loadResource(_mobList, "mob.lst", false);
+ }
+ if (getLanguage() != Common::PL_POL && getLanguage() != Common::DE_DEU) {
+ // update Mob texts for translated version
+ setMobTranslationTexts();
+ }
+
+ _animList.clear();
+ Resource::loadResource(_animList, "anim.lst", false);
+
+ for (uint32 i = 0; i < _objList.size(); i++) {
+ delete _objList[i];
+ }
+ _objList.clear();
+ Resource::loadResource(_objList, "obj.lst", false);
+
+ _room->loadRoom(_script->getRoomOffset(_locationNr));
+
+ for (uint i = 0; i < _maskList.size(); i++) {
+ free(_maskList[i]._data);
+ }
+ _maskList.clear();
+ _script->loadAllMasks(_maskList, _room->_nak);
+
+ _picWindowX = 0;
+
+ _lightX = _script->getLightX(_locationNr);
+ _lightY = _script->getLightY(_locationNr);
+ setShadowScale(_script->getShadowScale(_locationNr));
+
+ for (uint i = 0; i < _mobList.size(); i++) {
+ _mobList[i]._visible = _script->getMobVisible(_room->_mobs, i);
+ }
+
+ _script->installObjects(_room->_obj);
+
+ freeAllNormAnims();
+
+ clearBackAnimList();
+ _script->installBackAnims(_backAnimList, _room->_backAnim);
+
+ _graph->makeShadowTable(70, _graph->_shadowTable70);
+ _graph->makeShadowTable(50, _graph->_shadowTable50);
+
+ _mainHero->freeOldMove();
+ _secondHero->freeOldMove();
+
+ _mainHero->scrollHero();
+
+ return true;
+}
+
+void PrinceEngine::setShadowScale(int32 shadowScale) {
+ shadowScale = 100 - shadowScale;
+ if (!shadowScale) {
+ _shadScaleValue = 10000;
+ } else {
+ _shadScaleValue = 10000 / shadowScale;
+ }
+}
+
+void PrinceEngine::plotShadowLinePoint(int x, int y, int color, void *data) {
+ PrinceEngine *vm = (PrinceEngine *)data;
+ WRITE_LE_UINT16(&vm->_shadowLine[vm->_shadLineLen * 4], x);
+ WRITE_LE_UINT16(&vm->_shadowLine[vm->_shadLineLen * 4 + 2], y);
+ vm->_shadLineLen++;
+}
+
+void PrinceEngine::changeCursor(uint16 curId) {
+ _debugger->_cursorNr = curId;
+ _mouseFlag = curId;
+ _flags->setFlagValue(Flags::MOUSEENABLED, curId);
+
+ const Graphics::Surface *curSurface = nullptr;
+
+ switch (curId) {
+ case 0:
+ CursorMan.showMouse(false);
+ _optionsFlag = 0;
+ _selectedMob = -1;
+ return;
+ case 1:
+ curSurface = _cursor1->getSurface();
+ break;
+ case 2:
+ curSurface = _cursor2;
+ break;
+ case 3:
+ curSurface = _cursor3->getSurface();
+ Common::Point mousePos = _system->getEventManager()->getMousePos();
+ mousePos.x = CLIP(mousePos.x, (int16) 315, (int16) 639);
+ mousePos.y = CLIP(mousePos.y, (int16) 0, (int16) 170);
+ _system->warpMouse(mousePos.x, mousePos.y);
+ break;
+ }
+
+ CursorMan.replaceCursorPalette(_roomBmp->getPalette(), 0, 255);
+ CursorMan.replaceCursor(
+ curSurface->getBasePtr(0, 0),
+ curSurface->w, curSurface->h,
+ 0, 0,
+ 255, false,
+ &curSurface->format
+ );
+ CursorMan.showMouse(true);
+}
+
+void PrinceEngine::makeInvCursor(int itemNr) {
+ const Graphics::Surface *cur1Surface = _cursor1->getSurface();
+ int cur1W = cur1Surface->w;
+ int cur1H = cur1Surface->h;
+ const Common::Rect cur1Rect(0, 0, cur1W, cur1H);
+
+ const Graphics::Surface *itemSurface = _allInvList[itemNr].getSurface();
+ int itemW = itemSurface->w;
+ int itemH = itemSurface->h;
+
+ int cur2W = cur1W + itemW / 2;
+ int cur2H = cur1H + itemH / 2;
+
+ if (_cursor2 != nullptr) {
+ _cursor2->free();
+ delete _cursor2;
+ }
+ _cursor2 = new Graphics::Surface();
+ _cursor2->create(cur2W, cur2H, Graphics::PixelFormat::createFormatCLUT8());
+ Common::Rect cur2Rect(0, 0, cur2W, cur2H);
+ _cursor2->fillRect(cur2Rect, 255);
+ _cursor2->copyRectToSurface(*cur1Surface, 0, 0, cur1Rect);
+
+ const byte *src1 = (const byte *)itemSurface->getBasePtr(0, 0);
+ byte *dst1 = (byte *)_cursor2->getBasePtr(cur1W, cur1H);
+
+ if (itemH % 2) {
+ itemH--;
+ }
+ if (itemW % 2) {
+ itemW--;
+ }
+
+ for (int y = 0; y < itemH; y++) {
+ const byte *src2 = src1;
+ byte *dst2 = dst1;
+ if (y % 2 == 0) {
+ for (int x = 0; x < itemW; x++, src2++) {
+ if (x % 2 == 0) {
+ if (*src2) {
+ *dst2 = *src2;
+ } else {
+ *dst2 = 255;
+ }
+ dst2++;
+ }
+ }
+ dst1 += _cursor2->pitch;
+ }
+ src1 += itemSurface->pitch;
+ }
+}
+
+bool PrinceEngine::loadMusic(int musNumber) {
+ uint8 midiNumber = MusicPlayer::_musRoomTable[musNumber];
+ if (midiNumber) {
+ if (midiNumber != 100) {
+ if (_currentMidi != midiNumber) {
+ _currentMidi = midiNumber;
+ const char *musName = MusicPlayer::_musTable[_currentMidi];
+ _midiPlayer->loadMidi(musName);
+ }
+ }
+ } else {
+ stopMusic();
+ }
+ return true;
+}
+
+void PrinceEngine::stopMusic() {
+ if (_midiPlayer->isPlaying()) {
+ _midiPlayer->stop();
+ }
+}
+
+bool PrinceEngine::playNextFLCFrame() {
+ if (!_flicPlayer.isVideoLoaded())
+ return false;
+
+ const Graphics::Surface *s = _flicPlayer.decodeNextFrame();
+ if (s) {
+ _graph->drawTransparentSurface(_graph->_frontScreen, 0, 0, s, 255);
+ _graph->change();
+ _flcFrameSurface = s;
+ } else if (_flicLooped) {
+ _flicPlayer.rewind();
+ playNextFLCFrame();
+ } else if (_flcFrameSurface) {
+ _graph->drawTransparentSurface(_graph->_frontScreen, 0, 0, _flcFrameSurface, 255);
+ _graph->change();
+ }
+
+ return true;
+}
+
+void PrinceEngine::playSample(uint16 sampleId, uint16 loopType) {
+ if (_audioStream[sampleId]) {
+ if (_mixer->isSoundIDActive(sampleId)) {
+ return;
+ }
+ _audioStream[sampleId]->rewind();
+ if (sampleId < 28) {
+ _mixer->playStream(Audio::Mixer::kSFXSoundType, &_soundHandle[sampleId], _audioStream[sampleId], sampleId, Audio::Mixer::kMaxChannelVolume, 0, DisposeAfterUse::NO);
+ } else {
+ _mixer->playStream(Audio::Mixer::kSpeechSoundType, &_soundHandle[sampleId], _audioStream[sampleId], sampleId, Audio::Mixer::kMaxChannelVolume, 0, DisposeAfterUse::NO);
+ }
+ }
+}
+
+void PrinceEngine::stopSample(uint16 sampleId) {
+ _mixer->stopID(sampleId);
+}
+
+void PrinceEngine::stopAllSamples() {
+ _mixer->stopAll();
+}
+
+void PrinceEngine::freeSample(uint16 sampleId) {
+ stopSample(sampleId);
+ if (_audioStream[sampleId] != nullptr) {
+ delete _audioStream[sampleId];
+ _audioStream[sampleId] = nullptr;
+ }
+}
+
+void PrinceEngine::freeAllSamples() {
+ for (int sampleId = 0; sampleId < kMaxSamples; sampleId++) {
+ freeSample(sampleId);
+ }
+}
+
+bool PrinceEngine::loadSample(uint32 sampleSlot, const Common::String &streamName) {
+ // FIXME: This is just a workaround streamName is a path
+ // SOUND\\SCIERKA1.WAV for now only last path component is used
+ Common::String normalizedPath = lastPathComponent(streamName, '\\');
+
+ // WALKAROUND: Wrong name in script, not existing sound in data files
+ if (!normalizedPath.compareTo("9997BEKA.WAV")) {
+ return 0;
+ }
+
+ debugEngine("loadSample slot %d, name %s", sampleSlot, normalizedPath.c_str());
+
+ freeSample(sampleSlot);
+ Common::SeekableReadStream *sampleStream = SearchMan.createReadStreamForMember(normalizedPath);
+ if (sampleStream == nullptr) {
+ delete sampleStream;
+ error("Can't load sample %s to slot %d", normalizedPath.c_str(), sampleSlot);
+ }
+ _audioStream[sampleSlot] = Audio::makeWAVStream(sampleStream, DisposeAfterUse::NO);
+ delete sampleStream;
+ return true;
+}
+
+bool PrinceEngine::loadVoice(uint32 slot, uint32 sampleSlot, const Common::String &streamName) {
+ debugEngine("Loading wav %s slot %d", streamName.c_str(), slot);
+
+ if (slot >= kMaxTexts) {
+ error("Text slot bigger than MAXTEXTS %d", kMaxTexts - 1);
+ return false;
+ }
+
+ freeSample(sampleSlot);
+ Common::SeekableReadStream *sampleStream = SearchMan.createReadStreamForMember(streamName);
+ if (sampleStream == nullptr) {
+ debug("Can't open %s", streamName.c_str());
+ return false;
+ }
+
+ uint32 id = sampleStream->readUint32LE();
+ if (id != MKTAG('F', 'F', 'I', 'R')) {
+ error("It's not RIFF file %s", streamName.c_str());
+ return false;
+ }
+
+ sampleStream->skip(0x20);
+ id = sampleStream->readUint32LE();
+ if (id != MKTAG('a', 't', 'a', 'd')) {
+ error("No data section in %s id %04x", streamName.c_str(), id);
+ return false;
+ }
+
+ id = sampleStream->readUint32LE();
+ debugEngine("SetVoice slot %d time %04x", slot, id);
+ id <<= 3;
+ id /= 22050;
+ id += 2;
+
+ _textSlots[slot]._time = id;
+ if (!slot) {
+ _mainHero->_talkTime = id;
+ } else if (slot == 1) {
+ _secondHero->_talkTime = id;
+ }
+
+ debugEngine("SetVoice slot %d time %04x", slot, id);
+ sampleStream->seek(SEEK_SET);
+ _audioStream[sampleSlot] = Audio::makeWAVStream(sampleStream, DisposeAfterUse::NO);
+ delete sampleStream;
+ return true;
+}
+
+void PrinceEngine::setVoice(uint16 slot, uint32 sampleSlot, uint16 flag) {
+ Common::String sampleName;
+ uint32 currentString = _interpreter->getCurrentString();
+
+ if (currentString >= 80000) {
+ uint32 nr = currentString - 80000;
+ sampleName = Common::String::format("%02d0%02d-%02d.WAV", nr / 100, nr % 100, flag);
+ } else if (currentString >= 70000) {
+ sampleName = Common::String::format("inv%02d-01.WAV", currentString - 70000);
+ } else if (currentString >= 60000) {
+ sampleName = Common::String::format("M%04d-%02d.WAV", currentString - 60000, flag);
+ } else if (currentString >= 2000) {
+ return;
+ } else if (flag >= 100) {
+ sampleName = Common::String::format("%03d-%03d.WAV", currentString, flag);
+ } else {
+ sampleName = Common::String::format("%03d-%02d.WAV", currentString, flag);
+ }
+
+ loadVoice(slot, sampleSlot, sampleName);
+}
+
+bool PrinceEngine::loadAnim(uint16 animNr, bool loop) {
+ Common::String streamName = Common::String::format("AN%02d", animNr);
+ Common::SeekableReadStream *flicStream = SearchMan.createReadStreamForMember(streamName);
+
+ if (!flicStream) {
+ error("Can't open %s", streamName.c_str());
+ return false;
+ }
+
+ if (!_flicPlayer.loadStream(flicStream)) {
+ error("Can't load flic stream %s", streamName.c_str());
+ }
+
+ debugEngine("%s loaded", streamName.c_str());
+ _flicLooped = loop;
+ _flicPlayer.start();
+ playNextFLCFrame();
+ return true;
+}
+
+bool PrinceEngine::loadZoom(byte *zoomBitmap, uint32 dataSize, const char *resourceName) {
+ Common::SeekableReadStream *stream = SearchMan.createReadStreamForMember(resourceName);
+ if (!stream) {
+ delete stream;
+ return false;
+ }
+ if (stream->read(zoomBitmap, dataSize) != dataSize) {
+ free(zoomBitmap);
+ delete stream;
+ return false;
+ }
+ delete stream;
+ return true;
+}
+
+bool PrinceEngine::loadShadow(byte *shadowBitmap, uint32 dataSize, const char *resourceName1, const char *resourceName2) {
+ Common::SeekableReadStream *stream = SearchMan.createReadStreamForMember(resourceName1);
+ if (!stream) {
+ delete stream;
+ return false;
+ }
+
+ if (stream->read(shadowBitmap, dataSize) != dataSize) {
+ free(shadowBitmap);
+ delete stream;
+ return false;
+ }
+
+ Common::SeekableReadStream *stream2 = SearchMan.createReadStreamForMember(resourceName2);
+ if (!stream2) {
+ delete stream;
+ delete stream2;
+ return false;
+ }
+
+ byte *shadowBitmap2 = shadowBitmap + dataSize;
+ if (stream2->read(shadowBitmap2, dataSize) != dataSize) {
+ free(shadowBitmap);
+ delete stream;
+ delete stream2;
+ return false;
+ }
+
+ delete stream;
+ delete stream2;
+ return true;
+}
+
+bool PrinceEngine::loadTrans(byte *transTable, const char *resourceName) {
+ Common::SeekableReadStream *stream = SearchMan.createReadStreamForMember(resourceName);
+ if (!stream) {
+ delete stream;
+ for (int i = 0; i < 256; i++) {
+ for (int j = 0; j < 256; j++) {
+ transTable[i * 256 + j] = j;
+ }
+ }
+ return true;
+ }
+ if (stream->read(transTable, kTransTableSize) != kTransTableSize) {
+ delete stream;
+ return false;
+ }
+ delete stream;
+ return true;
+}
+
+bool PrinceEngine::loadPath(const char *resourceName) {
+ Common::SeekableReadStream *stream = SearchMan.createReadStreamForMember(resourceName);
+ if (!stream) {
+ delete stream;
+ return false;
+ }
+ if (stream->read(_roomPathBitmap, kPathBitmapLen) != kPathBitmapLen) {
+ delete stream;
+ return false;
+ }
+ delete stream;
+ return true;
+}
+
+bool PrinceEngine::loadAllInv() {
+ for (int i = 0; i < kMaxInv; i++) {
+ InvItem tempInvItem;
+
+ const Common::String invStreamName = Common::String::format("INV%02d", i);
+ Common::SeekableReadStream *invStream = SearchMan.createReadStreamForMember(invStreamName);
+ if (!invStream) {
+ delete invStream;
+ return true;
+ }
+
+ tempInvItem._x = invStream->readUint16LE();
+ tempInvItem._y = invStream->readUint16LE();
+ int width = invStream->readUint16LE();
+ int height = invStream->readUint16LE();
+ tempInvItem._surface = new Graphics::Surface();
+ tempInvItem._surface->create(width, height, Graphics::PixelFormat::createFormatCLUT8());
+
+ for (int h = 0; h < tempInvItem._surface->h; h++) {
+ invStream->read(tempInvItem._surface->getBasePtr(0, h), tempInvItem._surface->w);
+ }
+
+ _allInvList.push_back(tempInvItem);
+ delete invStream;
+ }
+
+ return true;
+}
+
+bool PrinceEngine::loadMobPriority(const char *resourceName) {
+ Common::SeekableReadStream *stream = SearchMan.createReadStreamForMember(resourceName);
+ if (!stream) {
+ delete stream;
+ return false;
+ }
+
+ _mobPriorityList.clear();
+ uint mobId;
+ while (1) {
+ mobId = stream->readUint32LE();
+ if (mobId == 0xFFFFFFFF) {
+ break;
+ }
+ _mobPriorityList.push_back(mobId);
+ }
+ delete stream;
+ return true;
+}
+
+void PrinceEngine::loadMobTranslationTexts() {
+ Common::SeekableReadStream *mobTranslationStream = SearchMan.createReadStreamForMember("mob_translate.dat");
+ if (!mobTranslationStream) {
+ error("Can't load mob_translate.dat");
+ }
+ _mobTranslationSize = mobTranslationStream->size();
+ _mobTranslationData = (byte *)malloc(_mobTranslationSize);
+ mobTranslationStream->read(_mobTranslationData, _mobTranslationSize);
+ delete mobTranslationStream;
+}
+
+void PrinceEngine::setMobTranslationTexts() {
+ int locationOffset = READ_UINT16(_mobTranslationData + (_locationNr - 1) * 2);
+ if (locationOffset) {
+ byte *locationText = _mobTranslationData + locationOffset;
+ for (uint i = 0; i < _mobList.size(); i++) {
+ byte c;
+ locationText++;
+ _mobList[i]._name.clear();
+ while ((c = *locationText)) {
+ _mobList[i]._name += c;
+ locationText++;
+ }
+ locationText++;
+ _mobList[i]._examText.clear();
+ c = *locationText;
+ locationText++;
+ if (c) {
+ _mobList[i]._examText += c;
+ do {
+ c = *locationText;
+ _mobList[i]._examText += c;
+ locationText++;
+ } while (c != 255);
+ }
+ }
+ }
+}
+
+void PrinceEngine::keyHandler(Common::Event event) {
+ uint16 nChar = event.kbd.keycode;
+ switch (nChar) {
+ case Common::KEYCODE_d:
+ if (event.kbd.hasFlags(Common::KBD_CTRL)) {
+ getDebugger()->attach();
+ }
+ break;
+ case Common::KEYCODE_z:
+ if (_flags->getFlagValue(Flags::POWERENABLED)) {
+ _flags->setFlagValue(Flags::MBFLAG, 1);
+ }
+ break;
+ case Common::KEYCODE_x:
+ if (_flags->getFlagValue(Flags::POWERENABLED)) {
+ _flags->setFlagValue(Flags::MBFLAG, 2);
+ }
+ break;
+ case Common::KEYCODE_ESCAPE:
+ _flags->setFlagValue(Flags::ESCAPED2, 1);
+ break;
+ }
+}
+
+int PrinceEngine::getMob(Common::Array<Mob> &mobList, bool usePriorityList, int posX, int posY) {
+
+ Common::Point pointPos(posX, posY);
+
+ int mobListSize;
+ if (usePriorityList) {
+ mobListSize = _mobPriorityList.size();
+ } else {
+ mobListSize = mobList.size();
+ }
+
+ for (int mobNumber = 0; mobNumber < mobListSize; mobNumber++) {
+ Mob *mob = nullptr;
+ if (usePriorityList) {
+ mob = &mobList[_mobPriorityList[mobNumber]];
+ } else {
+ mob = &mobList[mobNumber];
+ }
+
+ if (mob->_visible) {
+ continue;
+ }
+
+ int type = mob->_type & 7;
+ switch (type) {
+ case 0:
+ case 1:
+ //normal_mob
+ if (!mob->_rect.contains(pointPos)) {
+ continue;
+ }
+ break;
+ case 3:
+ //mob_obj
+ if (mob->_mask < kMaxObjects) {
+ int nr = _objSlot[mob->_mask];
+ if (nr != 0xFF) {
+ Object &obj = *_objList[nr];
+ Common::Rect objectRect(obj._x, obj._y, obj._x + obj._width, obj._y + obj._height);
+ if (objectRect.contains(pointPos)) {
+ Graphics::Surface *objSurface = obj.getSurface();
+ byte *pixel = (byte *)objSurface->getBasePtr(posX - obj._x, posY - obj._y);
+ if (*pixel != 255) {
+ break;
+ }
+ }
+ }
+ }
+ continue;
+ break;
+ case 2:
+ case 5:
+ //check_ba_mob
+ if (!_backAnimList[mob->_mask].backAnims.empty()) {
+ int currentAnim = _backAnimList[mob->_mask]._seq._currRelative;
+ Anim &backAnim = _backAnimList[mob->_mask].backAnims[currentAnim];
+ if (backAnim._animData != nullptr) {
+ if (!backAnim._state) {
+ Common::Rect backAnimRect(backAnim._currX, backAnim._currY, backAnim._currX + backAnim._currW, backAnim._currY + backAnim._currH);
+ if (backAnimRect.contains(pointPos)) {
+ int phase = backAnim._showFrame;
+ int phaseFrameIndex = backAnim._animData->getPhaseFrameIndex(phase);
+ Graphics::Surface *backAnimSurface = backAnim._animData->getFrame(phaseFrameIndex);
+ byte pixel = *(byte *)backAnimSurface->getBasePtr(posX - backAnim._currX, posY - backAnim._currY);
+ if (pixel != 255) {
+ if (type == 5) {
+ if (mob->_rect.contains(pointPos)) {
+ break;
+ }
+ } else {
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+ continue;
+ break;
+ default:
+ //not_part_ba
+ continue;
+ break;
+ }
+
+ if (usePriorityList) {
+ return _mobPriorityList[mobNumber];
+ } else {
+ return mobNumber;
+ }
+ }
+ return -1;
+}
+
+int PrinceEngine::checkMob(Graphics::Surface *screen, Common::Array<Mob> &mobList, bool usePriorityList) {
+ if (_mouseFlag == 0 || _mouseFlag == 3) {
+ return -1;
+ }
+ Common::Point mousePos = _system->getEventManager()->getMousePos();
+ int mobNumber = getMob(mobList, usePriorityList, mousePos.x + _picWindowX, mousePos.y);
+
+ if (mobNumber != -1) {
+ Common::String mobName = mobList[mobNumber]._name;
+
+ if (getLanguage() == Common::DE_DEU) {
+ for (uint i = 0; i < mobName.size(); i++) {
+ switch (mobName[i]) {
+ case '\xc4':
+ mobName.setChar('\x83', i);
+ break;
+ case '\xd6':
+ mobName.setChar('\x84', i);
+ break;
+ case '\xdc':
+ mobName.setChar('\x85', i);
+ break;
+ case '\xdf':
+ mobName.setChar('\x7f', i);
+ break;
+ case '\xe4':
+ mobName.setChar('\x80', i);
+ break;
+ case '\xf6':
+ mobName.setChar('\x81', i);
+ break;
+ case '\xfc':
+ mobName.setChar('\x82', i);
+ break;
+ }
+ }
+ }
+
+ uint16 textW = getTextWidth(mobName.c_str());
+
+ uint16 x = mousePos.x - textW / 2;
+ if (x > screen->w) {
+ x = 0;
+ }
+
+ if (x + textW > screen->w) {
+ x = screen->w - textW;
+ }
+
+ uint16 y = mousePos.y - _font->getFontHeight();
+ if (y > screen->h) {
+ y = _font->getFontHeight() - 2;
+ }
+
+ _font->drawString(screen, mobName, x, y, screen->w, 216);
+ }
+
+ return mobNumber;
+}
+
+void PrinceEngine::printAt(uint32 slot, uint8 color, char *s, uint16 x, uint16 y) {
+ debugC(1, DebugChannel::kEngine, "PrinceEngine::printAt slot %d, color %d, x %02d, y %02d, str %s", slot, color, x, y, s);
+
+ if (getLanguage() == Common::DE_DEU)
+ correctStringDEU(s);
+
+ Text &text = _textSlots[slot];
+ text._str = s;
+ text._x = x;
+ text._y = y;
+ text._color = color;
+ int lines = calcTextLines(s);
+ text._time = calcTextTime(lines);
+}
+
+int PrinceEngine::calcTextLines(const char *s) {
+ int lines = 1;
+ while (*s) {
+ if (*s == '\n') {
+ lines++;
+ }
+ s++;
+ }
+ return lines;
+}
+
+int PrinceEngine::calcTextTime(int numberOfLines) {
+ return numberOfLines * 30;
+}
+
+void PrinceEngine::correctStringDEU(char *s) {
+ while (*s) {
+ switch (*s) {
+ case '\xc4':
+ *s = '\x83';
+ break;
+ case '\xd6':
+ *s = '\x84';
+ break;
+ case '\xdc':
+ *s = '\x85';
+ break;
+ case '\xdf':
+ *s = '\x7f';
+ break;
+ case '\xe4':
+ *s = '\x80';
+ break;
+ case '\xf6':
+ *s = '\x81';
+ break;
+ case '\xfc':
+ *s = '\x82';
+ break;
+ }
+ s++;
+ }
+}
+
+uint32 PrinceEngine::getTextWidth(const char *s) {
+ uint16 textW = 0;
+ while (*s) {
+ textW += _font->getCharWidth(*s) + _font->getKerningOffset(0, 0);
+ s++;
+ }
+ return textW;
+}
+
+void PrinceEngine::showTexts(Graphics::Surface *screen) {
+ for (uint32 slot = 0; slot < kMaxTexts; slot++) {
+
+ if (_showInventoryFlag && slot) {
+ // only slot 0 for inventory
+ break;
+ }
+
+ Text& text = _textSlots[slot];
+ if (!text._str && !text._time) {
+ continue;
+ }
+
+ int x = text._x;
+ int y = text._y;
+
+ if (!_showInventoryFlag) {
+ x -= _picWindowX;
+ y -= _picWindowY;
+ }
+
+ Common::Array<Common::String> lines;
+ _font->wordWrapText(text._str, _graph->_frontScreen->w, lines);
+
+ int wideLine = 0;
+ for (uint i = 0; i < lines.size(); i++) {
+ int textLen = getTextWidth(lines[i].c_str());
+ if (textLen > wideLine) {
+ wideLine = textLen;
+ }
+ }
+
+ int leftBorderText = 6;
+ if (x + wideLine / 2 > kNormalWidth - leftBorderText) {
+ x = kNormalWidth - leftBorderText - wideLine / 2;
+ }
+
+ if (x - wideLine / 2 < leftBorderText) {
+ x = leftBorderText + wideLine / 2;
+ }
+
+ int textSkip = 2;
+ for (uint i = 0; i < lines.size(); i++) {
+ int drawX = x - getTextWidth(lines[i].c_str()) / 2;
+ int drawY = y - 10 - (lines.size() - i) * (_font->getFontHeight() - textSkip);
+ if (drawX < 0) {
+ drawX = 0;
+ }
+ if (drawY < 0) {
+ drawY = 0;
+ }
+ _font->drawString(screen, lines[i], drawX, drawY, screen->w, text._color);
+ }
+
+ text._time--;
+ if (!text._time) {
+ text._str = nullptr;
+ }
+ }
+}
+
+bool PrinceEngine::spriteCheck(int sprWidth, int sprHeight, int destX, int destY) {
+ destX -= _picWindowX;
+ destY -= _picWindowY;
+
+ // if x1 is on visible part of screen
+ if (destX < 0) {
+ if (destX + sprWidth < 1) {
+ //x2 is negative - out of window
+ return false;
+ }
+ }
+ // if x1 is outside of screen on right side
+ if (destX >= kNormalWidth) {
+ return false;
+ }
+
+ if (destY < 0) {
+ if (destY + sprHeight < 1) {
+ //y2 is negative - out of window
+ return false;
+ }
+ }
+ if (destY >= kNormalHeight) {
+ return false;
+ }
+
+ return true;
+}
+
+// CheckNak
+void PrinceEngine::checkMasks(int x1, int y1, int sprWidth, int sprHeight, int z) {
+ int x2 = x1 + sprWidth - 1;
+ int y2 = y1 + sprHeight - 1;
+ if (x1 < 0) {
+ x1 = 0;
+ }
+ for (uint i = 0; i < _maskList.size(); i++) {
+ if (!_maskList[i]._state && !_maskList[i]._flags) {
+ if (_maskList[i]._z > z) {
+ if (_maskList[i]._x1 <= x2 && _maskList[i]._x2 >= x1) {
+ if (_maskList[i]._y1 <= y2 && _maskList[i]._y2 >= y1) {
+ _maskList[i]._state = 1;
+ }
+ }
+ }
+ }
+ }
+}
+
+// ClsNak
+void PrinceEngine::clsMasks() {
+ for (uint i = 0; i < _maskList.size(); i++) {
+ if (_maskList[i]._state) {
+ _maskList[i]._state = 0;
+ }
+ }
+}
+
+// InsertNakladki
+void PrinceEngine::insertMasks(Graphics::Surface *originalRoomSurface) {
+ for (uint i = 0; i < _maskList.size(); i++) {
+ if (_maskList[i]._state) {
+ if (_maskList[i]._data != nullptr) {
+ showMask(i, originalRoomSurface);
+ } else {
+ error("insertMasks() - Wrong mask data- nr %d", i);
+ }
+ }
+ }
+}
+
+// ShowNak
+void PrinceEngine::showMask(int maskNr, Graphics::Surface *originalRoomSurface) {
+ if (!_maskList[maskNr]._flags) {
+ if (spriteCheck(_maskList[maskNr]._width, _maskList[maskNr]._height, _maskList[maskNr]._x1, _maskList[maskNr]._y1)) {
+ int destX = _maskList[maskNr]._x1 - _picWindowX;
+ int destY = _maskList[maskNr]._y1 - _picWindowY;
+ DrawNode newDrawNode;
+ newDrawNode.posX = destX;
+ newDrawNode.posY = destY;
+ newDrawNode.posZ = _maskList[maskNr]._z;
+ newDrawNode.width = _maskList[maskNr]._width;
+ newDrawNode.height = _maskList[maskNr]._height;
+ newDrawNode.s = nullptr;
+ newDrawNode.originalRoomSurface = originalRoomSurface;
+ newDrawNode.data = _maskList[maskNr].getMask();
+ newDrawNode.drawFunction = &_graph->drawMaskDrawNode;
+ _drawNodeList.push_back(newDrawNode);
+ }
+ }
+}
+
+void PrinceEngine::showSprite(Graphics::Surface *spriteSurface, int destX, int destY, int destZ) {
+ if (spriteCheck(spriteSurface->w, spriteSurface->h, destX, destY)) {
+ destX -= _picWindowX;
+ destY -= _picWindowY;
+ DrawNode newDrawNode;
+ newDrawNode.posX = destX;
+ newDrawNode.posY = destY;
+ newDrawNode.posZ = destZ;
+ newDrawNode.width = 0;
+ newDrawNode.height = 0;
+ newDrawNode.s = spriteSurface;
+ newDrawNode.originalRoomSurface = nullptr;
+ newDrawNode.data = _transTable;
+ newDrawNode.drawFunction = &_graph->drawTransparentWithTransDrawNode;
+ _drawNodeList.push_back(newDrawNode);
+ }
+}
+
+void PrinceEngine::showSpriteShadow(Graphics::Surface *shadowSurface, int destX, int destY, int destZ) {
+ if (spriteCheck(shadowSurface->w, shadowSurface->h, destX, destY)) {
+ destX -= _picWindowX;
+ destY -= _picWindowY;
+ DrawNode newDrawNode;
+ newDrawNode.posX = destX;
+ newDrawNode.posY = destY;
+ newDrawNode.posZ = destZ;
+ newDrawNode.width = 0;
+ newDrawNode.height = 0;
+ newDrawNode.s = shadowSurface;
+ newDrawNode.originalRoomSurface = nullptr;
+ newDrawNode.data = _graph->_shadowTable70;
+ newDrawNode.drawFunction = &_graph->drawAsShadowDrawNode;
+ _drawNodeList.push_back(newDrawNode);
+ }
+}
+
+void PrinceEngine::showAnim(Anim &anim) {
+ //ShowFrameCode
+ //ShowAnimFrame
+ int phase = anim._showFrame;
+ int phaseFrameIndex = anim._animData->getPhaseFrameIndex(phase);
+ int x = anim._x + anim._animData->getPhaseOffsetX(phase);
+ int y = anim._y + anim._animData->getPhaseOffsetY(phase);
+ int animFlag = anim._flags;
+ int checkMaskFlag = (animFlag & 1);
+ int maxFrontFlag = (animFlag & 2);
+ int specialZFlag = anim._nextAnim;
+ int z = anim._nextAnim;
+ Graphics::Surface *animSurface = anim._animData->getFrame(phaseFrameIndex);
+ int frameWidth = animSurface->w;
+ int frameHeight = animSurface->h;
+ int shadowZ = 0;
+
+ if (checkMaskFlag) {
+ if (!anim._nextAnim) {
+ z = y + frameHeight - 1;
+ }
+ checkMasks(x, y, frameWidth, frameHeight, z);
+ }
+
+ if (specialZFlag) {
+ z = specialZFlag;
+ } else if (maxFrontFlag) {
+ z = kMaxPicHeight + 1;
+ } else {
+ z = y + frameHeight - 1;
+ }
+ shadowZ = z;
+
+ anim._currX = x;
+ anim._currY = y;
+ anim._currW = frameWidth;
+ anim._currH = frameHeight;
+ showSprite(animSurface, x, y, z);
+
+ // make_special_shadow
+ if ((anim._flags & 0x80)) {
+ if (animSurface) {
+ DrawNode newDrawNode;
+ newDrawNode.posX = x;
+ newDrawNode.posY = y + animSurface->h - anim._shadowBack;
+ newDrawNode.posZ = Hero::kHeroShadowZ;
+ newDrawNode.width = 0;
+ newDrawNode.height = 0;
+ newDrawNode.scaleValue = _scaleValue;
+ newDrawNode.originalRoomSurface = nullptr;
+ newDrawNode.data = this;
+ newDrawNode.drawFunction = &Hero::showHeroShadow;
+ newDrawNode.s = animSurface;
+ _drawNodeList.push_back(newDrawNode);
+ }
+ }
+
+ //ShowFrameCodeShadow
+ //ShowAnimFrameShadow
+ if (anim._shadowData != nullptr) {
+ int shadowPhaseFrameIndex = anim._shadowData->getPhaseFrameIndex(phase);
+ int shadowX = anim._shadowData->getBaseX() + anim._shadowData->getPhaseOffsetX(phase);
+ int shadowY = anim._shadowData->getBaseY() + anim._shadowData->getPhaseOffsetY(phase);
+ Graphics::Surface *shadowSurface = anim._shadowData->getFrame(shadowPhaseFrameIndex);
+ int shadowFrameWidth = shadowSurface->w;
+ int shadowFrameHeight = shadowSurface->h;
+
+ if (checkMaskFlag) {
+ checkMasks(shadowX, shadowY, shadowFrameWidth, shadowFrameHeight, shadowY + shadowFrameWidth - 1);
+ }
+
+ if (!shadowZ) {
+ if (maxFrontFlag) {
+ shadowZ = kMaxPicHeight + 1;
+ } else {
+ shadowZ = shadowY + shadowFrameWidth - 1;
+ }
+ }
+ showSpriteShadow(shadowSurface, shadowX, shadowY, shadowZ);
+ }
+}
+
+void PrinceEngine::showNormAnims() {
+ for (int i = 0; i < kMaxNormAnims; i++) {
+ Anim &anim = _normAnimList[i];
+ if (anim._animData != nullptr) {
+ int phaseCount = anim._animData->getPhaseCount();
+ if (!anim._state) {
+ if (anim._frame == anim._lastFrame - 1) {
+ if (anim._loopType) {
+ if (anim._loopType == 1) {
+ anim._frame = anim._loopFrame;
+ } else {
+ continue;
+ }
+ }
+ } else {
+ anim._frame++;
+ }
+ anim._showFrame = anim._frame;
+ if (anim._showFrame >= phaseCount) {
+ anim._showFrame = phaseCount - 1;
+ }
+ showAnim(anim);
+ }
+ }
+ }
+}
+
+void PrinceEngine::setBackAnim(Anim &backAnim) {
+ int start = backAnim._basaData._start;
+ if (start != -1) {
+ backAnim._frame = start;
+ backAnim._showFrame = start;
+ backAnim._loopFrame = start;
+ }
+ int end = backAnim._basaData._end;
+ if (end != -1) {
+ backAnim._lastFrame = end;
+ }
+ backAnim._state = 0;
+}
+
+void PrinceEngine::showBackAnims() {
+ for (int i = 0; i < kMaxBackAnims; i++) {
+ BAS &seq = _backAnimList[i]._seq;
+ int activeSubAnim = seq._currRelative;
+ if (!_backAnimList[i].backAnims.empty()) {
+ if (_backAnimList[i].backAnims[activeSubAnim]._animData != nullptr) {
+ if (!_backAnimList[i].backAnims[activeSubAnim]._state) {
+ seq._counter++;
+ if (seq._type == 2) {
+ if (!seq._currRelative) {
+ if (seq._counter >= seq._data) {
+ if (seq._anims > 2) {
+ seq._currRelative = _randomSource.getRandomNumber(seq._anims - 2) + 1;
+ activeSubAnim = seq._currRelative;
+ seq._current = _backAnimList[i].backAnims[activeSubAnim]._basaData._num;
+ }
+ setBackAnim(_backAnimList[i].backAnims[activeSubAnim]);
+ seq._counter = 0;
+ }
+ }
+ }
+
+ if (seq._type == 3) {
+ if (!seq._currRelative) {
+ if (seq._counter < seq._data2) {
+ continue;
+ } else {
+ setBackAnim(_backAnimList[i].backAnims[activeSubAnim]);
+ }
+ }
+ }
+
+ if (_backAnimList[i].backAnims[activeSubAnim]._frame == _backAnimList[i].backAnims[activeSubAnim]._lastFrame - 1) {
+ _backAnimList[i].backAnims[activeSubAnim]._frame = _backAnimList[i].backAnims[activeSubAnim]._loopFrame;
+ switch (seq._type) {
+ case 1:
+ if (seq._anims > 1) {
+ int rnd;
+ do {
+ rnd = _randomSource.getRandomNumber(seq._anims - 1);
+ } while (rnd == seq._currRelative);
+ seq._currRelative = rnd;
+ seq._current = _backAnimList[i].backAnims[rnd]._basaData._num;
+ activeSubAnim = rnd;
+ setBackAnim(_backAnimList[i].backAnims[activeSubAnim]);
+ seq._counter = 0;
+ }
+ break;
+ case 2:
+ if (seq._currRelative) {
+ seq._currRelative = 0;
+ seq._current = _backAnimList[i].backAnims[0]._basaData._num;
+ activeSubAnim = 0;
+ setBackAnim(_backAnimList[i].backAnims[activeSubAnim]);
+ seq._counter = 0;
+ }
+ break;
+ case 3:
+ seq._currRelative = 0;
+ seq._current = _backAnimList[i].backAnims[0]._basaData._num;
+ seq._counter = 0;
+ seq._data2 = _randomSource.getRandomNumber(seq._data - 1);
+ continue; // for bug in original game
+ break;
+ }
+ } else {
+ _backAnimList[i].backAnims[activeSubAnim]._frame++;
+ }
+ _backAnimList[i].backAnims[activeSubAnim]._showFrame = _backAnimList[i].backAnims[activeSubAnim]._frame;
+ showAnim(_backAnimList[i].backAnims[activeSubAnim]);
+ }
+ }
+ }
+ }
+}
+
+void PrinceEngine::removeSingleBackAnim(int slot) {
+ if (!_backAnimList[slot].backAnims.empty()) {
+ for (uint j = 0; j < _backAnimList[slot].backAnims.size(); j++) {
+ if (_backAnimList[slot].backAnims[j]._animData != nullptr) {
+ delete _backAnimList[slot].backAnims[j]._animData;
+ _backAnimList[slot].backAnims[j]._animData = nullptr;
+ }
+ if (_backAnimList[slot].backAnims[j]._shadowData != nullptr) {
+ delete _backAnimList[slot].backAnims[j]._shadowData;
+ _backAnimList[slot].backAnims[j]._shadowData = nullptr;
+ }
+ }
+ _backAnimList[slot].backAnims.clear();
+ _backAnimList[slot]._seq._currRelative = 0;
+ }
+}
+
+void PrinceEngine::clearBackAnimList() {
+ for (int i = 0; i < kMaxBackAnims; i++) {
+ removeSingleBackAnim(i);
+ }
+}
+
+void PrinceEngine::grabMap() {
+ _graph->_frontScreen->copyFrom(*_roomBmp->getSurface());
+ showObjects();
+ runDrawNodes();
+ _graph->_mapScreen->copyFrom(*_graph->_frontScreen);
+}
+
+void PrinceEngine::initZoomIn(int slot) {
+ freeZoomObject(slot);
+ Object *object = _objList[slot];
+ if (object != nullptr) {
+ Graphics::Surface *zoomSource = object->getSurface();
+ if (zoomSource != nullptr) {
+ object->_flags |= 0x8000;
+ object->_zoomSurface = new Graphics::Surface();
+ object->_zoomSurface->create(zoomSource->w, zoomSource->h, Graphics::PixelFormat::createFormatCLUT8());
+ object->_zoomSurface->fillRect(Common::Rect(zoomSource->w, zoomSource->h), 0xFF);
+ object->_zoomTime = 20;
+ }
+ }
+}
+
+void PrinceEngine::initZoomOut(int slot) {
+ freeZoomObject(slot);
+ Object *object = _objList[slot];
+ if (object != nullptr) {
+ Graphics::Surface *zoomSource = object->getSurface();
+ if (zoomSource != nullptr) {
+ object->_flags |= 0x4000;
+ object->_zoomSurface = new Graphics::Surface();
+ object->_zoomSurface->copyFrom(*zoomSource);
+ object->_zoomTime = 10;
+ }
+ }
+}
+
+void PrinceEngine::doZoomIn(int slot) {
+ Object *object = _objList[slot];
+ if (object != nullptr) {
+ Graphics::Surface *orgSurface = object->getSurface();
+ if (orgSurface != nullptr) {
+ byte *src1 = (byte *)orgSurface->getBasePtr(0, 0);
+ byte *dst1 = (byte *)object->_zoomSurface->getBasePtr(0, 0);
+ int x = 0;
+ int surfaceHeight = orgSurface->h;
+ for (int y = 0; y < surfaceHeight; y++) {
+ byte *src2 = src1;
+ byte *dst2 = dst1;
+ int w = orgSurface->w - x;
+ src2 += x;
+ dst2 += x;
+ while (w > 0) {
+ int randVal = _randomSource.getRandomNumber(zoomInStep - 1);
+ if (randVal < w) {
+ *(dst2 + randVal) = *(src2 + randVal);
+ src2 += zoomInStep;
+ dst2 += zoomInStep;
+ } else if (y + 1 != surfaceHeight) {
+ *(dst1 + orgSurface->pitch + randVal - w) = *(src1 + orgSurface->pitch + randVal - w);
+ }
+ w -= zoomInStep;
+ }
+ x = -1 * w;
+ src1 += orgSurface->pitch;
+ dst1 += orgSurface->pitch;
+ }
+ }
+ }
+}
+
+void PrinceEngine::doZoomOut(int slot) {
+ Object *object = _objList[slot];
+ if (object != nullptr) {
+ Graphics::Surface *orgSurface = object->getSurface();
+ if (orgSurface != nullptr) {
+ byte *dst1 = (byte *)object->_zoomSurface->getBasePtr(0, 0);
+ int x = 0;
+ int surfaceHeight = orgSurface->h;
+ for (int y = 0; y < surfaceHeight; y++) {
+ byte *dst2 = dst1;
+ int w = orgSurface->w - x;
+ dst2 += x;
+ while (w > 0) {
+ int randVal = _randomSource.getRandomNumber(zoomInStep - 1);
+ if (randVal < w) {
+ *(dst2 + randVal) = 255;
+ dst2 += zoomInStep;
+ } else if (y + 1 != surfaceHeight) {
+ *(dst1 + orgSurface->pitch + randVal - w) = 255;
+ }
+ w -= zoomInStep;
+ }
+ x = -1 * w;
+ dst1 += orgSurface->pitch;
+ }
+ }
+ }
+}
+
+void PrinceEngine::freeZoomObject(int slot) {
+ Object *object = _objList[slot];
+ if (object != nullptr) {
+ if (object->_zoomSurface != nullptr) {
+ object->_zoomSurface->free();
+ delete object->_zoomSurface;
+ object->_zoomSurface = nullptr;
+ }
+ }
+}
+
+void PrinceEngine::showObjects() {
+ for (int i = 0; i < kMaxObjects; i++) {
+ int nr = _objSlot[i];
+ if (nr != 0xFF) {
+ Graphics::Surface *objSurface = nullptr;
+ if ((_objList[nr]->_flags & 0x8000)) {
+ _objList[nr]->_zoomTime--;
+ if (!_objList[nr]->_zoomTime) {
+ freeZoomObject(nr);
+ _objList[nr]->_flags &= 0x7FFF;
+ objSurface = _objList[nr]->getSurface();
+ } else {
+ doZoomIn(nr);
+ objSurface = _objList[nr]->_zoomSurface;
+ }
+ } else if ((_objList[nr]->_flags & 0x4000)) {
+ _objList[nr]->_zoomTime--;
+ if (!_objList[nr]->_zoomTime) {
+ freeZoomObject(nr);
+ _objList[nr]->_flags &= 0xBFFF;
+ objSurface = _objList[nr]->getSurface();
+ } else {
+ doZoomOut(nr);
+ objSurface = _objList[nr]->_zoomSurface;
+ }
+ } else {
+ objSurface = _objList[nr]->getSurface();
+ }
+
+ if (objSurface != nullptr) {
+ if (spriteCheck(objSurface->w, objSurface->h, _objList[nr]->_x, _objList[nr]->_y)) {
+ int destX = _objList[nr]->_x - _picWindowX;
+ int destY = _objList[nr]->_y - _picWindowY;
+ DrawNode newDrawNode;
+ newDrawNode.posX = destX;
+ newDrawNode.posY = destY;
+ newDrawNode.posZ = _objList[nr]->_z;
+ newDrawNode.width = 0;
+ newDrawNode.height = 0;
+ newDrawNode.s = objSurface;
+ newDrawNode.originalRoomSurface = nullptr;
+ if ((_objList[nr]->_flags & 0x2000)) {
+ newDrawNode.data = nullptr;
+ newDrawNode.drawFunction = &_graph->drawBackSpriteDrawNode;
+ } else {
+ newDrawNode.data = _transTable;
+ if (_flags->getFlagValue(Flags::NOANTIALIAS)) {
+ newDrawNode.drawFunction = &_graph->drawTransparentDrawNode;
+ } else {
+ newDrawNode.drawFunction = &_graph->drawTransparentWithTransDrawNode;
+ }
+ }
+ _drawNodeList.push_back(newDrawNode);
+ }
+
+ if ((_objList[nr]->_flags & 1)) {
+ checkMasks(_objList[nr]->_x, _objList[nr]->_y, objSurface->w, objSurface->h, _objList[nr]->_z);
+ }
+ }
+ }
+ }
+}
+
+void PrinceEngine::showParallax() {
+ if (!_pscrList.empty()) {
+ for (uint i = 0; i < _pscrList.size(); i++) {
+ Graphics::Surface *pscrSurface = _pscrList[i]->getSurface();
+ if (pscrSurface != nullptr) {
+ int x = _pscrList[i]->_x - (_pscrList[i]->_step * _picWindowX / 4);
+ int y = _pscrList[i]->_y;
+ int z = PScr::kPScrZ;
+ if (spriteCheck(pscrSurface->w, pscrSurface->h, x, y)) {
+ showSprite(pscrSurface, x, y, z);
+ }
+ }
+ }
+ }
+}
+
+bool PrinceEngine::compareDrawNodes(DrawNode d1, DrawNode d2) {
+ if (d1.posZ < d2.posZ) {
+ return true;
+ }
+ return false;
+}
+
+void PrinceEngine::runDrawNodes() {
+ Common::sort(_drawNodeList.begin(), _drawNodeList.end(), compareDrawNodes);
+
+ for (uint i = 0; i < _drawNodeList.size(); i++) {
+ (*_drawNodeList[i].drawFunction)(_graph->_frontScreen, &_drawNodeList[i]);
+ }
+ _graph->change();
+}
+
+void PrinceEngine::drawScreen() {
+ if (!_showInventoryFlag || _inventoryBackgroundRemember) {
+ clsMasks();
+
+ _mainHero->showHero();
+ _mainHero->scrollHero();
+ _mainHero->drawHero();
+
+ _secondHero->showHero();
+ _secondHero->_drawX -= _picWindowX;
+ _secondHero->drawHero();
+
+ const Graphics::Surface *roomSurface;
+ if (_locationNr != 50) {
+ roomSurface = _roomBmp->getSurface();
+ } else {
+ roomSurface = _graph->_mapScreen;
+ }
+ Graphics::Surface visiblePart;
+ if (roomSurface) {
+ visiblePart = roomSurface->getSubArea(Common::Rect(_picWindowX, 0, roomSurface->w, roomSurface->h));
+ _graph->draw(_graph->_frontScreen, &visiblePart);
+ }
+
+ showBackAnims();
+
+ showNormAnims();
+
+ playNextFLCFrame();
+
+ showObjects();
+
+ if (roomSurface) {
+ insertMasks(&visiblePart);
+ }
+
+ showParallax();
+
+ runDrawNodes();
+
+ _drawNodeList.clear();
+
+ if (!_inventoryBackgroundRemember && !_dialogFlag) {
+ if (!_optionsFlag) {
+ _selectedMob = checkMob(_graph->_frontScreen, _mobList, true);
+ }
+ showTexts(_graph->_frontScreen);
+ checkOptions();
+ } else {
+ _inventoryBackgroundRemember = false;
+ }
+
+ showPower();
+
+ getDebugger()->onFrame();
+
+ } else {
+ displayInventory();
+ }
+}
+
+void PrinceEngine::blackPalette() {
+ byte *paletteBackup = (byte *)malloc(256 * 3);
+ byte *blackPalette1 = (byte *)malloc(256 * 3);
+
+ int fadeStep = kFadeStep - 1;
+ for (int i = 0; i < kFadeStep; i++) {
+ _system->getPaletteManager()->grabPalette(paletteBackup, 0, 256);
+ for (int j = 0; j < 256; j++) {
+ blackPalette1[3 * j] = paletteBackup[3 * j] * fadeStep / 4;
+ blackPalette1[3 * j + 1] = paletteBackup[3 * j + 1] * fadeStep / 4;
+ blackPalette1[3 * j + 2] = paletteBackup[3 * j + 2] * fadeStep / 4;
+ }
+ fadeStep--;
+ _graph->setPalette(blackPalette1);
+ _system->updateScreen();
+ Common::Event event;
+ Common::EventManager *eventMan = _system->getEventManager();
+ eventMan->pollEvent(event);
+ if (shouldQuit()) {
+ free(paletteBackup);
+ free(blackPalette1);
+ return;
+ }
+ pausePrinceEngine();
+ }
+ free(paletteBackup);
+ free(blackPalette1);
+}
+
+void PrinceEngine::setPalette(const byte *palette) {
+ if (palette != nullptr) {
+ byte *blackPalette_ = (byte *)malloc(256 * 3);
+ int fadeStep = 0;
+ for (int i = 0; i <= kFadeStep; i++) {
+ for (int j = 0; j < 256; j++) {
+ blackPalette_[3 * j] = palette[3 * j] * fadeStep / 4;
+ blackPalette_[3 * j + 1] = palette[3 * j + 1] * fadeStep / 4;
+ blackPalette_[3 * j + 2] = palette[3 * j + 2] * fadeStep / 4;
+ }
+ fadeStep++;
+ _graph->setPalette(blackPalette_);
+ _system->updateScreen();
+ Common::Event event;
+ Common::EventManager *eventMan = _system->getEventManager();
+ eventMan->pollEvent(event);
+ if (shouldQuit()) {
+ _graph->setPalette(palette);
+ free(blackPalette_);
+ return;
+ }
+ pausePrinceEngine();
+ }
+ _graph->setPalette(palette);
+ free(blackPalette_);
+ }
+}
+
+void PrinceEngine::pausePrinceEngine(int fps) {
+ int delay = 1000 / fps - int32(_system->getMillis() - _currentTime);
+ delay = delay < 0 ? 0 : delay;
+ _system->delayMillis(delay);
+ _currentTime = _system->getMillis();
+}
+
+void PrinceEngine::addInv(int heroId, int item, bool addItemQuiet) {
+ Hero *hero = nullptr;
+ if (!heroId) {
+ hero = _mainHero;
+ } else if (heroId == 1) {
+ hero = _secondHero;
+ }
+ if (hero != nullptr) {
+ if (hero->_inventory.size() < kMaxItems) {
+ if (item != 0x7FFF) {
+ hero->_inventory.push_back(item);
+ }
+ if (!addItemQuiet) {
+ addInvObj();
+ }
+ _interpreter->setResult(0);
+ } else {
+ _interpreter->setResult(1);
+ }
+ }
+}
+
+void PrinceEngine::remInv(int heroId, int item) {
+ Hero *hero = nullptr;
+ if (!heroId) {
+ hero = _mainHero;
+ } else if (heroId == 1) {
+ hero = _secondHero;
+ }
+ if (hero != nullptr) {
+ for (uint i = 0; i < hero->_inventory.size(); i++) {
+ if (hero->_inventory[i] == item) {
+ hero->_inventory.remove_at(i);
+ _interpreter->setResult(0);
+ return;
+ }
+ }
+ }
+ _interpreter->setResult(1);
+}
+
+void PrinceEngine::clearInv(int heroId) {
+ switch (heroId) {
+ case 0:
+ _mainHero->_inventory.clear();
+ break;
+ case 1:
+ _secondHero->_inventory.clear();
+ break;
+ default:
+ error("clearInv() - wrong hero slot");
+ break;
+ }
+}
+
+void PrinceEngine::swapInv(int heroId) {
+ Common::Array<int> tempInv;
+ Hero *hero = nullptr;
+ if (!heroId) {
+ hero = _mainHero;
+ } else if (heroId == 1) {
+ hero = _secondHero;
+ }
+ if (hero != nullptr) {
+ for (uint i = 0; i < hero->_inventory.size(); i++) {
+ tempInv.push_back(hero->_inventory[i]);
+ }
+ hero->_inventory.clear();
+ for (uint i = 0; i < hero->_inventory2.size(); i++) {
+ hero->_inventory.push_back(hero->_inventory2[i]);
+ }
+ hero->_inventory2.clear();
+ for (uint i = 0; i < tempInv.size(); i++) {
+ hero->_inventory2.push_back(tempInv[i]);
+ }
+ tempInv.clear();
+ }
+}
+
+void PrinceEngine::addInvObj() {
+ changeCursor(0);
+ prepareInventoryToView();
+
+ _inventoryBackgroundRemember = true;
+ drawScreen();
+
+ Graphics::Surface *suitcase = _suitcaseBmp->getSurface();
+
+ if (!_flags->getFlagValue(Flags::CURSEBLINK)) {
+
+ loadSample(27, "PRZEDMIO.WAV");
+ playSample(27, 0);
+
+ _mst_shadow2 = 1;
+
+ while (_mst_shadow2 < 512) {
+ rememberScreenInv();
+ _graph->drawTransparentSurface(_graph->_screenForInventory, 0, 0, suitcase);
+ drawInvItems();
+ _graph->update(_graph->_screenForInventory);
+ _mst_shadow2 += 50;
+ Common::Event event;
+ Common::EventManager *eventMan = _system->getEventManager();
+ eventMan->pollEvent(event);
+ if (shouldQuit()) {
+ return;
+ }
+ pausePrinceEngine();
+ }
+ while (_mst_shadow2 > 256) {
+ rememberScreenInv();
+ _graph->drawTransparentSurface(_graph->_screenForInventory, 0, 0, suitcase);
+ drawInvItems();
+ _graph->update(_graph->_screenForInventory);
+ _mst_shadow2 -= 42;
+ Common::Event event;
+ Common::EventManager *eventMan = _system->getEventManager();
+ eventMan->pollEvent(event);
+ if (shouldQuit()) {
+ return;
+ }
+ pausePrinceEngine();
+ }
+ } else {
+ //CURSEBLINK:
+ for (int i = 0; i < 3; i++) {
+ _mst_shadow2 = 256;
+ while (_mst_shadow2 < 512) {
+ rememberScreenInv();
+ _graph->drawTransparentSurface(_graph->_screenForInventory, 0, 0, suitcase);
+ drawInvItems();
+ _graph->update(_graph->_screenForInventory);
+ _mst_shadow2 += 50;
+ Common::Event event;
+ Common::EventManager *eventMan = _system->getEventManager();
+ eventMan->pollEvent(event);
+ if (shouldQuit()) {
+ return;
+ }
+ pausePrinceEngine();
+ }
+ while (_mst_shadow2 > 256) {
+ rememberScreenInv();
+ _graph->drawTransparentSurface(_graph->_screenForInventory, 0, 0, suitcase);
+ drawInvItems();
+ _graph->update(_graph->_screenForInventory);
+ _mst_shadow2 -= 50;
+ Common::Event event;
+ Common::EventManager *eventMan = _system->getEventManager();
+ eventMan->pollEvent(event);
+ if (shouldQuit()) {
+ return;
+ }
+ pausePrinceEngine();
+ }
+ }
+ }
+ _mst_shadow2 = 0;
+ for (int i = 0; i < 20; i++) {
+ rememberScreenInv();
+ _graph->drawTransparentSurface(_graph->_screenForInventory, 0, 0, suitcase);
+ drawInvItems();
+ _graph->update(_graph->_screenForInventory);
+ Common::Event event;
+ Common::EventManager *eventMan = _system->getEventManager();
+ eventMan->pollEvent(event);
+ if (shouldQuit()) {
+ return;
+ }
+ pausePrinceEngine();
+ }
+}
+
+void PrinceEngine::rememberScreenInv() {
+ _graph->_screenForInventory->copyFrom(*_graph->_frontScreen);
+}
+
+void PrinceEngine::inventoryFlagChange(bool inventoryState) {
+ if (inventoryState) {
+ _showInventoryFlag = true;
+ _inventoryBackgroundRemember = true;
+ } else {
+ _showInventoryFlag = false;
+ }
+}
+
+void PrinceEngine::prepareInventoryToView() {
+ _invMobList.clear();
+ int invItem = _mainHero->_inventory.size();
+ _invLine = invItem / 3;
+ if (invItem % 3) {
+ _invLine++;
+ }
+ if (_invLine < 4) {
+ _invLine = 4;
+ }
+ _maxInvW = (374 - 2 * _invLine) / _invLine;
+ _invLineW = _maxInvW - 2;
+
+ int currInvX = _invLineX;
+ int currInvY = _invLineY;
+
+ Common::MemoryReadStream stream(_invTxt, _invTxtSize);
+ byte c;
+
+ uint item = 0;
+ for (int i = 0; i < _invLines; i++) {
+ for (int j = 0; j < _invLine; j++) {
+ Mob tempMobItem;
+ if (item < _mainHero->_inventory.size()) {
+ int itemNr = _mainHero->_inventory[item];
+ tempMobItem._visible = 0;
+ tempMobItem._mask = itemNr;
+ tempMobItem._rect = Common::Rect(currInvX + _picWindowX, currInvY, currInvX + _picWindowX + _invLineW - 1, currInvY + _invLineH - 1);
+ tempMobItem._type = 0; // to work with checkMob()
+
+ tempMobItem._name = "";
+ tempMobItem._examText = "";
+ int txtOffset = READ_LE_UINT32(&_invTxt[itemNr * 8]);
+ int examTxtOffset = READ_LE_UINT32(&_invTxt[itemNr * 8 + 4]);
+
+ stream.seek(txtOffset);
+ while ((c = stream.readByte())) {
+ tempMobItem._name += c;
+ }
+
+ stream.seek(examTxtOffset);
+ while ((c = stream.readByte())) {
+ tempMobItem._examText += c;
+ }
+ _invMobList.push_back(tempMobItem);
+ }
+ currInvX += _invLineW + _invLineSkipX;
+ item++;
+ }
+ currInvX = _invLineX;
+ currInvY += _invLineSkipY + _invLineH;
+ }
+}
+
+void PrinceEngine::drawInvItems() {
+ int currInvX = _invLineX;
+ int currInvY = _invLineY;
+ uint item = 0;
+ for (int i = 0; i < _invLines; i++) {
+ for (int j = 0; j < _invLine; j++) {
+ if (item < _mainHero->_inventory.size()) {
+ int itemNr = _mainHero->_inventory[item];
+ _mst_shadow = 0;
+ if (_mst_shadow2) {
+ if (!_flags->getFlagValue(Flags::CURSEBLINK)) {
+ if (item + 1 == _mainHero->_inventory.size()) { // last item in inventory
+ _mst_shadow = 1;
+ }
+ } else if (itemNr == 1 || itemNr == 3 || itemNr == 4 || itemNr == 7) {
+ _mst_shadow = 1;
+ }
+ }
+
+ int drawX = currInvX;
+ int drawY = currInvY;
+ Graphics::Surface *itemSurface = nullptr;
+ if (itemNr != 68) {
+ itemSurface = _allInvList[itemNr].getSurface();
+ if (itemSurface->h < _maxInvH) {
+ drawY += (_maxInvH - itemSurface->h) / 2;
+ }
+ } else {
+ // candle item:
+ if (_candleCounter == 8) {
+ _candleCounter = 0;
+ }
+ itemNr = _candleCounter;
+ _candleCounter++;
+ itemNr &= 7;
+ itemNr += 71;
+ itemSurface = _allInvList[itemNr].getSurface();
+ drawY += _allInvList[itemNr]._y + (_maxInvH - 76) / 2 - 200;
+ }
+ if (itemSurface->w < _maxInvW) {
+ drawX += (_maxInvW - itemSurface->w) / 2;
+ }
+ if (!_mst_shadow) {
+ _graph->drawTransparentSurface(_graph->_screenForInventory, drawX, drawY, itemSurface);
+ } else {
+ _mst_shadow = _mst_shadow2;
+ _graph->drawTransparentWithBlendSurface(_graph->_screenForInventory, drawX, drawY, itemSurface);
+ }
+ }
+ currInvX += _invLineW + _invLineSkipX;
+ item++;
+ }
+ currInvX = _invLineX;
+ currInvY += _invLineSkipY + _invLineH;
+ }
+}
+
+void PrinceEngine::walkTo() {
+ if (_mainHero->_visible) {
+ _mainHero->freeHeroAnim();
+ _mainHero->freeOldMove();
+ _interpreter->storeNewPC(_script->_scriptInfo.usdCode);
+ int destX, destY;
+ if (_optionsMob != -1) {
+ destX = _mobList[_optionsMob]._examPosition.x;
+ destY = _mobList[_optionsMob]._examPosition.y;
+ _mainHero->_destDirection = _mobList[_optionsMob]._examDirection;
+ } else {
+ Common::Point mousePos = _system->getEventManager()->getMousePos();
+ destX = mousePos.x + _picWindowX;
+ destY = mousePos.y + _picWindowY;
+ _mainHero->_destDirection = 0;
+ }
+ _mainHero->_coords = makePath(kMainHero, _mainHero->_middleX, _mainHero->_middleY, destX, destY);
+ if (_mainHero->_coords != nullptr) {
+ _mainHero->_currCoords = _mainHero->_coords;
+ _mainHero->_dirTab = _directionTable;
+ _mainHero->_currDirTab = _directionTable;
+ _directionTable = nullptr;
+ _mainHero->_state = Hero::kHeroStateMove;
+ moveShandria();
+ }
+ }
+}
+
+void PrinceEngine::moveRunHero(int heroId, int x, int y, int dir, bool runHeroFlag) {
+ Hero *hero = nullptr;
+ if (!heroId) {
+ hero = _mainHero;
+ } else if (heroId == 1) {
+ hero = _secondHero;
+ }
+
+ if (hero != nullptr) {
+ if (dir) {
+ hero->_destDirection = dir;
+ }
+ if (x || y) {
+ hero->freeOldMove();
+ hero->_coords = makePath(heroId, hero->_middleX, hero->_middleY, x, y);
+ if (hero->_coords != nullptr) {
+ hero->_currCoords = hero->_coords;
+ hero->_dirTab = _directionTable;
+ hero->_currDirTab = _directionTable;
+ _directionTable = nullptr;
+ if (runHeroFlag) {
+ hero->_state = Hero::kHeroStateRun;
+ } else {
+ hero->_state = Hero::kHeroStateMove;
+ }
+ if (heroId == kMainHero && _mouseFlag) {
+ moveShandria();
+ }
+ }
+ } else {
+ hero->freeOldMove();
+ hero->_state = Hero::kHeroStateTurn;
+ }
+ hero->freeHeroAnim();
+ hero->_visible = 1;
+ }
+}
+
+void PrinceEngine::leftMouseButton() {
+ _flags->setFlagValue(Flags::ESCAPED2, 1); // skip intro animation
+ _flags->setFlagValue(Flags::LMOUSE, 1);
+ if (_flags->getFlagValue(Flags::POWERENABLED)) {
+ _flags->setFlagValue(Flags::MBFLAG, 1);
+ }
+ if (_mouseFlag) {
+ int option = 0;
+ int optionEvent = -1;
+
+ if (_optionsFlag) {
+ if (_optionEnabled < _optionsNumber && _optionEnabled != -1) {
+ option = _optionEnabled;
+ _optionsFlag = 0;
+ } else {
+ return;
+ }
+ } else {
+ _optionsMob = _selectedMob;
+ if (_optionsMob == -1) {
+ walkTo();
+ return;
+ }
+ option = 0;
+ }
+ //do_option
+ if (_currentPointerNumber != 2) {
+ //skip_use_code
+ int optionScriptOffset = _room->getOptionOffset(option);
+ if (optionScriptOffset != 0) {
+ optionEvent = _script->scanMobEvents(_optionsMob, optionScriptOffset);
+ }
+ if (optionEvent == -1) {
+ if (!option) {
+ walkTo();
+ return;
+ } else {
+ optionEvent = _script->getOptionStandardOffset(option);
+ }
+ }
+ } else if (_selectedMode) {
+ //give_item
+ if (_room->_itemGive) {
+ optionEvent = _script->scanMobEventsWithItem(_optionsMob, _room->_itemGive, _selectedItem);
+ }
+ if (optionEvent == -1) {
+ //standard_giveitem
+ optionEvent = _script->_scriptInfo.stdGiveItem;
+ }
+ } else {
+ if (_room->_itemUse) {
+ optionEvent = _script->scanMobEventsWithItem(_optionsMob, _room->_itemUse, _selectedItem);
+ _flags->setFlagValue(Flags::SELITEM, _selectedItem);
+ }
+ if (optionEvent == -1) {
+ //standard_useitem
+ optionEvent = _script->_scriptInfo.stdUseItem;
+ }
+ }
+ _interpreter->storeNewPC(optionEvent);
+ _flags->setFlagValue(Flags::CURRMOB, _selectedMob);
+ _selectedMob = -1;
+ _optionsMob = -1;
+ } else {
+ if (!_flags->getFlagValue(Flags::POWERENABLED)) {
+ if (!_flags->getFlagValue(Flags::NOCLSTEXT)) {
+ for (int slot = 0; slot < kMaxTexts; slot++) {
+ if (slot != 9) {
+ Text& text = _textSlots[slot];
+ if (!text._str) {
+ continue;
+ }
+ text._str = 0;
+ text._time = 0;
+ }
+ }
+ _mainHero->_talkTime = 0;
+ _secondHero->_talkTime = 0;
+ }
+ }
+ }
+}
+
+void PrinceEngine::rightMouseButton() {
+ if (_flags->getFlagValue(Flags::POWERENABLED)) {
+ _flags->setFlagValue(Flags::MBFLAG, 2);
+ }
+ if (_mouseFlag && _mouseFlag != 3) {
+ _mainHero->freeOldMove();
+ _secondHero->freeOldMove();
+ _interpreter->storeNewPC(0);
+ if (_currentPointerNumber < 2) {
+ enableOptions(true);
+ } else {
+ _currentPointerNumber = 1;
+ changeCursor(1);
+ }
+ }
+}
+
+void PrinceEngine::inventoryLeftMouseButton() {
+ if (!_mouseFlag) {
+ _textSlots[0]._time = 0;
+ _textSlots[0]._str = nullptr;
+ stopSample(28);
+ }
+
+ if (_optionsFlag == 1) {
+ if (_selectedMob != -1) {
+ if (_optionEnabled < _invOptionsNumber) {
+ _optionsFlag = 0;
+ } else {
+ return;
+ }
+ } else {
+ error("PrinceEngine::inventoryLeftMouseButton() - optionsFlag = 1, selectedMob = 0");
+ if (_currentPointerNumber == 2) {
+ changeCursor(1);
+ _currentPointerNumber = 1;
+ _selectedMob = -1;
+ _optionsMob = -1;
+ return;
+ } else {
+ return;
+ }
+ }
+ } else {
+ if (_selectedMob != -1) {
+ if (_currentPointerNumber != 2) {
+ if (_invMobList[_selectedMob]._mask != 29) {
+ _optionEnabled = 0;
+ } else {
+ // map item
+ _optionEnabled = 1;
+ }
+ } else {
+ //use_item_on_item
+ int invObjUU = _script->scanMobEventsWithItem(_invMobList[_selectedMob]._mask, _script->_scriptInfo.invObjUU, _selectedItem);
+ if (invObjUU == -1) {
+ int textNr = 80011; // "I can't do it."
+ if (_selectedItem == 31 || _invMobList[_selectedMob]._mask == 31) {
+ textNr = 80020; // "Nothing is happening."
+ }
+ _interpreter->setCurrentString(textNr);
+ printAt(0, 216, (char *)_variaTxt->getString(textNr - 80000), kNormalWidth / 2, 100);
+ setVoice(0, 28, 1);
+ playSample(28, 0);
+ _selectedMob = -1;
+ _optionsMob = -1;
+ return;
+ } else {
+ _interpreter->storeNewPC(invObjUU);
+ _flags->setFlagValue(Flags::CURRMOB, _invMobList[_selectedMob]._mask);
+ _showInventoryFlag = false;
+ }
+ }
+ } else {
+ return;
+ }
+ }
+ //do_option
+ if (_optionEnabled == 0) {
+ int invObjExamEvent = _script->scanMobEvents(_invMobList[_selectedMob]._mask, _script->_scriptInfo.invObjExam);
+ if (invObjExamEvent == -1) {
+ // do_standard
+ printAt(0, 216, (char *)_invMobList[_selectedMob]._examText.c_str(), kNormalWidth / 2, _invExamY);
+ _interpreter->setCurrentString(_invMobList[_selectedMob]._mask + 70000);
+ setVoice(0, 28, 1);
+ playSample(28, 0);
+ // disableuseuse
+ changeCursor(0);
+ _currentPointerNumber = 1;
+ } else {
+ _interpreter->storeNewPC(invObjExamEvent);
+ _flags->setFlagValue(Flags::CURRMOB, _invMobList[_selectedMob]._mask);
+ _showInventoryFlag = false;
+ }
+ } else if (_optionEnabled == 1) {
+ // not_examine
+ int invObjUse = _script->scanMobEvents(_invMobList[_selectedMob]._mask, _script->_scriptInfo.invObjUse);
+ if (invObjUse == -1) {
+ // do_standard_use
+ _selectedMode = 0;
+ _selectedItem = _invMobList[_selectedMob]._mask;
+ makeInvCursor(_invMobList[_selectedMob]._mask);
+ _currentPointerNumber = 2;
+ changeCursor(2);
+ } else {
+ _interpreter->storeNewPC(invObjUse);
+ _flags->setFlagValue(Flags::CURRMOB, _invMobList[_selectedMob]._mask);
+ _showInventoryFlag = false;
+ }
+ } else if (_optionEnabled == 4) {
+ // do_standard_give
+ _selectedMode = 1;
+ _selectedItem = _invMobList[_selectedMob]._mask;
+ makeInvCursor(_invMobList[_selectedMob]._mask);
+ _currentPointerNumber = 2;
+ changeCursor(2);
+ } else {
+ // use_item_on_item
+ int invObjUU = _script->scanMobEventsWithItem(_invMobList[_selectedMob]._mask, _script->_scriptInfo.invObjUU, _selectedItem);
+ if (invObjUU == -1) {
+ int textNr = 80011; // "I can't do it."
+ if (_selectedItem == 31 || _invMobList[_selectedMob]._mask == 31) {
+ textNr = 80020; // "Nothing is happening."
+ }
+ _interpreter->setCurrentString(textNr);
+ printAt(0, 216, (char *)_variaTxt->getString(textNr - 80000), kNormalWidth / 2, 100);
+ setVoice(0, 28, 1);
+ playSample(28, 0);
+ } else {
+ _interpreter->storeNewPC(invObjUU);
+ _flags->setFlagValue(Flags::CURRMOB, _invMobList[_selectedMob]._mask);
+ _showInventoryFlag = false;
+ }
+ }
+ _selectedMob = -1;
+ _optionsMob = -1;
+}
+
+void PrinceEngine::inventoryRightMouseButton() {
+ if (_textSlots[0]._str == nullptr) {
+ enableOptions(false);
+ }
+}
+
+void PrinceEngine::enableOptions(bool checkType) {
+ if (_optionsFlag != 1) {
+ changeCursor(1);
+ _currentPointerNumber = 1;
+ if (_selectedMob != -1) {
+ if (checkType) {
+ if (_mobList[_selectedMob]._type & 0x100) {
+ return;
+ }
+ }
+ Common::Point mousePos = _system->getEventManager()->getMousePos();
+ int x1 = mousePos.x - _optionsWidth / 2;
+ int x2 = mousePos.x + _optionsWidth / 2;
+ if (x1 < 0) {
+ x1 = 0;
+ x2 = _optionsWidth;
+ } else if (x2 >= kNormalWidth) {
+ x1 = kNormalWidth - _optionsWidth;
+ x2 = kNormalWidth;
+ }
+ int y1 = mousePos.y - 10;
+ if (y1 < 0) {
+ y1 = 0;
+ }
+ if (y1 + _optionsHeight >= kNormalHeight) {
+ y1 = kNormalHeight - _optionsHeight;
+ }
+ _optionsMob = _selectedMob;
+ _optionsX = x1;
+ _optionsY = y1;
+ _optionsFlag = 1;
+ }
+ }
+}
+
+void PrinceEngine::checkOptions() {
+ if (_optionsFlag) {
+ Common::Rect optionsRect(_optionsX, _optionsY, _optionsX + _optionsWidth, _optionsY + _optionsHeight);
+ Common::Point mousePos = _system->getEventManager()->getMousePos();
+ if (!optionsRect.contains(mousePos)) {
+ _optionsFlag = 0;
+ _selectedMob = -1;
+ return;
+ }
+ _graph->drawAsShadowSurface(_graph->_frontScreen, _optionsX, _optionsY, _optionsPic, _graph->_shadowTable50);
+
+ _optionEnabled = -1;
+ int optionsYCord = mousePos.y - (_optionsY + 16);
+ if (optionsYCord >= 0) {
+ int selectedOptionNr = optionsYCord / _optionsStep;
+ if (selectedOptionNr < _optionsNumber) {
+ _optionEnabled = selectedOptionNr;
+ }
+ }
+ int optionsColor;
+ int textY = _optionsY + 16;
+ for (int i = 0; i < _optionsNumber; i++) {
+ if (i != _optionEnabled) {
+ optionsColor = _optionsColor1;
+ } else {
+ optionsColor = _optionsColor2;
+ }
+ Common::String optText;
+ switch(getLanguage()) {
+ case Common::PL_POL:
+ optText = optionsTextPL[i];
+ break;
+ case Common::DE_DEU:
+ optText = optionsTextDE[i];
+ break;
+ case Common::EN_ANY:
+ optText = optionsTextEN[i];
+ break;
+ default:
+ break;
+ };
+ uint16 textW = getTextWidth(optText.c_str());
+ uint16 textX = _optionsX + _optionsWidth / 2 - textW / 2;
+ _font->drawString(_graph->_frontScreen, optText, textX, textY, textW, optionsColor);
+ textY += _optionsStep;
+ }
+ }
+}
+
+void PrinceEngine::checkInvOptions() {
+ if (_optionsFlag) {
+ Common::Rect optionsRect(_optionsX, _optionsY, _optionsX + _invOptionsWidth, _optionsY + _invOptionsHeight);
+ Common::Point mousePos = _system->getEventManager()->getMousePos();
+ if (!optionsRect.contains(mousePos)) {
+ _optionsFlag = 0;
+ _selectedMob = -1;
+ return;
+ }
+ _graph->drawAsShadowSurface(_graph->_screenForInventory, _optionsX, _optionsY, _optionsPicInInventory, _graph->_shadowTable50);
+
+ _optionEnabled = -1;
+ int optionsYCord = mousePos.y - (_optionsY + 16);
+ if (optionsYCord >= 0) {
+ int selectedOptionNr = optionsYCord / _invOptionsStep;
+ if (selectedOptionNr < _invOptionsNumber) {
+ _optionEnabled = selectedOptionNr;
+ }
+ }
+ int optionsColor;
+ int textY = _optionsY + 16;
+ for (int i = 0; i < _invOptionsNumber; i++) {
+ if (i != _optionEnabled) {
+ optionsColor = _optionsColor1;
+ } else {
+ optionsColor = _optionsColor2;
+ }
+ Common::String invText;
+ switch(getLanguage()) {
+ case Common::PL_POL:
+ invText = invOptionsTextPL[i];
+ break;
+ case Common::DE_DEU:
+ invText = invOptionsTextDE[i];
+ break;
+ case Common::EN_ANY:
+ invText = invOptionsTextEN[i];
+ break;
+ default:
+ error("Unknown game language %d", getLanguage());
+ break;
+ };
+ uint16 textW = getTextWidth(invText.c_str());
+ uint16 textX = _optionsX + _invOptionsWidth / 2 - textW / 2;
+ _font->drawString(_graph->_screenForInventory, invText, textX, textY, _graph->_screenForInventory->w, optionsColor);
+ textY += _invOptionsStep;
+ }
+ }
+}
+
+void PrinceEngine::displayInventory() {
+
+ _mainHero->freeOldMove();
+ _secondHero->freeOldMove();
+
+ _interpreter->setFgOpcodePC(0);
+
+ stopAllSamples();
+
+ prepareInventoryToView();
+
+ while (!shouldQuit()) {
+
+ if (_textSlots[0]._str != nullptr) {
+ changeCursor(0);
+ } else {
+ changeCursor(_currentPointerNumber);
+
+ Common::Rect inventoryRect(_invX1, _invY1, _invX1 + _invWidth, _invY1 + _invHeight);
+ Common::Point mousePos = _system->getEventManager()->getMousePos();
+
+ if (!_invCurInside && inventoryRect.contains(mousePos)) {
+ _invCurInside = true;
+ }
+
+ if (_invCurInside && !inventoryRect.contains(mousePos)) {
+ inventoryFlagChange(false);
+ _invCurInside = false;
+ break;
+ }
+ }
+
+ rememberScreenInv();
+
+ Graphics::Surface *suitcase = _suitcaseBmp->getSurface();
+ _graph->drawTransparentSurface(_graph->_screenForInventory, 0, 0, suitcase);
+
+ drawInvItems();
+
+ showTexts(_graph->_screenForInventory);
+
+ if (!_optionsFlag && _textSlots[0]._str == nullptr) {
+ _selectedMob = checkMob(_graph->_screenForInventory, _invMobList, false);
+ }
+
+ checkInvOptions();
+
+ Common::Event event;
+ Common::EventManager *eventMan = _system->getEventManager();
+ while (eventMan->pollEvent(event)) {
+ switch (event.type) {
+ case Common::EVENT_KEYDOWN:
+ keyHandler(event);
+ break;
+ case Common::EVENT_LBUTTONDOWN:
+ inventoryLeftMouseButton();
+ break;
+ case Common::EVENT_RBUTTONDOWN:
+ inventoryRightMouseButton();
+ break;
+ default:
+ break;
+ }
+ }
+
+ if (!_showInventoryFlag) {
+ break;
+ }
+
+ if (shouldQuit())
+ return;
+
+ getDebugger()->onFrame();
+ _graph->update(_graph->_screenForInventory);
+ pausePrinceEngine();
+ }
+
+ if (_currentPointerNumber == 2) {
+ _flags->setFlagValue(Flags::SELITEM, _selectedItem);
+ } else {
+ _flags->setFlagValue(Flags::SELITEM, 0);
+ }
+}
+
+void PrinceEngine::createDialogBox(int dialogBoxNr) {
+ _dialogLines = 0;
+ int amountOfDialogOptions = 0;
+ int dialogDataValue = (int)READ_LE_UINT32(_dialogData);
+
+ byte c;
+ int sentenceNumber;
+ _dialogText = _dialogBoxAddr[dialogBoxNr];
+ byte *dialogText = _dialogText;
+
+ while ((sentenceNumber = *dialogText) != 0xFF) {
+ dialogText++;
+ if (!(dialogDataValue & (1 << sentenceNumber))) {
+ _dialogLines += calcTextLines((const char *)dialogText);
+ amountOfDialogOptions++;
+ }
+ do {
+ c = *dialogText;
+ dialogText++;
+ } while (c);
+ }
+
+ _dialogHeight = _font->getFontHeight() * _dialogLines + _dialogLineSpace * (amountOfDialogOptions + 1);
+ _dialogImage = new Graphics::Surface();
+ _dialogImage->create(_dialogWidth, _dialogHeight, Graphics::PixelFormat::createFormatCLUT8());
+ Common::Rect dBoxRect(0, 0, _dialogWidth, _dialogHeight);
+ _dialogImage->fillRect(dBoxRect, _graph->kShadowColor);
+}
+
+void PrinceEngine::dialogRun() {
+
+ _dialogFlag = true;
+
+ while (!shouldQuit()) {
+
+ _interpreter->stepBg();
+ drawScreen();
+
+ int dialogX = (640 - _dialogWidth) / 2;
+ int dialogY = 460 - _dialogHeight;
+ _graph->drawAsShadowSurface(_graph->_frontScreen, dialogX, dialogY, _dialogImage, _graph->_shadowTable50);
+
+ int dialogSkipLeft = 14;
+ int dialogSkipUp = 10;
+
+ int dialogTextX = dialogX + dialogSkipLeft;
+ int dialogTextY = dialogY + dialogSkipUp;
+
+ Common::Point mousePos = _system->getEventManager()->getMousePos();
+
+ byte c;
+ int sentenceNumber;
+ byte *dialogText = _dialogText;
+ byte *dialogCurrentText = nullptr;
+ int dialogSelected = -1;
+ int dialogDataValue = (int)READ_LE_UINT32(_dialogData);
+
+ while ((sentenceNumber = *dialogText) != 0xFF) {
+ dialogText++;
+ int actualColor = _dialogColor1;
+
+ if (!(dialogDataValue & (1 << sentenceNumber))) {
+ if (getLanguage() == Common::DE_DEU) {
+ correctStringDEU((char *)dialogText);
+ }
+ Common::Array<Common::String> lines;
+ _font->wordWrapText((const char *)dialogText, _graph->_frontScreen->w, lines);
+
+ Common::Rect dialogOption(dialogTextX, dialogTextY - dialogSkipUp / 2, dialogX + _dialogWidth - dialogSkipLeft, dialogTextY + lines.size() * _font->getFontHeight() + dialogSkipUp / 2 - 1);
+ if (dialogOption.contains(mousePos)) {
+ actualColor = _dialogColor2;
+ dialogSelected = sentenceNumber;
+ dialogCurrentText = dialogText;
+ }
+
+ for (uint j = 0; j < lines.size(); j++) {
+ _font->drawString(_graph->_frontScreen, lines[j], dialogTextX, dialogTextY, _graph->_frontScreen->w, actualColor);
+ dialogTextY += _font->getFontHeight();
+ }
+ dialogTextY += _dialogLineSpace;
+ }
+ do {
+ c = *dialogText;
+ dialogText++;
+ } while (c);
+ }
+
+ Common::Event event;
+ Common::EventManager *eventMan = _system->getEventManager();
+ while (eventMan->pollEvent(event)) {
+ switch (event.type) {
+ case Common::EVENT_KEYDOWN:
+ keyHandler(event);
+ break;
+ case Common::EVENT_LBUTTONDOWN:
+ if (dialogSelected != -1) {
+ dialogLeftMouseButton(dialogCurrentText, dialogSelected);
+ _dialogFlag = false;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+ if (shouldQuit()) {
+ return;
+ }
+
+ if (!_dialogFlag) {
+ break;
+ }
+
+ getDebugger()->onFrame();
+ _graph->update(_graph->_frontScreen);
+ pausePrinceEngine();
+ }
+ _dialogImage->free();
+ delete _dialogImage;
+ _dialogImage = nullptr;
+ _dialogFlag = false;
+}
+
+void PrinceEngine::dialogLeftMouseButton(byte *string, int dialogSelected) {
+ _interpreter->setString(string);
+ talkHero(0);
+
+ int dialogDataValue = (int)READ_LE_UINT32(_dialogData);
+ dialogDataValue |= (1u << dialogSelected);
+ WRITE_LE_UINT32(_dialogData, dialogDataValue);
+
+ _flags->setFlagValue(Flags::BOXSEL, dialogSelected + 1);
+ setVoice(0, 28, dialogSelected + 1);
+
+ _flags->setFlagValue(Flags::VOICE_H_LINE, _dialogOptLines[dialogSelected * 4]);
+ _flags->setFlagValue(Flags::VOICE_A_LINE, _dialogOptLines[dialogSelected * 4 + 1]);
+ _flags->setFlagValue(Flags::VOICE_B_LINE, _dialogOptLines[dialogSelected * 4 + 2]);
+
+ _interpreter->setString(_dialogOptAddr[dialogSelected]);
+}
+
+void PrinceEngine::talkHero(int slot) {
+ // heroSlot = textSlot (slot 0 or 1)
+ Text &text = _textSlots[slot];
+ int lines = calcTextLines((const char *)_interpreter->getString());
+ int time = lines * 30;
+
+ if (slot == 0) {
+ text._color = 220; // TODO - test this
+ _mainHero->_state = Hero::kHeroStateTalk;
+ _mainHero->_talkTime = time;
+ text._x = _mainHero->_middleX;
+ text._y = _mainHero->_middleY - _mainHero->_scaledFrameYSize;
+ } else {
+ text._color = _flags->getFlagValue(Flags::KOLOR); // TODO - test this
+ _secondHero->_state = Hero::kHeroStateTalk;
+ _secondHero->_talkTime = time;
+ text._x = _secondHero->_middleX;
+ text._y = _secondHero->_middleY - _secondHero->_scaledFrameYSize;
+ }
+ text._time = time;
+ if (getLanguage() == Common::DE_DEU) {
+ correctStringDEU((char *)_interpreter->getString());
+ }
+ text._str = (const char *)_interpreter->getString();
+ _interpreter->increaseString();
+}
+
+void PrinceEngine::doTalkAnim(int animNumber, int slot, AnimType animType) {
+ Text &text = _textSlots[slot];
+ int lines = calcTextLines((const char *)_interpreter->getString());
+ int time = lines * 30;
+ if (animType == kNormalAnimation) {
+ Anim &normAnim = _normAnimList[animNumber];
+ if (normAnim._animData != nullptr) {
+ if (!normAnim._state) {
+ if (normAnim._currW && normAnim._currH) {
+ text._color = _flags->getFlagValue(Flags::KOLOR);
+ text._x = normAnim._currX + normAnim._currW / 2;
+ text._y = normAnim._currY - 10;
+ }
+ }
+ }
+ } else if (animType == kBackgroundAnimation) {
+ if (!_backAnimList[animNumber].backAnims.empty()) {
+ int currAnim = _backAnimList[animNumber]._seq._currRelative;
+ Anim &backAnim = _backAnimList[animNumber].backAnims[currAnim];
+ if (backAnim._animData != nullptr) {
+ if (!backAnim._state) {
+ if (backAnim._currW && backAnim._currH) {
+ text._color = _flags->getFlagValue(Flags::KOLOR);
+ text._x = backAnim._currX + backAnim._currW / 2;
+ text._y = backAnim._currY - 10;
+ }
+ }
+ }
+ }
+ } else {
+ error("doTalkAnim() - wrong animType: %d", animType);
+ }
+ text._time = time;
+ if (getLanguage() == Common::DE_DEU) {
+ correctStringDEU((char *)_interpreter->getString());
+ }
+ text._str = (const char *)_interpreter->getString();
+ _interpreter->increaseString();
+}
+
+void PrinceEngine::freeNormAnim(int slot) {
+ if (!_normAnimList.empty()) {
+ _normAnimList[slot]._state = 1;
+ if (_normAnimList[slot]._animData != nullptr) {
+ delete _normAnimList[slot]._animData;
+ _normAnimList[slot]._animData = nullptr;
+ }
+ if (_normAnimList[slot]._shadowData != nullptr) {
+ delete _normAnimList[slot]._shadowData;
+ _normAnimList[slot]._shadowData = nullptr;
+ }
+ }
+}
+
+void PrinceEngine::freeAllNormAnims() {
+ for (int i = 0; i < kMaxNormAnims; i++) {
+ freeNormAnim(i);
+ }
+}
+
+void PrinceEngine::getCurve() {
+ _flags->setFlagValue(Flags::TORX1, _curveData[_curvPos]);
+ _flags->setFlagValue(Flags::TORY1, _curveData[_curvPos + 1]);
+ _curvPos += 2;
+}
+
+void PrinceEngine::makeCurve() {
+ _curvPos = 0;
+ int x1 = _flags->getFlagValue(Flags::TORX1);
+ int y1 = _flags->getFlagValue(Flags::TORY1);
+ int x2 = _flags->getFlagValue(Flags::TORX2);
+ int y2 = _flags->getFlagValue(Flags::TORY2);
+
+ for (int i = 0; i < kCurveLen; i++) {
+ int sum1 = x1 * curveValues[i][0];
+ sum1 += (x2 + (x1 - x2) / 2) * curveValues[i][1];
+ sum1 += x2 * curveValues[i][2];
+ sum1 += x2 * curveValues[i][3];
+
+ int sum2 = y1 * curveValues[i][0];
+ sum2 += (y2 - 20) * curveValues[i][1];
+ sum2 += (y2 - 10) * curveValues[i][2];
+ sum2 += y2 * curveValues[i][3];
+
+ _curveData[i * 2] = (sum1 >> 15);
+ _curveData[i * 2 + 1] = (sum2 >> 15);
+ }
+}
+
+void PrinceEngine::mouseWeirdo() {
+ if (_mouseFlag == 3) {
+ int weirdDir = _randomSource.getRandomNumber(3);
+ Common::Point mousePos = _system->getEventManager()->getMousePos();
+ switch (weirdDir) {
+ case 0:
+ mousePos.x += kCelStep;
+ break;
+ case 1:
+ mousePos.x -= kCelStep;
+ break;
+ case 2:
+ mousePos.y += kCelStep;
+ break;
+ case 3:
+ mousePos.y -= kCelStep;
+ break;
+ }
+ mousePos.x = CLIP(mousePos.x, (int16) 315, (int16) 639);
+ _flags->setFlagValue(Flags::MXFLAG, mousePos.x);
+ mousePos.y = CLIP(mousePos.y, (int16) 0, (int16) 170);
+ _flags->setFlagValue(Flags::MYFLAG, mousePos.y);
+ _system->warpMouse(mousePos.x, mousePos.y);
+ }
+}
+
+void PrinceEngine::showPower() {
+ if (_flags->getFlagValue(Flags::POWERENABLED)) {
+ int power = _flags->getFlagValue(Flags::POWER);
+
+ byte *dst = (byte *)_graph->_frontScreen->getBasePtr(kPowerBarPosX, kPowerBarPosY);
+ for (int y = 0; y < kPowerBarHeight; y++) {
+ byte *dst2 = dst;
+ for (int x = 0; x < kPowerBarWidth; x++, dst2++) {
+ *dst2 = kPowerBarBackgroundColor;
+ }
+ dst += _graph->_frontScreen->pitch;
+ }
+
+ if (power) {
+ dst = (byte *)_graph->_frontScreen->getBasePtr(kPowerBarPosX, kPowerBarGreenPosY);
+ for (int y = 0; y < kPowerBarGreenHeight; y++) {
+ byte *dst2 = dst;
+ for (int x = 0; x < power + 1; x++, dst2++) {
+ if (x < 58) {
+ *dst2 = kPowerBarGreenColor1;
+ } else {
+ *dst2 = kPowerBarGreenColor2;
+ }
+ }
+ dst += _graph->_frontScreen->pitch;
+ }
+ }
+
+ _graph->change();
+ }
+}
+
+void PrinceEngine::scrollCredits() {
+ byte *scrollAdress = _creditsData;
+ while (!shouldQuit()) {
+ for (int scrollPos = 0; scrollPos > -23; scrollPos--) {
+ const Graphics::Surface *roomSurface = _roomBmp->getSurface();
+ if (roomSurface) {
+ _graph->draw(_graph->_frontScreen, roomSurface);
+ }
+ char *s = (char *)scrollAdress;
+ int drawY = scrollPos;
+ for (int i = 0; i < 22; i++) {
+ Common::String line;
+ char *linePos = s;
+ while ((*linePos != 13)) {
+ line += *linePos;
+ linePos++;
+ }
+ if (!line.empty()) {
+ int drawX = (kNormalWidth - getTextWidth(line.c_str())) / 2;
+ _font->drawString(_graph->_frontScreen, line, drawX, drawY, _graph->_frontScreen->w, 217);
+ }
+
+ char letter1;
+ bool gotIt1 = false;
+ do {
+ letter1 = *s;
+ s++;
+ if (letter1 == 13) {
+ if (*s == 10) {
+ s++;
+ }
+ if (*s != 35) {
+ gotIt1 = true;
+ }
+ break;
+ }
+ } while (letter1 != 35);
+
+ if (gotIt1) {
+ drawY += 23;
+ } else {
+ break;
+ }
+ }
+ Common::Event event;
+ Common::EventManager *eventMan = _system->getEventManager();
+ while (eventMan->pollEvent(event)) {
+ if (event.type == Common::EVENT_KEYDOWN) {
+ if (event.kbd.keycode == Common::KEYCODE_ESCAPE) {
+ blackPalette();
+ return;
+ }
+ }
+ }
+ if (shouldQuit()) {
+ return;
+ }
+ _graph->change();
+ _graph->update(_graph->_frontScreen);
+ pausePrinceEngine(kFPS * 2);
+ }
+ char letter2;
+ byte *scan2 = scrollAdress;
+ bool gotIt2 = false;
+ do {
+ letter2 = *scan2;
+ scan2++;
+ if (letter2 == 13) {
+ if (*scan2 == 10) {
+ scan2++;
+ }
+ if (*scan2 != 35) {
+ gotIt2 = true;
+ }
+ break;
+ }
+ } while (letter2 != 35);
+ if (gotIt2) {
+ scrollAdress = scan2;
+ } else {
+ break;
+ }
+ }
+ blackPalette();
+}
+
+// Modified version of Graphics::drawLine() to allow breaking the loop and return value
+int PrinceEngine::drawLine(int x0, int y0, int x1, int y1, int (*plotProc)(int, int, void *), void *data) {
+ // Bresenham's line algorithm, as described by Wikipedia
+ const bool steep = ABS(y1 - y0) > ABS(x1 - x0);
+
+ if (steep) {
+ SWAP(x0, y0);
+ SWAP(x1, y1);
+ }
+
+ const int delta_x = ABS(x1 - x0);
+ const int delta_y = ABS(y1 - y0);
+ const int delta_err = delta_y;
+ int x = x0;
+ int y = y0;
+ int err = 0;
+
+ const int x_step = (x0 < x1) ? 1 : -1;
+ const int y_step = (y0 < y1) ? 1 : -1;
+
+ int stopFlag = 0;
+ if (steep)
+ stopFlag = (*plotProc)(y, x, data);
+ else
+ stopFlag = (*plotProc)(x, y, data);
+
+ while (x != x1 && !stopFlag) {
+ x += x_step;
+ err += delta_err;
+ if (2 * err > delta_x) {
+ y += y_step;
+ err -= delta_x;
+ }
+ if (steep)
+ stopFlag = (*plotProc)(y, x, data);
+ else
+ stopFlag = (*plotProc)(x, y, data);
+ }
+ return stopFlag;
+}
+
+int PrinceEngine::getPixelAddr(byte *pathBitmap, int x, int y) {
+ int mask = 128 >> (x & 7);
+ byte value = pathBitmap[x / 8 + y * 80];
+ return (mask & value);
+}
+
+void PrinceEngine::findPoint(int x, int y) {
+ _fpX = x;
+ _fpY = y;
+
+ if (getPixelAddr(_roomPathBitmap, x, y)) {
+ return;
+ }
+
+ int fpL = x;
+ int fpU = y;
+ int fpR = x;
+ int fpD = y;
+
+ while (1) {
+ if (fpD != kMaxPicHeight) {
+ if (getPixelAddr(_roomPathBitmap, x, fpD)) {
+ _fpX = x;
+ _fpY = fpD;
+ break;
+ }
+ fpD++;
+ }
+ if (fpU) {
+ if (getPixelAddr(_roomPathBitmap, x, fpU)) {
+ _fpX = x;
+ _fpY = fpU;
+ break;
+ }
+ fpU--;
+ }
+ if (fpL) {
+ if (getPixelAddr(_roomPathBitmap, fpL, y)) {
+ _fpX = fpL;
+ _fpY = y;
+ break;
+ }
+ fpL--;
+ }
+ if (fpR != _sceneWidth) {
+ if (getPixelAddr(_roomPathBitmap, fpR, y)) {
+ _fpX = fpR;
+ _fpY = y;
+ break;
+ }
+ fpR++;
+ }
+ if (!fpU && (fpD == kMaxPicHeight)) {
+ if (!fpL && (fpR == _sceneWidth)) {
+ break;
+ }
+ }
+ }
+}
+
+Direction PrinceEngine::makeDirection(int x1, int y1, int x2, int y2) {
+ if (x1 != x2) {
+ if (y1 != y2) {
+ if (x1 > x2) {
+ if (y1 > y2) {
+ if (x1 - x2 >= y1 - y2) {
+ return kDirLU;
+ } else {
+ return kDirUL;
+ }
+ } else {
+ if (x1 - x2 >= y2 - y1) {
+ return kDirLD;
+ } else {
+ return kDirDL;
+ }
+ }
+ } else {
+ if (y1 > y2) {
+ if (x2 - x1 >= y1 - y2) {
+ return kDirRU;
+ } else {
+ return kDirUR;
+ }
+ } else {
+ if (x2 - x1 >= y2 - y1) {
+ return kDirRD;
+ } else {
+ return kDirDR;
+ }
+ }
+ }
+ } else {
+ if (x1 >= x2) {
+ return kDirL;
+ } else {
+ return kDirR;
+ }
+ }
+ } else {
+ if (y1 >= y2) {
+ return kDirU;
+ } else {
+ return kDirD;
+ }
+ }
+}
+
+void PrinceEngine::specialPlot(int x, int y) {
+ if (_coords < _coordsBufEnd) {
+ WRITE_LE_UINT16(_coords, x);
+ _coords += 2;
+ WRITE_LE_UINT16(_coords, y);
+ _coords += 2;
+ specialPlot2(x, y);
+ }
+}
+
+void PrinceEngine::specialPlot2(int x, int y) {
+ int mask = 128 >> (x & 7);
+ _roomPathBitmapTemp[x / 8 + y * 80] |= mask;
+}
+
+void PrinceEngine::specialPlotInside(int x, int y) {
+ if (_coords < _coordsBufEnd) {
+ WRITE_LE_UINT16(_coords, x);
+ _coords += 2;
+ WRITE_LE_UINT16(_coords, y);
+ _coords += 2;
+ }
+}
+
+int PrinceEngine::plotTraceLine(int x, int y, void *data) {
+ PrinceEngine *traceLine = (PrinceEngine *)data;
+ if (!traceLine->_traceLineFirstPointFlag) {
+ if (!traceLine->getPixelAddr(traceLine->_roomPathBitmapTemp, x, y)) {
+ if (traceLine->getPixelAddr(traceLine->_roomPathBitmap, x, y)) {
+ traceLine->specialPlotInside(x, y);
+ traceLine->_traceLineLen++;
+ return 0;
+ } else {
+ return -1;
+ }
+ } else {
+ return 1;
+ }
+ } else {
+ traceLine->_traceLineFirstPointFlag = false;
+ return 0;
+ }
+}
+
+int PrinceEngine::leftDownDir() {
+ if (!checkLeftDownDir()) {
+ specialPlot(_checkX, _checkY);
+ return 0;
+ }
+ if (!checkLeftDir()) {
+ specialPlot(_checkX, _checkY);
+ return 0;
+ }
+ if (!checkDownDir()) {
+ specialPlot(_checkX, _checkY);
+ return 0;
+ }
+ if (!checkLeftUpDir()) {
+ specialPlot(_checkX, _checkY);
+ return 0;
+ }
+ if (!checkRightDownDir()) {
+ specialPlot(_checkX, _checkY);
+ return 0;
+ }
+ if (!checkUpDir()) {
+ specialPlot(_checkX, _checkY);
+ return 0;
+ }
+ if (!checkRightDir()) {
+ specialPlot(_checkX, _checkY);
+ return 0;
+ }
+ if (!checkRightUpDir()) {
+ specialPlot(_checkX, _checkY);
+ return 0;
+ }
+ return -1;
+}
+
+int PrinceEngine::leftDir() {
+ if (!checkLeftDir()) {
+ specialPlot(_checkX, _checkY);
+ return 0;
+ }
+ if (!checkLeftUpDir()) {
+ specialPlot(_checkX, _checkY);
+ return 0;
+ }
+ if (!checkLeftDownDir()) {
+ specialPlot(_checkX, _checkY);
+ return 0;
+ }
+ if (!checkUpDir()) {
+ specialPlot(_checkX, _checkY);
+ return 0;
+ }
+ if (!checkDownDir()) {
+ specialPlot(_checkX, _checkY);
+ return 0;
+ }
+ if (!checkRightUpDir()) {
+ specialPlot(_checkX, _checkY);
+ return 0;
+ }
+ if (!checkRightDownDir()) {
+ specialPlot(_checkX, _checkY);
+ return 0;
+ }
+ if (!checkRightDir()) {
+ specialPlot(_checkX, _checkY);
+ return 0;
+ }
+ return -1;
+}
+
+int PrinceEngine::leftUpDir() {
+ if (!checkLeftUpDir()) {
+ specialPlot(_checkX, _checkY);
+ return 0;
+ }
+ if (!checkLeftDir()) {
+ specialPlot(_checkX, _checkY);
+ return 0;
+ }
+ if (!checkUpDir()) {
+ specialPlot(_checkX, _checkY);
+ return 0;
+ }
+ if (!checkLeftDownDir()) {
+ specialPlot(_checkX, _checkY);
+ return 0;
+ }
+ if (!checkRightUpDir()) {
+ specialPlot(_checkX, _checkY);
+ return 0;
+ }
+ if (!checkDownDir()) {
+ specialPlot(_checkX, _checkY);
+ return 0;
+ }
+ if (!checkRightDir()) {
+ specialPlot(_checkX, _checkY);
+ return 0;
+ }
+ if (!checkRightDownDir()) {
+ specialPlot(_checkX, _checkY);
+ return 0;
+ }
+ return -1;
+}
+
+int PrinceEngine::rightDownDir() {
+ if (!checkRightDownDir()) {
+ specialPlot(_checkX, _checkY);
+ return 0;
+ }
+ if (!checkRightDir()) {
+ specialPlot(_checkX, _checkY);
+ return 0;
+ }
+ if (!checkDownDir()) {
+ specialPlot(_checkX, _checkY);
+ return 0;
+ }
+ if (!checkRightUpDir()) {
+ specialPlot(_checkX, _checkY);
+ return 0;
+ }
+ if (!checkLeftDownDir()) {
+ specialPlot(_checkX, _checkY);
+ return 0;
+ }
+ if (!checkUpDir()) {
+ specialPlot(_checkX, _checkY);
+ return 0;
+ }
+ if (!checkLeftDir()) {
+ specialPlot(_checkX, _checkY);
+ return 0;
+ }
+ if (!checkLeftUpDir()) {
+ specialPlot(_checkX, _checkY);
+ return 0;
+ }
+ return -1;
+}
+
+int PrinceEngine::rightDir() {
+ if (!checkRightDir()) {
+ specialPlot(_checkX, _checkY);
+ return 0;
+ }
+ if (!checkRightUpDir()) {
+ specialPlot(_checkX, _checkY);
+ return 0;
+ }
+ if (!checkRightDownDir()) {
+ specialPlot(_checkX, _checkY);
+ return 0;
+ }
+ if (!checkUpDir()) {
+ specialPlot(_checkX, _checkY);
+ return 0;
+ }
+ if (!checkDownDir()) {
+ specialPlot(_checkX, _checkY);
+ return 0;
+ }
+ if (!checkLeftUpDir()) {
+ specialPlot(_checkX, _checkY);
+ return 0;
+ }
+ if (!checkLeftDownDir()) {
+ specialPlot(_checkX, _checkY);
+ return 0;
+ }
+ if (!checkLeftDir()) {
+ specialPlot(_checkX, _checkY);
+ return 0;
+ }
+ return -1;
+}
+
+int PrinceEngine::rightUpDir() {
+ if (!checkRightUpDir()) {
+ specialPlot(_checkX, _checkY);
+ return 0;
+ }
+ if (!checkRightDir()) {
+ specialPlot(_checkX, _checkY);
+ return 0;
+ }
+ if (!checkUpDir()) {
+ specialPlot(_checkX, _checkY);
+ return 0;
+ }
+ if (!checkRightDownDir()) {
+ specialPlot(_checkX, _checkY);
+ return 0;
+ }
+ if (!checkLeftUpDir()) {
+ specialPlot(_checkX, _checkY);
+ return 0;
+ }
+ if (!checkDownDir()) {
+ specialPlot(_checkX, _checkY);
+ return 0;
+ }
+ if (!checkLeftDir()) {
+ specialPlot(_checkX, _checkY);
+ return 0;
+ }
+ if (!checkLeftDownDir()) {
+ specialPlot(_checkX, _checkY);
+ return 0;
+ }
+ return -1;
+}
+
+int PrinceEngine::upLeftDir() {
+ if (!checkLeftUpDir()) {
+ specialPlot(_checkX, _checkY);
+ return 0;
+ }
+ if (!checkUpDir()) {
+ specialPlot(_checkX, _checkY);
+ return 0;
+ }
+ if (!checkLeftDir()) {
+ specialPlot(_checkX, _checkY);
+ return 0;
+ }
+ if (!checkRightUpDir()) {
+ specialPlot(_checkX, _checkY);
+ return 0;
+ }
+ if (!checkLeftDownDir()) {
+ specialPlot(_checkX, _checkY);
+ return 0;
+ }
+ if (!checkRightDir()) {
+ specialPlot(_checkX, _checkY);
+ return 0;
+ }
+ if (!checkDownDir()) {
+ specialPlot(_checkX, _checkY);
+ return 0;
+ }
+ if (!checkRightDownDir()) {
+ specialPlot(_checkX, _checkY);
+ return 0;
+ }
+ return -1;
+}
+
+int PrinceEngine::upDir() {
+ if (!checkUpDir()) {
+ specialPlot(_checkX, _checkY);
+ return 0;
+ }
+ if (!checkLeftUpDir()) {
+ specialPlot(_checkX, _checkY);
+ return 0;
+ }
+ if (!checkRightUpDir()) {
+ specialPlot(_checkX, _checkY);
+ return 0;
+ }
+ if (!checkLeftDir()) {
+ specialPlot(_checkX, _checkY);
+ return 0;
+ }
+ if (!checkRightDir()) {
+ specialPlot(_checkX, _checkY);
+ return 0;
+ }
+ if (!checkLeftDownDir()) {
+ specialPlot(_checkX, _checkY);
+ return 0;
+ }
+ if (!checkRightDownDir()) {
+ specialPlot(_checkX, _checkY);
+ return 0;
+ }
+ if (!checkDownDir()) {
+ specialPlot(_checkX, _checkY);
+ return 0;
+ }
+ return -1;
+}
+
+int PrinceEngine::upRightDir() {
+ if (!checkRightUpDir()) {
+ specialPlot(_checkX, _checkY);
+ return 0;
+ }
+ if (!checkUpDir()) {
+ specialPlot(_checkX, _checkY);
+ return 0;
+ }
+ if (!checkRightDir()) {
+ specialPlot(_checkX, _checkY);
+ return 0;
+ }
+ if (!checkLeftUpDir()) {
+ specialPlot(_checkX, _checkY);
+ return 0;
+ }
+ if (!checkRightDownDir()) {
+ specialPlot(_checkX, _checkY);
+ return 0;
+ }
+ if (!checkLeftDir()) {
+ specialPlot(_checkX, _checkY);
+ return 0;
+ }
+ if (!checkDownDir()) {
+ specialPlot(_checkX, _checkY);
+ return 0;
+ }
+ if (!checkLeftDownDir()) {
+ specialPlot(_checkX, _checkY);
+ return 0;
+ }
+ return -1;
+}
+
+int PrinceEngine::downLeftDir() {
+ if (!checkLeftDownDir()) {
+ specialPlot(_checkX, _checkY);
+ return 0;
+ }
+ if (!checkDownDir()) {
+ specialPlot(_checkX, _checkY);
+ return 0;
+ }
+ if (!checkLeftDir()) {
+ specialPlot(_checkX, _checkY);
+ return 0;
+ }
+ if (!checkRightDownDir()) {
+ specialPlot(_checkX, _checkY);
+ return 0;
+ }
+ if (!checkLeftUpDir()) {
+ specialPlot(_checkX, _checkY);
+ return 0;
+ }
+ if (!checkRightDir()) {
+ specialPlot(_checkX, _checkY);
+ return 0;
+ }
+ if (!checkUpDir()) {
+ specialPlot(_checkX, _checkY);
+ return 0;
+ }
+ if (!checkRightUpDir()) {
+ specialPlot(_checkX, _checkY);
+ return 0;
+ }
+ return -1;
+}
+
+int PrinceEngine::downDir() {
+ if (!checkDownDir()) {
+ specialPlot(_checkX, _checkY);
+ return 0;
+ }
+ if (!checkRightDownDir()) {
+ specialPlot(_checkX, _checkY);
+ return 0;
+ }
+ if (!checkLeftDownDir()) {
+ specialPlot(_checkX, _checkY);
+ return 0;
+ }
+ if (!checkRightDir()) {
+ specialPlot(_checkX, _checkY);
+ return 0;
+ }
+ if (!checkLeftDir()) {
+ specialPlot(_checkX, _checkY);
+ return 0;
+ }
+ if (!checkRightUpDir()) {
+ specialPlot(_checkX, _checkY);
+ return 0;
+ }
+ if (!checkLeftUpDir()) {
+ specialPlot(_checkX, _checkY);
+ return 0;
+ }
+ if (!checkUpDir()) {
+ specialPlot(_checkX, _checkY);
+ return 0;
+ }
+ return -1;
+}
+
+int PrinceEngine::downRightDir() {
+ if (!checkRightDownDir()) {
+ specialPlot(_checkX, _checkY);
+ return 0;
+ }
+ if (!checkDownDir()) {
+ specialPlot(_checkX, _checkY);
+ return 0;
+ }
+ if (!checkRightDir()) {
+ specialPlot(_checkX, _checkY);
+ return 0;
+ }
+ if (!checkLeftDownDir()) {
+ specialPlot(_checkX, _checkY);
+ return 0;
+ }
+ if (!checkRightUpDir()) {
+ specialPlot(_checkX, _checkY);
+ return 0;
+ }
+ if (!checkLeftDir()) {
+ specialPlot(_checkX, _checkY);
+ return 0;
+ }
+ if (!checkUpDir()) {
+ specialPlot(_checkX, _checkY);
+ return 0;
+ }
+ if (!checkLeftUpDir()) {
+ specialPlot(_checkX, _checkY);
+ return 0;
+ }
+ return -1;
+}
+
+int PrinceEngine::cpe() {
+ if ((*(_checkBitmap - kPBW) & _checkMask)) {
+ if ((*(_checkBitmap + kPBW) & _checkMask)) {
+ int value;
+ switch (_checkMask) {
+ case 128:
+ value = READ_LE_UINT16(_checkBitmap - 1);
+ value &= 0x4001;
+ if (value != 0x4001) {
+ return 0;
+ }
+ break;
+ case 64:
+ value = *_checkBitmap;
+ value &= 0xA0;
+ if (value != 0xA0) {
+ return 0;
+ }
+ break;
+ case 32:
+ value = *_checkBitmap;
+ value &= 0x50;
+ if (value != 0x50) {
+ return 0;
+ }
+ break;
+ case 16:
+ value = *_checkBitmap;
+ value &= 0x28;
+ if (value != 0x28) {
+ return 0;
+ }
+ break;
+ case 8:
+ value = *_checkBitmap;
+ value &= 0x14;
+ if (value != 0x14) {
+ return 0;
+ }
+ break;
+ case 4:
+ value = *_checkBitmap;
+ value &= 0xA;
+ if (value != 0xA) {
+ return 0;
+ }
+ break;
+ case 2:
+ value = *_checkBitmap;
+ value &= 0x5;
+ if (value != 0x5) {
+ return 0;
+ }
+ break;
+ case 1:
+ value = READ_LE_UINT16(_checkBitmap);
+ value &= 0x8002;
+ if (value != 0x8002) {
+ return 0;
+ }
+ break;
+ default:
+ error("Wrong _checkMask value - cpe()");
+ break;
+ }
+ _checkX = _rembX;
+ _checkY = _rembY;
+ _checkBitmapTemp = _rembBitmapTemp;
+ _checkBitmap = _rembBitmap;
+ _checkMask = _rembMask;
+ return -1;
+ }
+ return 0;
+ }
+ return 0;
+}
+
+int PrinceEngine::checkLeftDownDir() {
+ if (_checkX && _checkY != (kMaxPicHeight / 2 - 1)) {
+ int tempMask = _checkMask;
+ if (tempMask != 128) {
+ tempMask <<= 1;
+ if ((*(_checkBitmap + kPBW) & tempMask)) {
+ if (!(*(_checkBitmapTemp + kPBW) & tempMask)) {
+ _checkBitmap += kPBW;
+ _checkBitmapTemp += kPBW;
+ _checkMask = tempMask;
+ } else {
+ return 1;
+ }
+ } else {
+ return -1;
+ }
+ } else {
+ if ((*(_checkBitmap + kPBW - 1) & 1)) {
+ if (!(*(_checkBitmapTemp + kPBW - 1) & 1)) {
+ _checkBitmap += (kPBW - 1);
+ _checkBitmapTemp += (kPBW - 1);
+ _checkMask = 1;
+ } else {
+ return 1;
+ }
+ } else {
+ return -1;
+ }
+ }
+ _checkX--;
+ _checkY++;
+ return cpe();
+ } else {
+ return -1;
+ }
+}
+
+int PrinceEngine::checkLeftDir() {
+ if (_checkX) {
+ int tempMask = _checkMask;
+ if (tempMask != 128) {
+ tempMask <<= 1;
+ if ((*(_checkBitmap) & tempMask)) {
+ if (!(*(_checkBitmapTemp) & tempMask)) {
+ _checkMask = tempMask;
+ } else {
+ return 1;
+ }
+ } else {
+ return -1;
+ }
+ } else {
+ if ((*(_checkBitmap - 1) & 1)) {
+ if (!(*(_checkBitmapTemp - 1) & 1)) {
+ _checkBitmap--;
+ _checkBitmapTemp--;
+ _checkMask = 1;
+ } else {
+ return 1;
+ }
+ } else {
+ return -1;
+ }
+ }
+ _checkX--;
+ return cpe();
+ } else {
+ return -1;
+ }
+}
+
+int PrinceEngine::checkDownDir() {
+ if (_checkY != (kMaxPicHeight / 2 - 1)) {
+ if ((*(_checkBitmap + kPBW) & _checkMask)) {
+ if (!(*(_checkBitmapTemp + kPBW) & _checkMask)) {
+ _checkBitmap += kPBW;
+ _checkBitmapTemp += kPBW;
+ _checkY++;
+ return cpe();
+ } else {
+ return 1;
+ }
+ } else {
+ return -1;
+ }
+ } else {
+ return -1;
+ }
+}
+
+int PrinceEngine::checkUpDir() {
+ if (_checkY) {
+ if ((*(_checkBitmap - kPBW) & _checkMask)) {
+ if (!(*(_checkBitmapTemp - kPBW) & _checkMask)) {
+ _checkBitmap -= kPBW;
+ _checkBitmapTemp -= kPBW;
+ _checkY--;
+ return cpe();
+ } else {
+ return 1;
+ }
+ } else {
+ return -1;
+ }
+ } else {
+ return -1;
+ }
+}
+
+int PrinceEngine::checkRightDir() {
+ if (_checkX != (kMaxPicWidth / 2 - 1)) {
+ int tempMask = _checkMask;
+ if (tempMask != 1) {
+ tempMask >>= 1;
+ if ((*(_checkBitmap) & tempMask)) {
+ if (!(*(_checkBitmapTemp) & tempMask)) {
+ _checkMask = tempMask;
+ } else {
+ return 1;
+ }
+ } else {
+ return -1;
+ }
+ } else {
+ if ((*(_checkBitmap + 1) & 128)) {
+ if (!(*(_checkBitmapTemp + 1) & 128)) {
+ _checkBitmap++;
+ _checkBitmapTemp++;
+ _checkMask = 128;
+ } else {
+ return 1;
+ }
+ } else {
+ return -1;
+ }
+ }
+ _checkX++;
+ return cpe();
+ } else {
+ return -1;
+ }
+}
+
+int PrinceEngine::checkLeftUpDir() {
+ if (_checkX && _checkY) {
+ int tempMask = _checkMask;
+ if (tempMask != 128) {
+ tempMask <<= 1;
+ if ((*(_checkBitmap - kPBW) & tempMask)) {
+ if (!(*(_checkBitmapTemp - kPBW) & tempMask)) {
+ _checkBitmap -= kPBW;
+ _checkBitmapTemp -= kPBW;
+ _checkMask = tempMask;
+ } else {
+ return 1;
+ }
+ } else {
+ return -1;
+ }
+ } else {
+ if ((*(_checkBitmap - (kPBW + 1)) & 1)) {
+ if (!(*(_checkBitmapTemp - (kPBW + 1)) & 1)) {
+ _checkBitmap -= (kPBW + 1);
+ _checkBitmapTemp -= (kPBW + 1);
+ _checkMask = 1;
+ } else {
+ return 1;
+ }
+ } else {
+ return -1;
+ }
+ }
+ _checkX--;
+ _checkY--;
+ return cpe();
+ } else {
+ return -1;
+ }
+}
+
+int PrinceEngine::checkRightDownDir() {
+ if (_checkX != (kMaxPicWidth / 2 - 1) && _checkY != (kMaxPicHeight / 2 - 1)) {
+ int tempMask = _checkMask;
+ if (tempMask != 1) {
+ tempMask >>= 1;
+ if ((*(_checkBitmap + kPBW) & tempMask)) {
+ if (!(*(_checkBitmapTemp + kPBW) & tempMask)) {
+ _checkBitmap += kPBW;
+ _checkBitmapTemp += kPBW;
+ _checkMask = tempMask;
+ } else {
+ return 1;
+ }
+ } else {
+ return -1;
+ }
+ } else {
+ if ((*(_checkBitmap + kPBW + 1) & 128)) {
+ if (!(*(_checkBitmapTemp + kPBW + 1) & 128)) {
+ _checkBitmap += kPBW + 1;
+ _checkBitmapTemp += kPBW + 1;
+ _checkMask = 128;
+ } else {
+ return 1;
+ }
+ } else {
+ return -1;
+ }
+ }
+ _checkX++;
+ _checkY++;
+ return cpe();
+ } else {
+ return -1;
+ }
+}
+
+int PrinceEngine::checkRightUpDir() {
+ if (_checkX != (kMaxPicWidth / 2 - 1) && _checkY) {
+ int tempMask = _checkMask;
+ if (tempMask != 1) {
+ tempMask >>= 1;
+ if ((*(_checkBitmap - kPBW) & tempMask)) {
+ if (!(*(_checkBitmapTemp - kPBW) & tempMask)) {
+ _checkBitmap -= kPBW;
+ _checkBitmapTemp -= kPBW;
+ _checkMask = tempMask;
+ } else {
+ return 1;
+ }
+ } else {
+ return -1;
+ }
+ } else {
+ if ((*(_checkBitmap - kPBW + 1) & 128)) {
+ if (!(*(_checkBitmapTemp - kPBW + 1) & 128)) {
+ _checkBitmap -= (kPBW - 1);
+ _checkBitmapTemp -= (kPBW - 1);
+ _checkMask = 128;
+ } else {
+ return 1;
+ }
+ } else {
+ return -1;
+ }
+ }
+ _checkX++;
+ _checkY--;
+ return cpe();
+ } else {
+ return -1;
+ }
+}
+
+bool PrinceEngine::tracePath(int x1, int y1, int x2, int y2) {
+ for (uint i = 0; i < kPathBitmapLen; i++) {
+ _roomPathBitmapTemp[i] = 0;
+ }
+ if (x1 != x2 || y1 != y2) {
+ if (getPixelAddr(_roomPathBitmap, x1, y1)) {
+ if (getPixelAddr(_roomPathBitmap, x2, y2)) {
+ _coords = _coordsBuf;
+ specialPlot(x1, y1);
+
+ int x = x1;
+ int y = y1;
+
+ while (1) {
+ int btx = x;
+ int bty = y;
+ byte *bcad = _coords;
+
+ _traceLineLen = 0;
+ _traceLineFirstPointFlag = true;
+ int drawLineFlag = drawLine(x, y, x2, y2, &this->plotTraceLine, this);
+
+ if (!drawLineFlag) {
+ return true;
+ } else if (drawLineFlag == -1 && _traceLineLen >= 2) {
+ byte *tempCorrds = bcad;
+ while (tempCorrds != _coords) {
+ x = READ_LE_UINT16(tempCorrds);
+ y = READ_LE_UINT16(tempCorrds + 2);
+ tempCorrds += 4;
+ specialPlot2(x, y);
+ }
+ } else {
+ _coords = bcad;
+ x = btx;
+ y = bty;
+ }
+
+ Direction dir = makeDirection(x, y, x2, y2);
+
+ _rembBitmapTemp = &_roomPathBitmapTemp[x / 8 + y * 80];
+ _rembBitmap = &_roomPathBitmap[x / 8 + y * 80];
+ _rembMask = 128 >> (x & 7);
+ _rembX = x;
+ _rembY = y;
+
+ _checkBitmapTemp = _rembBitmapTemp;
+ _checkBitmap = _rembBitmap;
+ _checkMask = _rembMask;
+ _checkX = _rembX;
+ _checkY = _rembY;
+
+ int result;
+ switch (dir) {
+ case kDirLD:
+ result = leftDownDir();
+ break;
+ case kDirL:
+ result = leftDir();
+ break;
+ case kDirLU:
+ result = leftUpDir();
+ break;
+ case kDirRD:
+ result = rightDownDir();
+ break;
+ case kDirR:
+ result = rightDir();
+ break;
+ case kDirRU:
+ result = rightUpDir();
+ break;
+ case kDirUL:
+ result = upLeftDir();
+ break;
+ case kDirU:
+ result = upDir();
+ break;
+ case kDirUR:
+ result = upRightDir();
+ break;
+ case kDirDL:
+ result = downLeftDir();
+ break;
+ case kDirD:
+ result = downDir();
+ break;
+ case kDirDR:
+ result = downRightDir();
+ break;
+ default:
+ result = -1;
+ error("tracePath: wrong direction %d", dir);
+ break;
+ }
+
+ if (result) {
+ byte *tempCoords = _coords;
+ tempCoords -= 4;
+ if (tempCoords > _coordsBuf) {
+ int tempX = READ_LE_UINT16(tempCoords);
+ int tempY = READ_LE_UINT16(tempCoords + 2);
+ if (_checkX == tempX && _checkY == tempY) {
+ _coords = tempCoords;
+ }
+ x = READ_LE_UINT16(tempCoords);
+ y = READ_LE_UINT16(tempCoords + 2);
+ } else {
+ return false;
+ }
+ } else {
+ x = _checkX;
+ y = _checkY;
+ }
+ }
+ return true;
+ } else {
+ error("tracePath: wrong destination point");
+ }
+ } else {
+ error("tracePath: wrong start point");
+ }
+ } else {
+ error("tracePath: same point");
+ }
+}
+
+void PrinceEngine::specialPlotInside2(int x, int y) {
+ WRITE_LE_UINT16(_coords2, x);
+ _coords2 += 2;
+ WRITE_LE_UINT16(_coords2, y);
+ _coords2 += 2;
+}
+
+int PrinceEngine::plotTracePoint(int x, int y, void *data) {
+ PrinceEngine *tracePoint = (PrinceEngine *)data;
+ if (!tracePoint->_tracePointFirstPointFlag) {
+ if (tracePoint->getPixelAddr(tracePoint->_roomPathBitmap, x, y)) {
+ tracePoint->specialPlotInside2(x, y);
+ return 0;
+ } else {
+ return -1;
+ }
+ } else {
+ tracePoint->_tracePointFirstPointFlag = false;
+ return 0;
+ }
+}
+
+void PrinceEngine::approxPath() {
+ byte *oldCoords;
+ _coords2 = _coordsBuf2;
+ byte *tempCoordsBuf = _coordsBuf; // first point on path
+ byte *tempCoords = _coords;
+ if (tempCoordsBuf != tempCoords) {
+ tempCoords -= 4; // last point on path
+ while (tempCoordsBuf != tempCoords) {
+ int x1 = READ_LE_UINT16(tempCoords);
+ int y1 = READ_LE_UINT16(tempCoords + 2);
+ int x2 = READ_LE_UINT16(tempCoordsBuf);
+ int y2 = READ_LE_UINT16(tempCoordsBuf + 2);
+ tempCoordsBuf += 4;
+ //TracePoint
+ oldCoords = _coords2;
+ if (_coords2 == _coordsBuf2) {
+ WRITE_LE_UINT16(_coords2, x1);
+ WRITE_LE_UINT16(_coords2 + 2, y1);
+ _coords2 += 4;
+ } else {
+ int testX = READ_LE_UINT16(_coords2 - 4);
+ int testY = READ_LE_UINT16(_coords2 - 2);
+ if (testX != x1 || testY != y1) {
+ WRITE_LE_UINT16(_coords2, x1);
+ WRITE_LE_UINT16(_coords2 + 2, y1);
+ _coords2 += 4;
+ }
+ }
+ _tracePointFirstPointFlag = true;
+ bool drawLineFlag = drawLine(x1, y1, x2, y2, &this->plotTracePoint, this);
+ if (!drawLineFlag) {
+ tempCoords = tempCoordsBuf - 4;
+ tempCoordsBuf = _coordsBuf;
+ } else {
+ _coords2 = oldCoords;
+ }
+ }
+ }
+}
+
+void PrinceEngine::freeDirectionTable() {
+ if (_directionTable != nullptr) {
+ free(_directionTable);
+ _directionTable = nullptr;
+ }
+}
+
+int PrinceEngine::scanDirectionsFindNext(byte *tempCoordsBuf, int xDiff, int yDiff) {
+
+ int tempX, tempY, direction;
+
+ tempX = Hero::kHeroDirLeft;
+ if (xDiff < 0) {
+ tempX = Hero::kHeroDirRight;
+ }
+
+ tempY = Hero::kHeroDirUp;
+ if (yDiff < 0) {
+ tempY = Hero::kHeroDirDown;
+ }
+
+ while (1) {
+ int againPointX1 = READ_LE_UINT16(tempCoordsBuf);
+ int againPointY1 = READ_LE_UINT16(tempCoordsBuf + 2);
+ tempCoordsBuf += 4;
+
+ if (tempCoordsBuf == _coords) {
+ direction = tempX;
+ break;
+ }
+
+ int dX = againPointX1 - READ_LE_UINT16(tempCoordsBuf);
+ int dY = againPointY1 - READ_LE_UINT16(tempCoordsBuf + 2);
+
+ if (dX != xDiff) {
+ direction = tempY;
+ break;
+ }
+
+ if (dY != yDiff) {
+ direction = tempX;
+ break;
+ }
+ }
+ return direction;
+}
+
+void PrinceEngine::scanDirections() {
+ freeDirectionTable();
+ byte *tempCoordsBuf = _coordsBuf;
+ if (tempCoordsBuf != _coords) {
+ int size = (_coords - tempCoordsBuf) / 4 + 1; // number of coord points plus one for end marker
+ _directionTable = (byte *)malloc(size);
+ byte *tempDirTab = _directionTable;
+ int direction = -1;
+ int lastDirection = -1;
+
+ while (1) {
+ int x1 = READ_LE_UINT16(tempCoordsBuf);
+ int y1 = READ_LE_UINT16(tempCoordsBuf + 2);
+ tempCoordsBuf += 4;
+ if (tempCoordsBuf == _coords) {
+ break;
+ }
+ int x2 = READ_LE_UINT16(tempCoordsBuf);
+ int y2 = READ_LE_UINT16(tempCoordsBuf + 2);
+
+ int xDiff = x1 - x2;
+ int yDiff = y1 - y2;
+
+ if (xDiff) {
+ if (yDiff) {
+ if (lastDirection != -1) {
+ direction = lastDirection;
+ if (direction == Hero::kHeroDirLeft) {
+ if (xDiff < 0) {
+ direction = scanDirectionsFindNext(tempCoordsBuf, xDiff, yDiff);
+ }
+ } else if (direction == Hero::kHeroDirRight) {
+ if (xDiff >= 0) {
+ direction = scanDirectionsFindNext(tempCoordsBuf, xDiff, yDiff);
+ }
+ } else if (direction == Hero::kHeroDirUp) {
+ if (yDiff < 0) {
+ direction = scanDirectionsFindNext(tempCoordsBuf, xDiff, yDiff);
+ }
+ } else {
+ if (yDiff >= 0) {
+ direction = scanDirectionsFindNext(tempCoordsBuf, xDiff, yDiff);
+ }
+ }
+ } else {
+ direction = scanDirectionsFindNext(tempCoordsBuf, xDiff, yDiff);
+ }
+ } else {
+ direction = Hero::kHeroDirLeft;
+ if (xDiff < 0) {
+ direction = Hero::kHeroDirRight;
+ }
+ }
+ } else {
+ if (yDiff) {
+ direction = Hero::kHeroDirUp;
+ if (yDiff < 0) {
+ direction = Hero::kHeroDirDown;
+ }
+ } else {
+ direction = lastDirection;
+ }
+ }
+ lastDirection = direction;
+ *tempDirTab = direction;
+ tempDirTab++;
+ }
+ *tempDirTab = *(tempDirTab - 1);
+ tempDirTab++;
+ *tempDirTab = 0;
+ }
+}
+
+void PrinceEngine::moveShandria() {
+ int shanLen1 = _shanLen;
+ if (_flags->getFlagValue(Flags::SHANDOG)) {
+ _secondHero->freeHeroAnim();
+ _secondHero->freeOldMove();
+ byte *shanCoords = _mainHero->_currCoords + shanLen1 * 4 - 4;
+ int shanX = READ_LE_UINT16(shanCoords - 4);
+ int shanY = READ_LE_UINT16(shanCoords - 2);
+ int xDiff = shanX - _secondHero->_middleX;
+ if (xDiff < 0) {
+ xDiff *= -1;
+ }
+ int yDiff = shanY - _secondHero->_middleY;
+ if (yDiff < 0) {
+ yDiff *= -1;
+ }
+ shanCoords -= 4;
+ if (shanCoords != _mainHero->_currCoords) {
+ yDiff *= 1.5;
+ int shanDis = xDiff * xDiff + yDiff * yDiff;
+ if (shanDis >= kMinDistance) {
+ while (1) {
+ shanCoords -= 4;
+ if (shanCoords == _mainHero->_currCoords) {
+ break;
+ }
+ int x = READ_LE_UINT16(shanCoords);
+ int y = READ_LE_UINT16(shanCoords + 2);
+ int pointDiffX = x - shanX;
+ if (pointDiffX < 0) {
+ pointDiffX *= -1;
+ }
+ int pointDiffY = y - shanY;
+ if (pointDiffY < 0) {
+ pointDiffY *= -1;
+ }
+ pointDiffY *= 1.5;
+ int distance = pointDiffX * pointDiffX + pointDiffY * pointDiffY;
+ if (distance >= kMinDistance) {
+ break;
+ }
+ }
+ int pathSizeDiff = (shanCoords - _mainHero->_currCoords) / 4;
+ int destDir = *(_mainHero->_currDirTab + pathSizeDiff);
+ _secondHero->_destDirection = destDir;
+ int destX = READ_LE_UINT16(shanCoords);
+ int destY = READ_LE_UINT16(shanCoords + 2);
+ _secondHero->_coords = makePath(kSecondHero, _secondHero->_middleX, _secondHero->_middleY, destX, destY);
+ if (_secondHero->_coords != nullptr) {
+ _secondHero->_currCoords = _secondHero->_coords;
+ int delay = shanLen1 - _shanLen;
+ if (delay < 6) {
+ delay = 6;
+ }
+ _secondHero->_moveDelay = delay / 2;
+ _secondHero->_state = Hero::kHeroStateDelayMove;
+ _secondHero->_dirTab = _directionTable;
+ _secondHero->_currDirTab = _directionTable;
+ _directionTable = nullptr;
+ }
+ }
+ }
+ }
+}
+
+byte *PrinceEngine::makePath(int heroId, int currX, int currY, int destX, int destY) {
+ int realDestX = destX;
+ int realDestY = destY;
+ _flags->setFlagValue(Flags::MOVEDESTX, destX);
+ _flags->setFlagValue(Flags::MOVEDESTY, destY);
+
+ int x1 = currX / 2;
+ int y1 = currY / 2;
+ int x2 = destX / 2;
+ int y2 = destY / 2;
+
+ if ((x1 != x2) || (y1 != y2)) {
+ findPoint(x1, y1);
+ if (!getPixelAddr(_roomPathBitmap, _fpX, _fpY)) {
+ return nullptr;
+ }
+ if ((x1 != _fpX) || (y1 != _fpY)) {
+ x1 = _fpX;
+ y1 = _fpY;
+ }
+ findPoint(x2, y2);
+ if (!getPixelAddr(_roomPathBitmap, _fpX, _fpY)) {
+ return nullptr;
+ }
+ if ((x2 != _fpX) || (y2 != _fpY)) {
+ x2 = _fpX;
+ y2 = _fpY;
+ if (!_flags->getFlagValue(Flags::EXACTMOVE)) {
+ realDestX = x2 * 2;
+ realDestY = y2 * 2;
+ _flags->setFlagValue(Flags::MOVEDESTX, realDestX);
+ _flags->setFlagValue(Flags::MOVEDESTY, realDestY);
+ } else {
+ return nullptr;
+ }
+ }
+
+ if ((x1 == x2) && (y1 == y2)) {
+ if (!heroId) {
+ _mainHero->freeOldMove();
+ _mainHero->_state = Hero::kHeroStateTurn;
+ } else if (heroId == 1) {
+ _secondHero->freeOldMove();
+ _secondHero->_state = Hero::kHeroStateTurn;
+ }
+ return nullptr;
+ }
+
+ int pathLen1 = 0;
+ int pathLen2 = 0;
+ int stX = x1;
+ int stY = y1;
+ int sizeCoords2 = 0;
+
+ if (tracePath(x1, y1, x2, y2)) {
+ allocCoords2();
+ approxPath();
+ sizeCoords2 = _coords2 - _coordsBuf2;
+ for (int i = 0; i < sizeCoords2; i++) {
+ _coordsBuf[i] = _coordsBuf2[i];
+ }
+ _coords = _coordsBuf + sizeCoords2;
+ approxPath();
+ _coordsBuf3 = _coordsBuf2;
+ _coordsBuf2 = nullptr;
+ _coords3 = _coords2;
+ _coords2 = nullptr;
+ pathLen1 = _coords3 - _coordsBuf3;
+ }
+ if (tracePath(x2, y2, x1, y1)) {
+ allocCoords2();
+ approxPath();
+ sizeCoords2 = _coords2 - _coordsBuf2;
+ for (int i = 0; i < sizeCoords2; i++) {
+ _coordsBuf[i] = _coordsBuf2[i];
+ }
+ _coords = _coordsBuf + sizeCoords2;
+ approxPath();
+ pathLen2 = _coords2 - _coordsBuf2;
+ }
+
+ byte *chosenCoordsBuf = _coordsBuf2;
+ byte *choosenCoords = _coords2;
+ int choosenLength = pathLen1;
+ if (pathLen1 < pathLen2) {
+ chosenCoordsBuf = _coordsBuf3;
+ choosenCoords = _coords3;
+ choosenLength = pathLen2;
+ }
+
+ if (choosenLength) {
+ if (chosenCoordsBuf != nullptr) {
+ int tempXBegin = READ_LE_UINT16(chosenCoordsBuf);
+ int tempYBegin = READ_LE_UINT16(chosenCoordsBuf + 2);
+ if (stX != tempXBegin || stY != tempYBegin) {
+ SWAP(chosenCoordsBuf, choosenCoords);
+ chosenCoordsBuf -= 4;
+ byte *tempCoordsBuf = _coordsBuf;
+ while (1) {
+ int cord = READ_LE_UINT32(chosenCoordsBuf);
+ WRITE_LE_UINT32(tempCoordsBuf, cord);
+ tempCoordsBuf += 4;
+ if (chosenCoordsBuf == choosenCoords) {
+ break;
+ }
+ chosenCoordsBuf -= 4;
+ }
+ _coords = tempCoordsBuf;
+ } else {
+ int sizeChoosen = choosenCoords - chosenCoordsBuf;
+ for (int i = 0; i < sizeChoosen; i++) {
+ _coordsBuf[i] = chosenCoordsBuf[i];
+ }
+ _coords = _coordsBuf + sizeChoosen;
+ }
+ WRITE_LE_UINT32(_coords, 0xFFFFFFFF);
+ freeCoords2();
+ freeCoords3();
+ scanDirections();
+
+ byte *tempCoordsBuf = _coordsBuf;
+ byte *tempCoords = _coords;
+ byte *newCoords;
+ if (tempCoordsBuf != tempCoords) {
+ int normCoordsSize = _coords - _coordsBuf + 4;
+ newCoords = (byte *)malloc(normCoordsSize);
+ byte *newCoordsBegin = newCoords;
+ while (tempCoordsBuf != tempCoords) {
+ int newValueX = READ_LE_UINT16(tempCoordsBuf);
+ WRITE_LE_UINT16(newCoords, newValueX * 2);
+ newCoords += 2;
+ int newValueY = READ_LE_UINT16(tempCoordsBuf + 2);
+ WRITE_LE_UINT16(newCoords, newValueY * 2);
+ newCoords += 2;
+ tempCoordsBuf += 4;
+ }
+ WRITE_LE_UINT16(newCoords - 4, realDestX);
+ WRITE_LE_UINT16(newCoords - 2, realDestY);
+ WRITE_LE_UINT32(newCoords, 0xFFFFFFFF);
+ newCoords += 4;
+ _shanLen = (newCoords - newCoordsBegin);
+ _shanLen /= 4;
+ return newCoordsBegin;
+ }
+ }
+ }
+ _coords = _coordsBuf;
+ freeCoords2();
+ freeCoords3();
+ return nullptr;
+ } else {
+ if (!heroId) {
+ _mainHero->freeOldMove();
+ _mainHero->_state = Hero::kHeroStateTurn;
+ } else if (heroId == 1) {
+ _secondHero->freeOldMove();
+ _secondHero->_state = Hero::kHeroStateTurn;
+ }
+ return nullptr;
+ }
+}
+
+void PrinceEngine::allocCoords2() {
+ if (_coordsBuf2 == nullptr) {
+ _coordsBuf2 = (byte *)malloc(kTracePts * 4);
+ _coords2 = _coordsBuf2;
+ }
+}
+
+void PrinceEngine::freeCoords2() {
+ if (_coordsBuf2 != nullptr) {
+ free(_coordsBuf2);
+ _coordsBuf2 = nullptr;
+ _coords2 = nullptr;
+ }
+}
+
+void PrinceEngine::freeCoords3() {
+ if (_coordsBuf3 != nullptr) {
+ free(_coordsBuf3);
+ _coordsBuf3 = nullptr;
+ _coords3 = nullptr;
+ }
+}
+
+void PrinceEngine::openInventoryCheck() {
+ if (!_optionsFlag) {
+ if (_mouseFlag == 1 || _mouseFlag == 2) {
+ if (_mainHero->_visible) {
+ if (!_flags->getFlagValue(Flags::INVALLOWED)) {
+ // 29 - Basement, 50 - Map
+ if (_locationNr != 29 && _locationNr != 50) {
+ Common::Point mousePos = _system->getEventManager()->getMousePos();
+ if (mousePos.y < 4 && !_showInventoryFlag) {
+ _invCounter++;
+ } else {
+ _invCounter = 0;
+ }
+ if (_invCounter >= _invMaxCount) {
+ inventoryFlagChange(true);
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+void PrinceEngine::mainLoop() {
+ changeCursor(0);
+ _currentTime = _system->getMillis();
+
+ while (!shouldQuit()) {
+ Common::Event event;
+ Common::EventManager *eventMan = _system->getEventManager();
+ while (eventMan->pollEvent(event)) {
+ switch (event.type) {
+ case Common::EVENT_KEYDOWN:
+ keyHandler(event);
+ break;
+ case Common::EVENT_LBUTTONDOWN:
+ leftMouseButton();
+ break;
+ case Common::EVENT_RBUTTONDOWN:
+ rightMouseButton();
+ break;
+ default:
+ break;
+ }
+ }
+
+ if (shouldQuit()) {
+ return;
+ }
+
+ // for "throw a rock" mini-game
+ mouseWeirdo();
+
+ _interpreter->stepBg();
+ _interpreter->stepFg();
+
+ drawScreen();
+
+ _graph->update(_graph->_frontScreen);
+
+ openInventoryCheck();
+
+ pausePrinceEngine();
+ }
+}
+
+} // End of namespace Prince
diff --git a/engines/prince/prince.h b/engines/prince/prince.h
new file mode 100644
index 0000000000..6dce044a41
--- /dev/null
+++ b/engines/prince/prince.h
@@ -0,0 +1,674 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public 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 PRINCE_H
+#define PRINCE_H
+
+#include "common/random.h"
+#include "common/system.h"
+#include "common/debug.h"
+#include "common/debug-channels.h"
+#include "common/textconsole.h"
+#include "common/rect.h"
+#include "common/events.h"
+#include "common/endian.h"
+#include "common/savefile.h"
+#include "common/serializer.h"
+
+#include "image/bmp.h"
+
+#include "gui/debugger.h"
+
+#include "engines/engine.h"
+#include "engines/util.h"
+
+#include "audio/mixer.h"
+
+#include "video/flic_decoder.h"
+
+#include "prince/mob.h"
+#include "prince/object.h"
+#include "prince/pscr.h"
+
+namespace Prince {
+
+struct PrinceGameDescription;
+struct SavegameHeader;
+
+class PrinceEngine;
+class GraphicsMan;
+class Script;
+class Interpreter;
+class InterpreterFlags;
+class Debugger;
+class MusicPlayer;
+class VariaTxt;
+class Cursor;
+class MhwanhDecoder;
+class Font;
+class Hero;
+class Animation;
+class Room;
+class Pscr;
+
+struct Text {
+ const char *_str;
+ uint16 _x, _y;
+ uint16 _time;
+ uint32 _color;
+
+ Text() : _str(nullptr), _x(0), _y(0), _time(0), _color(255){
+ }
+};
+
+struct AnimListItem {
+ uint16 _type; // type of animation - for background anims RND of frame
+ uint16 _fileNumber;
+ uint16 _startPhase; // first phase number
+ uint16 _endPhase;
+ uint16 _loopPhase;
+ int16 _x;
+ int16 _y;
+ uint16 _loopType;
+ uint16 _nextAnim; // number of animation to do for loop = 3
+ uint16 _flags; // byte 0 - draw masks, byte 1 - draw in front of mask, byte 2 - load but turn off drawing
+ bool loadFromStream(Common::SeekableReadStream &stream);
+};
+
+struct BAS {
+ int32 _type; // type of sequence
+ int32 _data; // additional data
+ int32 _anims; // number of animations
+ int32 _current; // actual number of animation
+ int32 _counter; // time counter for animation
+ int32 _currRelative; //actual relative number for animation
+ int32 _data2; // additional data for measurements
+};
+
+const int kStructSizeBAS = 28;
+
+struct BASA {
+ int16 _num; // animation number
+ int16 _start; // initial frame
+ int16 _end; // final frame
+ //int16 _pad; // fulfilment to 8 bytes
+};
+
+const int kStructSizeBASA = 8;
+
+// background and normal animation
+struct Anim {
+ BASA _basaData;
+ int32 _addr; //animation adress
+ int16 _usage;
+ int16 _state; // state of animation: 0 - turning on, 1 - turning off
+ int16 _flags;
+ int16 _frame; // number of phase to show
+ int16 _lastFrame; // last phase
+ int16 _loopFrame; // first frame of loop
+ int16 _showFrame; // actual visible frame of animation
+ int16 _loopType; // type of loop (0 - last frame; 1 - normal loop (begin from _loopFrame); 2 - no loop; 3 - load new animation)
+ int16 _nextAnim; // number of next animation to load after actual
+ int16 _x;
+ int16 _y;
+ int32 _currFrame;
+ int16 _currX;
+ int16 _currY;
+ int16 _currW;
+ int16 _currH;
+ int16 _packFlag;
+ int32 _currShadowFrame;
+ int16 _packShadowFlag;
+ int32 _shadowBack;
+ int16 _relX;
+ int16 _relY;
+ Animation *_animData;
+ Animation *_shadowData;
+
+ enum AnimOffsets {
+ kAnimState = 10,
+ kAnimFrame = 14,
+ kAnimLastFrame = 16,
+ kAnimX = 26
+ };
+
+ int16 getAnimData(Anim::AnimOffsets offset) {
+ switch (offset) {
+ case kAnimState:
+ return _state;
+ case kAnimFrame:
+ return _frame + 1; // fix for location 30 - man with a dog animation
+ case kAnimX:
+ return _x;
+ default:
+ error("getAnimData() - Wrong offset type: %d", (int) offset);
+ }
+ }
+
+ void setAnimData(Anim::AnimOffsets offset, int16 value) {
+ if (offset == kAnimX) {
+ _x = value;
+ } else {
+ error("setAnimData() - Wrong offset: %d, value: %d", (int) offset, value);
+ }
+ }
+};
+
+struct BackgroundAnim {
+ BAS _seq;
+ Common::Array<Anim> backAnims;
+};
+
+enum AnimType {
+ kBackgroundAnimation,
+ kNormalAnimation
+};
+
+// Nak (PL - Nakladka)
+struct Mask {
+ uint16 _state; // visible / invisible
+ int16 _flags; // turning on / turning off of an mask
+ int16 _x1;
+ int16 _y1;
+ int16 _x2;
+ int16 _y2;
+ int16 _z;
+ int16 _number; // number of mask for background recreating
+ int16 _width;
+ int16 _height;
+ byte *_data;
+
+ int16 getX() const {
+ return READ_LE_UINT16(_data);
+ }
+
+ int16 getY() const {
+ return READ_LE_UINT16(_data + 2);
+ }
+
+ int16 getWidth() const {
+ return READ_LE_UINT16(_data + 4);
+ }
+
+ int16 getHeight() const {
+ return READ_LE_UINT16(_data + 6);
+ }
+
+ byte *getMask() const {
+ return (byte *)(_data + 8);
+ }
+};
+
+struct InvItem {
+ int _x;
+ int _y;
+ Graphics::Surface *_surface;
+ Graphics::Surface *getSurface() const { return _surface; }
+};
+
+struct DrawNode {
+ int posX;
+ int posY;
+ int posZ;
+ int32 width;
+ int32 height;
+ int32 scaleValue;
+ Graphics::Surface *s;
+ Graphics::Surface *originalRoomSurface;
+ void *data;
+ void (*drawFunction)(Graphics::Surface *, DrawNode *);
+};
+
+struct DebugChannel {
+
+enum Type {
+ kScript,
+ kEngine
+};
+
+};
+
+class PrinceEngine : public Engine {
+protected:
+ Common::Error run();
+
+public:
+ PrinceEngine(OSystem *syst, const PrinceGameDescription *gameDesc);
+ virtual ~PrinceEngine();
+
+ virtual bool hasFeature(EngineFeature f) const;
+ virtual void pauseEngineIntern(bool pause);
+ virtual bool canSaveGameStateCurrently();
+ virtual bool canLoadGameStateCurrently();
+ virtual Common::Error saveGameState(int slot, const Common::String &desc);
+ virtual Common::Error loadGameState(int slot);
+
+ static bool readSavegameHeader(Common::InSaveFile *in, SavegameHeader &header);
+ Common::String generateSaveName(int slot);
+ void writeSavegameHeader(Common::OutSaveFile *out, SavegameHeader &header);
+ void syncGame(Common::SeekableReadStream *readStream, Common::WriteStream *writeStream);
+ bool loadGame(int slotNumber);
+ void resetGame();
+
+ int32 _creditsDataSize;
+ byte *_creditsData;
+ void scrollCredits();
+
+ int getGameType() const;
+ const char *getGameId() const;
+ uint32 getFeatures() const;
+ Common::Language getLanguage() const;
+
+ const PrinceGameDescription *_gameDescription;
+ Video::FlicDecoder _flicPlayer;
+ const Graphics::Surface *_flcFrameSurface;
+ VariaTxt *_variaTxt;
+
+ uint32 _talkTxtSize;
+ byte *_talkTxt;
+
+ uint32 _mobTranslationSize;
+ byte *_mobTranslationData;
+
+ bool loadLocation(uint16 locationNr);
+ bool loadAnim(uint16 animNr, bool loop);
+ bool loadVoice(uint32 textSlot, uint32 sampleSlot, const Common::String &name);
+ bool loadSample(uint32 sampleSlot, const Common::String &name);
+ bool loadZoom(byte *zoomBitmap, uint32 dataSize, const char *resourceName);
+ bool loadShadow(byte *shadowBitmap, uint32 dataSize, const char *resourceName1, const char *resourceName2);
+ bool loadTrans(byte *transTable, const char *resourceName);
+ bool loadMobPriority(const char *resourceName);
+
+ void loadMobTranslationTexts();
+ void setMobTranslationTexts();
+
+ bool loadMusic(int musNumber);
+ void stopMusic();
+
+ void playSample(uint16 sampleId, uint16 loopType);
+ void stopSample(uint16 sampleId);
+ void stopAllSamples();
+ void freeSample(uint16 sampleId);
+ void freeAllSamples();
+
+ void setVoice(uint16 slot, uint32 sampleSlot, uint16 flag);
+
+ virtual GUI::Debugger *getDebugger();
+
+ void changeCursor(uint16 curId);
+ void printAt(uint32 slot, uint8 color, char *s, uint16 x, uint16 y);
+ int calcTextLines(const char *s);
+ int calcTextTime(int numberOfLines);
+ void correctStringDEU(char *s);
+
+ static const uint8 kMaxTexts = 32;
+ Text _textSlots[kMaxTexts];
+
+ Hero *_mainHero;
+ Hero *_secondHero;
+
+ enum HeroId {
+ kMainHero,
+ kSecondHero
+ };
+
+ int _mouseFlag;
+ uint32 _currentTime;
+ uint16 _locationNr;
+ uint16 _sceneWidth;
+ int32 _picWindowX;
+ int32 _picWindowY;
+
+ Image::BitmapDecoder *_roomBmp;
+ MhwanhDecoder *_suitcaseBmp;
+ Room *_room;
+ Script *_script;
+ InterpreterFlags *_flags;
+ Interpreter *_interpreter;
+ GraphicsMan *_graph;
+ uint8 _currentMidi;
+ byte *_zoomBitmap;
+ byte *_shadowBitmap;
+ byte *_transTable;
+
+ int16 _scaleValue; // scale for hero or special shadow animation
+ int16 _lightX; // for hero shadow
+ int16 _lightY;
+ int32 _shadScaleValue;
+ int32 _shadLineLen;
+ byte *_shadowLine;
+ void setShadowScale(int32 shadowScale);
+ static void plotShadowLinePoint(int x, int y, int color, void *data);
+
+ static const int16 kFPS = 15;
+ static const int32 kIntMax = 2147483647;
+
+ static const int16 kMaxPicWidth = 1280;
+ static const int16 kMaxPicHeight = 480;
+ static const int16 kZoomStep = 4;
+ static const int32 kZoomBitmapLen = kMaxPicHeight / kZoomStep * kMaxPicWidth / kZoomStep;
+ static const int32 kShadowBitmapSize = kMaxPicWidth * kMaxPicHeight / 8;
+ static const int16 kShadowLineArraySize = 2 * 1280 * 4;
+ static const int16 kZoomBitmapWidth = kMaxPicWidth / kZoomStep;
+ static const int16 kZoomBitmapHeight = kMaxPicHeight / kZoomStep;
+ static const int16 kNormalWidth = 640;
+ static const int16 kNormalHeight = 480;
+ static const uint32 kTransTableSize = 256 * 256;
+
+ static const int kMaxNormAnims = 64;
+ static const int kMaxBackAnims = 64;
+ static const int kMaxObjects = 64;
+ static const int kMaxMobs = 64;
+
+ Common::Array<DrawNode> _drawNodeList;
+ Common::Array<AnimListItem> _animList;
+ Common::Array<BackgroundAnim> _backAnimList;
+ Common::Array<Anim> _normAnimList;
+ Common::Array<Mob> _mobList;
+ Common::Array<uint32> _mobPriorityList;
+ Common::Array<Mask> _maskList;
+ Common::Array<Object *> _objList;
+ uint16 *_objSlot;
+
+ void freeNormAnim(int slot);
+ void freeAllNormAnims();
+ void removeSingleBackAnim(int slot);
+
+ Common::RandomSource _randomSource;
+
+ void checkMasks(int x1, int y1, int sprWidth, int sprHeight, int z);
+ void insertMasks(Graphics::Surface *originalRoomSurface);
+ void showMask(int maskNr, Graphics::Surface *originalRoomSurface);
+ void clsMasks();
+
+ void grabMap();
+
+ int _selectedMob; // number of selected Mob / inventory item
+ int _selectedItem; // number of item on mouse cursor
+ int _selectedMode;
+ int _currentPointerNumber;
+
+ static const int16 kMaxInv = 90; // max amount of inventory items in whole game
+ static const uint16 kMaxItems = 30; // size of inventory
+
+ uint32 _invTxtSize;
+ byte *_invTxt;
+
+ Graphics::Surface *_optionsPic;
+ Graphics::Surface *_optionsPicInInventory;
+
+ bool _optionsFlag;
+ int _optionEnabled;
+ int _optionsMob;
+ int _optionsX;
+ int _optionsY;
+ int _optionsWidth;
+ int _optionsHeight;
+ int _invOptionsWidth;
+ int _invOptionsHeight;
+ int _optionsStep;
+ int _invOptionsStep;
+ int _optionsNumber;
+ int _invOptionsNumber;
+ int _optionsColor1; // color for non-selected options
+ int _optionsColor2; // color for selected option
+
+ bool _showInventoryFlag;
+ int _invExamY;
+ bool _inventoryBackgroundRemember;
+ int _invLineX;
+ int _invLineY;
+ int _invLine; // number of items in one line
+ int _invLines; // number of lines with inventory items
+ int _invLineW;
+ int _invLineH;
+ int _maxInvW;
+ int _maxInvH;
+ int _invLineSkipX;
+ int _invLineSkipY;
+ int _invX1;
+ int _invY1;
+ int _invWidth;
+ int _invHeight;
+ bool _invCurInside;
+ int _mst_shadow;
+ int _mst_shadow2; // blinking after adding new item
+ int _candleCounter; // special counter for candle inventory item
+ int _invMaxCount; // time to turn inventory on
+ int _invCounter; // turning on counter
+
+ void inventoryFlagChange(bool inventoryState);
+ bool loadAllInv();
+ void rememberScreenInv();
+ void prepareInventoryToView();
+ void drawInvItems();
+ void displayInventory();
+ void addInv(int heroId, int item, bool addItemQuiet);
+ void remInv(int heroId, int item);
+ void clearInv(int heroId);
+ void swapInv(int heroId);
+ void addInvObj();
+ void makeInvCursor(int itemNr);
+ void enableOptions(bool checkType);
+ void checkOptions();
+ void checkInvOptions();
+ void openInventoryCheck();
+
+ void leftMouseButton();
+ void rightMouseButton();
+ void inventoryLeftMouseButton();
+ void inventoryRightMouseButton();
+ void dialogLeftMouseButton(byte *string, int dialogSelected);
+
+ uint32 _dialogDatSize;
+ byte *_dialogDat;
+ byte *_dialogData; // on, off flags for lines of dialog text
+
+ byte *_dialogBoxAddr[32]; // adresses of dialog windows
+ byte *_dialogOptAddr[32]; // adresses of dialog options
+ int _dialogOptLines[4 * 32]; // numbers of initial dialog lines
+
+ byte *_dialogText;
+ int _dialogLines;
+ bool _dialogFlag;
+ int _dialogWidth;
+ int _dialogHeight;
+ int _dialogLineSpace;
+ int _dialogColor1; // color for non-selected options
+ int _dialogColor2; // color for selected option
+ Graphics::Surface *_dialogImage;
+
+ void createDialogBox(int dialogBoxNr);
+ void dialogRun();
+ void talkHero(int slot);
+ void doTalkAnim(int animNumber, int slot, AnimType animType);
+
+ static const uint8 zoomInStep = 8;
+ void initZoomIn(int slot);
+ void initZoomOut(int slot);
+ void doZoomIn(int slot);
+ void doZoomOut(int slot);
+ void freeZoomObject(int slot);
+
+ static const uint8 kFadeStep = 4;
+ void blackPalette();
+ void setPalette(const byte *palette);
+
+ int getMob(Common::Array<Mob> &mobList, bool usePriorityList, int posX, int posY);
+
+ // 'Throw a rock' mini-game:
+ static const int16 kCurveLen = 17;
+ static const int kCelStep = 4;
+ int16 *_curveData;
+ int _curvPos;
+ void makeCurve();
+ void getCurve();
+ void mouseWeirdo();
+
+ static const uint16 kPowerBarPosX = 288;
+ static const uint16 kPowerBarPosY = 430;
+ static const uint8 kPowerBarWidth = 64;
+ static const uint8 kPowerBarHeight = 16;
+ static const uint8 kPowerBarBackgroundColor = 0;
+ static const uint16 kPowerBarGreenPosY = 434;
+ static const uint8 kPowerBarGreenColor1 = 202;
+ static const uint8 kPowerBarGreenColor2 = 235;
+ static const uint8 kPowerBarGreenHeight = 8;
+ void showPower();
+
+ // Pathfinding
+ static const int16 kPathGridStep = 2;
+ static const uint32 kPathBitmapLen = (kMaxPicHeight / kPathGridStep * kMaxPicWidth / kPathGridStep) / 8;
+ static const int32 kTracePts = 8000;
+ static const int32 kPBW = kMaxPicWidth / 16; // PathBitmapWidth
+ static const int kMinDistance = 2500;
+
+ byte *_roomPathBitmap; // PL - Sala
+ byte *_roomPathBitmapTemp; // PL - SSala
+ byte *_coordsBufEnd;
+ byte *_coordsBuf; // optimal path
+ byte *_coords; // last path point adress from coordsBuf
+ byte *_coordsBuf2;
+ byte *_coords2;
+ byte *_coordsBuf3;
+ byte *_coords3;
+ int _traceLineLen;
+ bool _traceLineFirstPointFlag; // if plotTraceLine after first point
+ bool _tracePointFirstPointFlag; // if plotTracePoint after first point
+ byte *_directionTable;
+ int _shanLen;
+
+ byte *_checkBitmapTemp;
+ byte *_checkBitmap;
+ int _checkMask;
+ int _checkX;
+ int _checkY;
+
+ byte *_rembBitmapTemp;
+ byte *_rembBitmap;
+ int _rembMask;
+ int _rembX;
+ int _rembY;
+
+ int _fpX;
+ int _fpY;
+
+ int drawLine(int x0, int y0, int x1, int y1, int (*plotProc)(int, int, void *), void *data);
+ bool loadPath(const char *resourceName);
+ byte *makePath(int heroId, int currX, int currY, int destX, int destY);
+ void findPoint(int x, int y);
+ int getPixelAddr(byte *pathBitmap, int x, int y);
+ static int plotTraceLine(int x, int y, void *data);
+ void specialPlotInside(int x, int y);
+ bool tracePath(int x1, int y1, int x2, int y2);
+ Direction makeDirection(int x1, int y1, int x2, int y2);
+ void specialPlot(int x, int y);
+ void specialPlot2(int x, int y);
+ void allocCoords2();
+ void freeCoords2();
+ void freeCoords3();
+ static int plotTracePoint(int x, int y, void *data);
+ void specialPlotInside2(int x, int y);
+ void approxPath();
+ void freeDirectionTable();
+ void scanDirections();
+ int scanDirectionsFindNext(byte *coords, int xDiff, int yDiff);
+ void moveShandria();
+ void walkTo();
+ void moveRunHero(int heroId, int x, int y, int dir, bool runHeroFlag);
+
+ int leftDownDir();
+ int leftDir();
+ int leftUpDir();
+ int rightDownDir();
+ int rightDir();
+ int rightUpDir();
+ int upLeftDir();
+ int upDir();
+ int upRightDir();
+ int downLeftDir();
+ int downDir();
+ int downRightDir();
+
+ int cpe();
+ int checkLeftDownDir();
+ int checkLeftDir();
+ int checkDownDir();
+ int checkUpDir();
+ int checkRightDir();
+ int checkLeftUpDir();
+ int checkRightDownDir();
+ int checkRightUpDir();
+
+private:
+ bool playNextFLCFrame();
+ void keyHandler(Common::Event event);
+ int checkMob(Graphics::Surface *screen, Common::Array<Mob> &mobList, bool usePriorityList);
+ void drawScreen();
+ void showTexts(Graphics::Surface *screen);
+ void init();
+ void showLogo();
+ void showAnim(Anim &anim);
+ void showNormAnims();
+ void setBackAnim(Anim &backAnim);
+ void showBackAnims();
+ void clearBackAnimList();
+ bool spriteCheck(int sprWidth, int sprHeight, int destX, int destY);
+ void showSprite(Graphics::Surface *spriteSurface, int destX, int destY, int destZ);
+ void showSpriteShadow(Graphics::Surface *shadowSurface, int destX, int destY, int destZ);
+ void showObjects();
+ void showParallax();
+ static bool compareDrawNodes(DrawNode d1, DrawNode d2);
+ void runDrawNodes();
+ void makeShadowTable(int brightness);
+ void pausePrinceEngine(int fps = kFPS);
+
+ uint32 getTextWidth(const char *s);
+ void debugEngine(const char *s, ...);
+
+ uint8 _cursorNr;
+
+ Common::RandomSource *_rnd;
+ Cursor *_cursor1;
+ Graphics::Surface *_cursor2;
+ Cursor *_cursor3;
+ Debugger *_debugger;
+ Font *_font;
+ MusicPlayer *_midiPlayer;
+
+ static const int kMaxSamples = 60;
+ Audio::RewindableAudioStream *_audioStream[kMaxSamples];
+ Audio::SoundHandle _soundHandle[kMaxSamples];
+
+ Common::Array<PScr *> _pscrList;
+ Common::Array<InvItem> _allInvList;
+ Common::Array<Mob> _invMobList;
+
+ bool _flicLooped;
+
+ void mainLoop();
+
+};
+
+} // End of namespace Prince
+
+#endif
diff --git a/engines/prince/pscr.cpp b/engines/prince/pscr.cpp
new file mode 100644
index 0000000000..d9d36a3356
--- /dev/null
+++ b/engines/prince/pscr.cpp
@@ -0,0 +1,75 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public 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/archive.h"
+#include "common/stream.h"
+
+#include "prince/pscr.h"
+
+namespace Prince {
+
+PScr::PScr() : _x(0), _y(0), _step(0), _surface(nullptr)
+{
+}
+
+PScr::~PScr() {
+ if (_surface != nullptr) {
+ _surface->free();
+ delete _surface;
+ _surface = nullptr;
+ }
+}
+
+void PScr::loadSurface(Common::SeekableReadStream &stream) {
+ stream.skip(4);
+ int width = stream.readUint16LE();
+ int height = stream.readUint16LE();
+ _surface = new Graphics::Surface();
+ _surface->create(width, height, Graphics::PixelFormat::createFormatCLUT8());
+
+ for (int h = 0; h < _surface->h; h++) {
+ stream.read(_surface->getBasePtr(0, h), _surface->w);
+ }
+}
+
+bool PScr::loadFromStream(Common::SeekableReadStream &stream) {
+ int32 pos = stream.pos();
+ uint16 file = stream.readUint16LE();
+ if (file == 0xFFFF) {
+ return false;
+ }
+ _x = stream.readUint16LE();
+ _y = stream.readUint16LE();
+ _step = stream.readUint16LE();
+
+ const Common::String pscrStreamName = Common::String::format("PS%02d", file);
+ Common::SeekableReadStream *pscrStream = SearchMan.createReadStreamForMember(pscrStreamName);
+ if (pscrStream != nullptr) {
+ loadSurface(*pscrStream);
+ }
+ delete pscrStream;
+ stream.seek(pos + 12); // size of PScrList struct
+
+ return true;
+}
+
+} // End of namespace Prince
diff --git a/engines/prince/pscr.h b/engines/prince/pscr.h
new file mode 100644
index 0000000000..fdcdb524a9
--- /dev/null
+++ b/engines/prince/pscr.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 PRINCE_PSCR_H
+#define PRINCE_PSCR_H
+
+#include "graphics/surface.h"
+
+namespace Prince {
+
+class PScr {
+public:
+ PScr();
+ ~PScr();
+ int16 _x;
+ int16 _y;
+ int16 _step;
+ static const int16 kPScrZ = 1000;
+
+ bool loadFromStream(Common::SeekableReadStream &stream);
+ Graphics::Surface *getSurface() const { return _surface; }
+private:
+ void loadSurface(Common::SeekableReadStream &stream);
+ Graphics::Surface *_surface;
+};
+
+} // End of namespace Prince
+
+#endif
diff --git a/engines/prince/resource.h b/engines/prince/resource.h
new file mode 100644
index 0000000000..f42eb87842
--- /dev/null
+++ b/engines/prince/resource.h
@@ -0,0 +1,100 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public 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 PRINCE_RESOURCE_H
+#define PRINCE_RESOURCE_H
+
+#include "common/stream.h"
+#include "common/archive.h"
+#include "common/debug-channels.h"
+#include "common/ptr.h"
+
+namespace Prince {
+
+namespace Resource {
+
+ template <typename T>
+ bool loadFromStream(T &resource, Common::SeekableReadStream &stream) {
+ return resource.loadStream(stream);
+ }
+
+ template<typename T>
+ bool loadResource(T *resource, const char *resourceName, bool required) {
+ Common::ScopedPtr<Common::SeekableReadStream> stream(SearchMan.createReadStreamForMember(resourceName));
+ if (!stream) {
+ if (required)
+ error("Can't load %s", resourceName);
+ return false;
+ }
+
+ return loadFromStream(*resource, *stream);
+ }
+
+ template <typename T>
+ bool loadResource(Common::Array<T> &array, Common::SeekableReadStream &stream, bool required = true) {
+ T t;
+ while (t.loadFromStream(stream))
+ array.push_back(t);
+
+ return true;
+ }
+
+
+ template <typename T>
+ bool loadResource(Common::Array<T> &array, const char *resourceName, bool required = true) {
+ Common::ScopedPtr<Common::SeekableReadStream> stream(SearchMan.createReadStreamForMember(resourceName));
+ if (!stream) {
+ if (required)
+ error("Can't load %s", resourceName);
+ return false;
+ }
+
+ return loadResource(array, *stream, required);
+ }
+
+ template <typename T>
+ bool loadResource(Common::Array<T *> &array, const char *resourceName, bool required = true) {
+
+ Common::ScopedPtr<Common::SeekableReadStream> stream(SearchMan.createReadStreamForMember(resourceName));
+ if (!stream) {
+ if (required)
+ error("Can't load %s", resourceName);
+ return false;
+ }
+
+ // FIXME: This is stupid. Maybe loadFromStream should be helper method that returns initiailzed object
+ while (true) {
+ T* t = new T();
+ if (!t->loadFromStream(*stream)) {
+ delete t;
+ break;
+ }
+ array.push_back(t);
+ }
+ return true;
+ }
+
+}
+
+} // End of namespace Prince
+
+#endif
diff --git a/engines/prince/saveload.cpp b/engines/prince/saveload.cpp
new file mode 100644
index 0000000000..46e598be70
--- /dev/null
+++ b/engines/prince/saveload.cpp
@@ -0,0 +1,531 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "prince/prince.h"
+#include "prince/graphics.h"
+#include "prince/detection.h"
+#include "prince/flags.h"
+#include "prince/script.h"
+#include "prince/hero.h"
+
+#include "common/savefile.h"
+#include "common/system.h"
+#include "common/config-manager.h"
+#include "common/memstream.h"
+
+#include "graphics/thumbnail.h"
+#include "graphics/surface.h"
+#include "graphics/palette.h"
+#include "graphics/scaler.h"
+
+namespace Prince {
+
+#define kBadSVG 99
+#define kSavegameVersion 1
+#define kSavegameStrSize 14
+#define kSavegameStr "SCUMMVM_PRINCE"
+
+class InterpreterFlags;
+class Interpreter;
+
+struct SavegameHeader {
+ uint8 version;
+ Common::String saveName;
+ Graphics::Surface *thumbnail;
+ int saveYear, saveMonth, saveDay;
+ int saveHour, saveMinutes;
+};
+
+int PrinceMetaEngine::getMaximumSaveSlot() const {
+ return 99;
+}
+
+SaveStateList PrinceMetaEngine::listSaves(const char *target) const {
+ Common::SaveFileManager *saveFileMan = g_system->getSavefileManager();
+ Common::StringArray filenames;
+ Common::String pattern = target;
+ pattern += ".???";
+
+ filenames = saveFileMan->listSavefiles(pattern);
+ sort(filenames.begin(), filenames.end()); // Sort (hopefully ensuring we are sorted numerically..)
+
+ SaveStateList saveList;
+ for (Common::StringArray::const_iterator filename = filenames.begin(); filename != filenames.end(); filename++) {
+ // Obtain the last 3 digits of the filename, since they correspond to the save slot
+ int slotNum = atoi(filename->c_str() + filename->size() - 3);
+
+ if (slotNum >= 0 && slotNum <= 99) {
+
+ Common::InSaveFile *file = saveFileMan->openForLoading(*filename);
+ if (file) {
+ Prince::SavegameHeader header;
+
+ // Check to see if it's a ScummVM savegame or not
+ char buffer[kSavegameStrSize + 1];
+ file->read(buffer, kSavegameStrSize + 1);
+
+ if (!strncmp(buffer, kSavegameStr, kSavegameStrSize + 1)) {
+ // Valid savegame
+ if (Prince::PrinceEngine::readSavegameHeader(file, header)) {
+ saveList.push_back(SaveStateDescriptor(slotNum, header.saveName));
+ if (header.thumbnail) {
+ header.thumbnail->free();
+ delete header.thumbnail;
+ }
+ }
+ } else {
+ // Must be an original format savegame
+ saveList.push_back(SaveStateDescriptor(slotNum, "Unknown"));
+ }
+
+ delete file;
+ }
+ }
+ }
+
+ return saveList;
+}
+
+SaveStateDescriptor PrinceMetaEngine::querySaveMetaInfos(const char *target, int slot) const {
+ Common::String fileName = Common::String::format("%s.%03d", target, slot);
+ Common::InSaveFile *f = g_system->getSavefileManager()->openForLoading(fileName);
+
+ if (f) {
+ Prince::SavegameHeader header;
+
+ // Check to see if it's a ScummVM savegame or not
+ char buffer[kSavegameStrSize + 1];
+ f->read(buffer, kSavegameStrSize + 1);
+
+ bool hasHeader = !strncmp(buffer, kSavegameStr, kSavegameStrSize + 1) &&
+ Prince::PrinceEngine::readSavegameHeader(f, header);
+ delete f;
+
+ if (!hasHeader) {
+ // Original savegame perhaps?
+ SaveStateDescriptor desc(slot, "Unknown");
+ return desc;
+ } else {
+ // Create the return descriptor
+ SaveStateDescriptor desc(slot, header.saveName);
+ desc.setThumbnail(header.thumbnail);
+ desc.setSaveDate(header.saveYear, header.saveMonth, header.saveDay);
+ desc.setSaveTime(header.saveHour, header.saveMinutes);
+
+ return desc;
+ }
+ }
+
+ return SaveStateDescriptor();
+}
+
+bool PrinceEngine::readSavegameHeader(Common::InSaveFile *in, SavegameHeader &header) {
+ header.thumbnail = nullptr;
+
+ // Get the savegame version
+ header.version = in->readByte();
+ if (header.version > kSavegameVersion)
+ return false;
+
+ // Read in the string
+ header.saveName.clear();
+ char ch;
+ while ((ch = (char)in->readByte()) != '\0')
+ header.saveName += ch;
+
+ // Get the thumbnail
+ header.thumbnail = Graphics::loadThumbnail(*in);
+ if (!header.thumbnail)
+ return false;
+
+ // Read in save date/time
+ header.saveYear = in->readSint16LE();
+ header.saveMonth = in->readSint16LE();
+ header.saveDay = in->readSint16LE();
+ header.saveHour = in->readSint16LE();
+ header.saveMinutes = in->readSint16LE();
+
+ return true;
+}
+
+void PrinceMetaEngine::removeSaveState(const char *target, int slot) const {
+ Common::String fileName = Common::String::format("%s.%03d", target, slot);
+ g_system->getSavefileManager()->removeSavefile(fileName);
+}
+
+bool PrinceEngine::canSaveGameStateCurrently() {
+ if (_mouseFlag && _mouseFlag != 3) {
+ if (_mainHero->_visible) {
+ // 29 - Basement
+ if (_locationNr != 29) {
+ // No dialog box and not in inventory
+ if (!_dialogFlag && !_showInventoryFlag) {
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+}
+
+bool PrinceEngine::canLoadGameStateCurrently() {
+ if (_mouseFlag && _mouseFlag != 3) {
+ if (_mainHero->_visible) {
+ // 29 - Basement
+ if (_locationNr != 29) {
+ // No dialog box and not in inventory
+ if (!_dialogFlag && !_showInventoryFlag) {
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+}
+
+Common::Error PrinceEngine::saveGameState(int slot, const Common::String &desc) {
+ // Set up the serializer
+ Common::String slotName = generateSaveName(slot);
+ Common::OutSaveFile *saveFile = g_system->getSavefileManager()->openForSaving(slotName);
+
+ // Write out the ScummVM savegame header
+ SavegameHeader header;
+ header.saveName = desc;
+ header.version = kSavegameVersion;
+ writeSavegameHeader(saveFile, header);
+
+ // Write out the data of the savegame
+ syncGame(nullptr, saveFile);
+
+ // Finish writing out game data
+ saveFile->finalize();
+ delete saveFile;
+
+ return Common::kNoError;
+}
+
+Common::String PrinceEngine::generateSaveName(int slot) {
+ return Common::String::format("%s.%03d", _targetName.c_str(), slot);
+}
+
+void PrinceEngine::writeSavegameHeader(Common::OutSaveFile *out, SavegameHeader &header) {
+ // Write out a savegame header
+ out->write(kSavegameStr, kSavegameStrSize + 1);
+
+ out->writeByte(kSavegameVersion);
+
+ // Write savegame name
+ out->write(header.saveName.c_str(), header.saveName.size() + 1);
+
+ // Get the active palette
+ uint8 thumbPalette[256 * 3];
+ _system->getPaletteManager()->grabPalette(thumbPalette, 0, 256);
+
+ // Create a thumbnail and save it
+ Graphics::Surface *thumb = new Graphics::Surface();
+ Graphics::Surface *s = _graph->_frontScreen; // check inventory / map etc..
+ ::createThumbnail(thumb, (const byte *)s->getPixels(), s->w, s->h, thumbPalette);
+ Graphics::saveThumbnail(*out, *thumb);
+ thumb->free();
+ delete thumb;
+
+ // Write out the save date/time
+ TimeDate td;
+ g_system->getTimeAndDate(td);
+ out->writeSint16LE(td.tm_year + 1900);
+ out->writeSint16LE(td.tm_mon + 1);
+ out->writeSint16LE(td.tm_mday);
+ out->writeSint16LE(td.tm_hour);
+ out->writeSint16LE(td.tm_min);
+}
+
+void PrinceEngine::syncGame(Common::SeekableReadStream *readStream, Common::WriteStream *writeStream) {
+ int emptyRoom = 0x00;
+ int normRoom = 0xFF;
+ byte endInv = 0xFF;
+
+ Common::Serializer s(readStream, writeStream);
+
+ if (s.isSaving()) {
+ // Flag values
+ for (int i = 0; i < _flags->kMaxFlags; i++) {
+ uint32 value = _flags->getFlagValue((Flags::Id)(_flags->kFlagMask + i));
+ s.syncAsUint32LE(value);
+ }
+
+ // Dialog data
+ for (uint32 i = 0; i < _dialogDatSize; i++) {
+ byte value = _dialogDat[i];
+ s.syncAsByte(value);
+ }
+
+ // Location number
+ s.syncAsUint16LE(_locationNr);
+
+ // Rooms
+ for (int roomId = 0; roomId < _script->kMaxRooms; roomId++) {
+ Room *room = new Room();
+ room->loadRoom(_script->getRoomOffset(roomId));
+
+ if (room->_mobs) {
+ s.syncAsByte(normRoom);
+ } else {
+ s.syncAsByte(emptyRoom);
+ delete room;
+ continue;
+ }
+
+ // Mobs
+ for (int mobId = 0; mobId < kMaxMobs; mobId++) {
+ byte value = _script->getMobVisible(room->_mobs, mobId);
+ s.syncAsByte(value);
+ }
+
+ // Background animations
+ for (int backAnimSlot = 0; backAnimSlot < kMaxBackAnims; backAnimSlot++) {
+ uint32 value = _script->getBackAnimId(room->_backAnim, backAnimSlot);
+ s.syncAsUint32LE(value);
+ }
+
+ // Objects
+ for (int objectSlot = 0; objectSlot < kMaxObjects; objectSlot++) {
+ byte value = _script->getObjId(room->_obj, objectSlot);
+ s.syncAsByte(value);
+ }
+
+ delete room;
+ }
+
+ // Main hero
+ s.syncAsUint16LE(_mainHero->_visible);
+ s.syncAsUint16LE(_mainHero->_middleX);
+ s.syncAsUint16LE(_mainHero->_middleY);
+ s.syncAsUint16LE(_mainHero->_lastDirection);
+ s.syncAsUint32LE(_mainHero->_color);
+ s.syncAsUint16LE(_mainHero->_maxBoredom);
+ s.syncAsUint32LE(_mainHero->_animSetNr);
+
+ for (uint inv1Slot = 0; inv1Slot < _mainHero->_inventory.size(); inv1Slot++) {
+ s.syncAsByte(_mainHero->_inventory[inv1Slot]);
+ }
+ s.syncAsByte(endInv);
+
+ for (uint inv2Slot = 0; inv2Slot < _mainHero->_inventory2.size(); inv2Slot++) {
+ s.syncAsByte(_mainHero->_inventory2[inv2Slot]);
+ }
+ s.syncAsByte(endInv);
+
+ // Second hero
+ s.syncAsUint16LE(_secondHero->_visible);
+ s.syncAsUint16LE(_secondHero->_middleX);
+ s.syncAsUint16LE(_secondHero->_middleY);
+ s.syncAsUint16LE(_secondHero->_lastDirection);
+ s.syncAsUint32LE(_secondHero->_color);
+ s.syncAsUint16LE(_secondHero->_maxBoredom);
+ s.syncAsUint32LE(_secondHero->_animSetNr);
+
+ for (uint inv1Slot = 0; inv1Slot < _secondHero->_inventory.size(); inv1Slot++) {
+ s.syncAsByte(_secondHero->_inventory[inv1Slot]);
+ }
+ s.syncAsByte(endInv);
+
+ for (uint inv2Slot = 0; inv2Slot < _secondHero->_inventory2.size(); inv2Slot++) {
+ s.syncAsByte(_secondHero->_inventory2[inv2Slot]);
+ }
+ s.syncAsByte(endInv);
+
+ } else {
+ // Cursor reset
+ changeCursor(1);
+ _currentPointerNumber = 1;
+
+ // Flag values
+ for (int i = 0; i < _flags->kMaxFlags; i++) {
+ uint32 value = 0;
+ s.syncAsUint32LE(value);
+ _flags->setFlagValue((Flags::Id)(_flags->kFlagMask + i), value);
+ }
+
+ // Dialog data
+ for (uint32 i = 0; i < _dialogDatSize; i++) {
+ byte value = 0;
+ s.syncAsByte(value);
+ _dialogDat[i] = value;
+ }
+
+ // Location number
+ int restoreRoom = 0;
+ s.syncAsUint16LE(restoreRoom);
+ _flags->setFlagValue(Flags::RESTOREROOM, restoreRoom);
+
+ // Rooms
+ for (int roomId = 0; roomId < _script->kMaxRooms; roomId++) {
+ Room *room = new Room();
+ room->loadRoom(_script->getRoomOffset(roomId));
+
+ byte roomType = emptyRoom;
+ s.syncAsByte(roomType);
+ if (roomType == emptyRoom) {
+ delete room;
+ continue;
+ }
+
+ // Mobs
+ for (int mobId = 0; mobId < kMaxMobs; mobId++) {
+ byte value = 0;
+ s.syncAsByte(value);
+ _script->setMobVisible(room->_mobs, mobId, value);
+ }
+
+ // Background animations
+ for (int backAnimSlot = 0; backAnimSlot < kMaxBackAnims; backAnimSlot++) {
+ uint32 value = 0;
+ s.syncAsUint32LE(value);
+ _script->setBackAnimId(room->_backAnim, backAnimSlot, value);
+ }
+
+ // Objects
+ for (int objectSlot = 0; objectSlot < kMaxObjects; objectSlot++) {
+ byte value = 0;
+ s.syncAsByte(value);
+ _script->setObjId(room->_obj, objectSlot, value);
+ }
+
+ delete room;
+ }
+
+ // Main hero
+ s.syncAsUint16LE(_mainHero->_visible);
+ s.syncAsUint16LE(_mainHero->_middleX);
+ s.syncAsUint16LE(_mainHero->_middleY);
+ s.syncAsUint16LE(_mainHero->_lastDirection);
+ s.syncAsUint32LE(_mainHero->_color);
+ s.syncAsUint16LE(_mainHero->_maxBoredom);
+ s.syncAsUint32LE(_mainHero->_animSetNr);
+ _mainHero->loadAnimSet(_mainHero->_animSetNr);
+
+ _mainHero->_inventory.clear();
+ byte invId = endInv;
+ while (1) {
+ s.syncAsByte(invId);
+ if (invId == endInv) {
+ break;
+ }
+ _mainHero->_inventory.push_back(invId);
+ }
+
+ _mainHero->_inventory2.clear();
+ invId = endInv;
+ while (1) {
+ s.syncAsByte(invId);
+ if (invId == endInv) {
+ break;
+ }
+ _mainHero->_inventory2.push_back(invId);
+ }
+
+ // Second hero
+ s.syncAsUint16LE(_secondHero->_visible);
+ s.syncAsUint16LE(_secondHero->_middleX);
+ s.syncAsUint16LE(_secondHero->_middleY);
+ s.syncAsUint16LE(_secondHero->_lastDirection);
+ s.syncAsUint32LE(_secondHero->_color);
+ s.syncAsUint16LE(_secondHero->_maxBoredom);
+ s.syncAsUint32LE(_secondHero->_animSetNr);
+ _secondHero->loadAnimSet(_secondHero->_animSetNr);
+
+ _secondHero->_inventory.clear();
+ invId = endInv;
+ while (1) {
+ s.syncAsByte(invId);
+ if (invId == endInv) {
+ break;
+ }
+ _secondHero->_inventory.push_back(invId);
+ }
+
+ _secondHero->_inventory2.clear();
+ invId = endInv;
+ while (1) {
+ s.syncAsByte(invId);
+ if (invId == endInv) {
+ break;
+ }
+ _secondHero->_inventory2.push_back(invId);
+ }
+
+ // Script
+ _interpreter->setBgOpcodePC(0);
+ _interpreter->setFgOpcodePC(_script->_scriptInfo.restoreGame);
+
+ }
+}
+
+Common::Error PrinceEngine::loadGameState(int slot) {
+ if (!loadGame(slot)) {
+ return Common::kReadingFailed;
+ }
+ return Common::kNoError;
+}
+
+bool PrinceEngine::loadGame(int slotNumber) {
+ Common::MemoryReadStream *readStream;
+
+ // Open up the savegame file
+ Common::String slotName = generateSaveName(slotNumber);
+ Common::InSaveFile *saveFile = g_system->getSavefileManager()->openForLoading(slotName);
+
+ // Read the data into a data buffer
+ int size = saveFile->size();
+ byte *dataBuffer = (byte *)malloc(size);
+ saveFile->read(dataBuffer, size);
+ readStream = new Common::MemoryReadStream(dataBuffer, size, DisposeAfterUse::YES);
+ delete saveFile;
+
+ // Check to see if it's a ScummVM savegame or not
+ char buffer[kSavegameStrSize + 1];
+ readStream->read(buffer, kSavegameStrSize + 1);
+
+ if (strncmp(buffer, kSavegameStr, kSavegameStrSize + 1) != 0) {
+ delete readStream;
+ return false;
+ } else {
+ SavegameHeader saveHeader;
+
+ if (!readSavegameHeader(readStream, saveHeader)) {
+ delete readStream;
+ return false;
+ }
+
+ // Delete the thumbnail
+ saveHeader.thumbnail->free();
+ delete saveHeader.thumbnail;
+ }
+
+ // Get in the savegame
+ syncGame(readStream, nullptr);
+ delete readStream;
+
+ return true;
+}
+
+} // End of namespace Prince
diff --git a/engines/prince/script.cpp b/engines/prince/script.cpp
new file mode 100644
index 0000000000..4ed3cee6f3
--- /dev/null
+++ b/engines/prince/script.cpp
@@ -0,0 +1,2082 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "prince/script.h"
+#include "prince/prince.h"
+#include "prince/flags.h"
+#include "prince/variatxt.h"
+#include "prince/font.h"
+#include "prince/hero.h"
+#include "prince/resource.h"
+#include "prince/animation.h"
+
+#include "common/debug.h"
+#include "common/debug-channels.h"
+#include "common/archive.h"
+#include "common/memstream.h"
+
+namespace Prince {
+
+static const uint16 kNumOpcodes = 144;
+
+Room::Room() {}
+
+bool Room::loadRoom(byte *roomData) {
+ int roomSize = 64;
+ Common::MemoryReadStream roomStream(roomData, roomSize);
+
+ _mobs = roomStream.readSint32LE();
+ _backAnim = roomStream.readSint32LE();
+ _obj = roomStream.readSint32LE();
+ _nak = roomStream.readSint32LE();
+ _itemUse = roomStream.readSint32LE();
+ _itemGive = roomStream.readSint32LE();
+ _walkTo = roomStream.readSint32LE();
+ _examine = roomStream.readSint32LE();
+ _pickup = roomStream.readSint32LE();
+ _use = roomStream.readSint32LE();
+ _pushOpen = roomStream.readSint32LE();
+ _pullClose = roomStream.readSint32LE();
+ _talk = roomStream.readSint32LE();
+ _give = roomStream.readSint32LE();
+
+ return true;
+}
+
+int Room::getOptionOffset(int option) {
+ switch (option) {
+ case 0:
+ return _walkTo;
+ case 1:
+ return _examine;
+ case 2:
+ return _pickup;
+ case 3:
+ return _use;
+ case 4:
+ return _pushOpen;
+ case 5:
+ return _pullClose;
+ case 6:
+ return _talk;
+ case 7:
+ return _give;
+ default:
+ error("Wrong option - nr %d", option);
+ }
+}
+
+Script::Script(PrinceEngine *vm) : _vm(vm), _data(nullptr), _dataSize(0) {
+}
+
+Script::~Script() {
+ if (_data != nullptr) {
+ free(_data);
+ _dataSize = 0;
+ _data = nullptr;
+ }
+}
+
+bool Script::loadStream(Common::SeekableReadStream &stream) {
+ _dataSize = stream.size();
+ if (!_dataSize) {
+ return false;
+ }
+
+ _data = (byte *)malloc(_dataSize);
+
+ if (!_data) {
+ return false;
+ }
+
+ stream.read(_data, _dataSize);
+
+ Common::MemoryReadStream scriptDataStream(_data, _dataSize);
+ _scriptInfo.rooms = scriptDataStream.readSint32LE();
+ _scriptInfo.startGame = scriptDataStream.readSint32LE();
+ _scriptInfo.restoreGame = scriptDataStream.readSint32LE();
+ _scriptInfo.stdExamine = scriptDataStream.readSint32LE();
+ _scriptInfo.stdPickup = scriptDataStream.readSint32LE();
+ _scriptInfo.stdUse = scriptDataStream.readSint32LE();
+ _scriptInfo.stdOpen = scriptDataStream.readSint32LE();
+ _scriptInfo.stdClose = scriptDataStream.readSint32LE();
+ _scriptInfo.stdTalk = scriptDataStream.readSint32LE();
+ _scriptInfo.stdGive = scriptDataStream.readSint32LE();
+ _scriptInfo.usdCode = scriptDataStream.readSint32LE();
+ _scriptInfo.invObjExam = scriptDataStream.readSint32LE();
+ _scriptInfo.invObjUse = scriptDataStream.readSint32LE();
+ _scriptInfo.invObjUU = scriptDataStream.readSint32LE();
+ _scriptInfo.stdUseItem = scriptDataStream.readSint32LE();
+ _scriptInfo.lightSources = scriptDataStream.readSint32LE();
+ _scriptInfo.specRout = scriptDataStream.readSint32LE();
+ _scriptInfo.invObjGive = scriptDataStream.readSint32LE();
+ _scriptInfo.stdGiveItem = scriptDataStream.readSint32LE();
+ _scriptInfo.goTester = scriptDataStream.readSint32LE();
+
+ return true;
+}
+
+uint16 Script::readScript16(uint32 address) {
+ assert((_data + address + sizeof(uint16)) <= (_data + _dataSize));
+ uint16 data = READ_LE_UINT16(&_data[address]);
+ return data;
+}
+
+uint32 Script::readScript32(uint32 address) {
+ assert((_data + address + sizeof(uint32)) <= (_data + _dataSize));
+ uint32 data = READ_LE_UINT32(&_data[address]);
+ return data;
+}
+
+int16 Script::getLightX(int locationNr) {
+ return (int)READ_LE_UINT16(&_data[_scriptInfo.lightSources + locationNr * 8]);
+}
+
+int16 Script::getLightY(int locationNr) {
+ return (int)READ_LE_UINT16(&_data[_scriptInfo.lightSources + locationNr * 8 + 2]);
+}
+
+int32 Script::getShadowScale(int locationNr) {
+ return (int)READ_LE_UINT16(&_data[_scriptInfo.lightSources + locationNr * 8 + 4]);
+}
+
+uint32 Script::getStartGameOffset() {
+ return _scriptInfo.startGame;
+}
+
+uint32 Script::getLocationInitScript(int initRoomTableOffset, int roomNr) {
+ return (uint32)READ_LE_UINT32(&_data[initRoomTableOffset + roomNr * 4]);
+}
+
+byte Script::getMobVisible(int roomMobOffset, uint16 mob) {
+ return _data[roomMobOffset + mob];
+}
+
+void Script::setMobVisible(int roomMobOffset, uint16 mob, byte value) {
+ _data[roomMobOffset + mob] = value;
+}
+
+uint8 *Script::getRoomOffset(int locationNr) {
+ return &_data[_scriptInfo.rooms + locationNr * 64];
+}
+
+int32 Script::getOptionStandardOffset(int option) {
+ switch (option) {
+ case 1:
+ return _scriptInfo.stdExamine;
+ case 2:
+ return _scriptInfo.stdPickup;
+ case 3:
+ return _scriptInfo.stdUse;
+ case 4:
+ return _scriptInfo.stdOpen;
+ case 5:
+ return _scriptInfo.stdClose;
+ case 6:
+ return _scriptInfo.stdTalk;
+ case 7:
+ return _scriptInfo.stdGive;
+ default:
+ error("Wrong standard option - nr %d", option);
+ }
+}
+
+uint8 *Script::getHeroAnimName(int offset) {
+ return &_data[offset];
+}
+
+uint32 Script::getBackAnimId(int roomBackAnimOffset, int slot) {
+ uint32 animId = READ_LE_UINT32(&_data[roomBackAnimOffset + slot * 4]);
+ return animId;
+}
+
+void Script::setBackAnimId(int roomBackAnimOffset, int slot, int animId) {
+ WRITE_LE_UINT32(&_data[roomBackAnimOffset + slot * 4], animId);
+}
+
+byte Script::getObjId(int roomObjOffset, int slot) {
+ return _data[roomObjOffset + slot];
+}
+
+void Script::setObjId(int roomObjOffset, int slot, byte objectId) {
+ _data[roomObjOffset + slot] = objectId;
+}
+
+int Script::scanMobEvents(int mobMask, int dataEventOffset) {
+ debug("mobMask: %d", mobMask);
+ int i = 0;
+ int16 mob;
+ int32 code;
+ do {
+ mob = (int)READ_LE_UINT16(&_data[dataEventOffset + i * 6]);
+ if (mob == mobMask) {
+ code = (int)READ_LE_UINT32(&_data[dataEventOffset + i * 6 + 2]);
+ debug("code: %d", code);
+ return code;
+ }
+ i++;
+ } while (mob != -1);
+ return -1;
+}
+
+int Script::scanMobEventsWithItem(int mobMask, int dataEventOffset, int itemMask) {
+ debug("mobMask: %d", mobMask);
+ int i = 0;
+ int16 mob;
+ int16 item;
+ int32 code;
+ do {
+ mob = (int)READ_LE_UINT16(&_data[dataEventOffset + i * 8]);
+ if (mob == mobMask) {
+ item = (int)READ_LE_UINT16(&_data[dataEventOffset + i * 8 + 2]);
+ if (item == itemMask) {
+ code = (int)READ_LE_UINT32(&_data[dataEventOffset + i * 8 + 4]);
+ debug("itemMask: %d", item);
+ debug("code: %d", code);
+ return code;
+ }
+ }
+ i++;
+ } while (mob != -1);
+ return -1;
+}
+
+void Script::installSingleBackAnim(Common::Array<BackgroundAnim> &backAnimList, int slot, int roomBackAnimOffset) {
+
+ _vm->removeSingleBackAnim(slot); // free slot before loading
+
+ int offset = roomBackAnimOffset + slot * 4; // BackgroundAnim offset for selected slot number
+
+ BackgroundAnim newBackgroundAnim; // BackgroundAnim seq data and its array of Anim
+
+ int animOffset = READ_LE_UINT32(&_data[offset]); // pos of BackgroundAnim data in script
+ int anims = READ_LE_UINT32(&_data[animOffset + 8]); // amount of Anim in BackgroundAnim
+
+ if (anims == 0) {
+ anims = 1; // anims with 0 as amount in game data has just 1 animation
+ }
+
+ if (animOffset != 0) {
+ Common::MemoryReadStream stream(_data, _dataSize); // stream from script data
+ for (int i = 0; i < anims; i++) {
+ Anim newAnim;
+ stream.seek(animOffset + kStructSizeBAS + kStructSizeBASA * i);
+ // Anim BASA data
+ newAnim._basaData._num = stream.readUint16LE();
+ newAnim._basaData._start = stream.readUint16LE();
+ newAnim._basaData._end = stream.readUint16LE();
+
+ // Anim number in game files
+ int animNumber = newAnim._basaData._num;
+ const Common::String animName = Common::String::format("AN%02d", animNumber);
+ const Common::String shadowName = Common::String::format("AN%02dS", animNumber);
+ newAnim._animData = new Animation();
+ newAnim._shadowData = new Animation();
+ Resource::loadResource(newAnim._animData, animName.c_str(), true);
+ if (!Resource::loadResource(newAnim._shadowData, shadowName.c_str(), false)) {
+ delete newAnim._shadowData;
+ newAnim._shadowData = nullptr;
+ }
+
+ newAnim._usage = 0;
+ newAnim._state = 0; // enabled
+ if ((_vm->_animList[animNumber]._flags & 4)) {
+ newAnim._state = 1;
+ newAnim._frame = _vm->_animList[animNumber]._endPhase;
+ newAnim._showFrame = _vm->_animList[animNumber]._endPhase;
+ } else {
+ newAnim._frame = _vm->_animList[animNumber]._startPhase;
+ newAnim._showFrame = _vm->_animList[animNumber]._startPhase;
+ }
+ newAnim._flags = _vm->_animList[animNumber]._flags;
+ newAnim._lastFrame = _vm->_animList[animNumber]._endPhase;
+ newAnim._loopFrame = _vm->_animList[animNumber]._loopPhase;
+ newAnim._loopType = _vm->_animList[animNumber]._loopType;
+ newAnim._nextAnim = _vm->_animList[animNumber]._nextAnim;
+ newAnim._x = _vm->_animList[animNumber]._x;
+ newAnim._y = _vm->_animList[animNumber]._y;
+ newAnim._currFrame = 0;
+ newAnim._currX = _vm->_animList[animNumber]._x;
+ newAnim._currY = _vm->_animList[animNumber]._y;
+ newAnim._currW = 0;
+ newAnim._currH = 0;
+ newAnim._packFlag = 0;
+ newAnim._shadowBack = _vm->_animList[animNumber]._type;
+ newBackgroundAnim.backAnims.push_back(newAnim);
+ }
+
+ // Anim BAS data
+ stream.seek(animOffset);
+ newBackgroundAnim._seq._type = stream.readUint32LE();
+ newBackgroundAnim._seq._data = stream.readUint32LE();
+ newBackgroundAnim._seq._anims = stream.readUint32LE();
+ stream.skip(12);
+ newBackgroundAnim._seq._current = newBackgroundAnim.backAnims[0]._basaData._num;
+ newBackgroundAnim._seq._counter = 0;
+ newBackgroundAnim._seq._currRelative = 0;
+ newBackgroundAnim._seq._data2 = stream.readUint32LE();
+
+ int start = newBackgroundAnim.backAnims[0]._basaData._start; // BASA_Start of first frame
+ int end = newBackgroundAnim.backAnims[0]._basaData._end; // BASA_End of first frame
+
+ if (start != -1) {
+ newBackgroundAnim.backAnims[0]._frame = start;
+ newBackgroundAnim.backAnims[0]._showFrame = start;
+ newBackgroundAnim.backAnims[0]._loopFrame = start;
+ }
+
+ if (end != -1) {
+ newBackgroundAnim.backAnims[0]._lastFrame = end;
+ }
+
+ backAnimList[slot] = newBackgroundAnim;
+ }
+}
+
+void Script::installBackAnims(Common::Array<BackgroundAnim> &backAnimList, int roomBackAnimOffset) {
+ for (int i = 0; i < _vm->kMaxBackAnims; i++) {
+ installSingleBackAnim(backAnimList, i, roomBackAnimOffset);
+ }
+}
+
+void Script::installObjects(int offset) {
+ for (int i = 0; i < _vm->kMaxObjects; i++) {
+ _vm->_objSlot[i] = _data[offset];
+ offset++;
+ }
+}
+
+bool Script::loadAllMasks(Common::Array<Mask> &maskList, int offset) {
+ Mask tempMask;
+ while (1) {
+ Common::MemoryReadStream maskStream(_data, _dataSize);
+ maskStream.seek(offset);
+ tempMask._state = maskStream.readUint16LE();
+ if (tempMask._state == 0xffff) {
+ break;
+ }
+ tempMask._flags = maskStream.readUint16LE();
+ tempMask._x1 = maskStream.readUint16LE();
+ tempMask._y1 = maskStream.readUint16LE();
+ tempMask._x2 = maskStream.readUint16LE();
+ tempMask._y2 = maskStream.readUint16LE();
+ tempMask._z = maskStream.readUint16LE();
+ tempMask._number = maskStream.readUint16LE();
+
+ const Common::String msStreamName = Common::String::format("MS%02d", tempMask._number);
+ Common::SeekableReadStream *msStream = SearchMan.createReadStreamForMember(msStreamName);
+ if (!msStream) {
+ tempMask._width = 0;
+ tempMask._height = 0;
+ tempMask._data = nullptr;
+ debug("Can't load %s", msStreamName.c_str());
+ delete msStream;
+ } else {
+ int32 dataSize = msStream->size();
+ if (dataSize != -1) {
+ tempMask._data = (byte *)malloc(dataSize);
+ if (msStream->read(tempMask._data, dataSize) != (uint32)dataSize) {
+ free(tempMask._data);
+ delete msStream;
+ return false;
+ }
+ delete msStream;
+ }
+ tempMask._width = tempMask.getWidth();
+ tempMask._height = tempMask.getHeight();
+ }
+
+ maskList.push_back(tempMask);
+ offset += 16; // size of Mask (Nak) struct
+ }
+ return true;
+}
+
+InterpreterFlags::InterpreterFlags() {
+ resetAllFlags();
+}
+
+void InterpreterFlags::resetAllFlags() {
+ memset(_flags, 0, sizeof(_flags));
+}
+
+void InterpreterFlags::setFlagValue(Flags::Id flagId, int32 value) {
+ _flags[(uint32)flagId - kFlagMask] = value;
+}
+
+int32 InterpreterFlags::getFlagValue(Flags::Id flagId) {
+ return _flags[(uint32)flagId - kFlagMask];
+}
+
+Interpreter::Interpreter(PrinceEngine *vm, Script *script, InterpreterFlags *flags) :
+ _vm(vm), _script(script), _flags(flags),
+ _stacktop(0), _opcodeNF(false), _opcodeEnd(false),
+ _waitFlag(0), _result(true) {
+
+ // Initialize the script
+ _mode = "fg";
+ _fgOpcodePC = _script->getStartGameOffset();
+ _bgOpcodePC = 0;
+}
+
+void Interpreter::debugInterpreter(const char *s, ...) {
+ char buf[STRINGBUFLEN];
+ va_list va;
+ va_start(va, s);
+ vsnprintf(buf, STRINGBUFLEN, s, va);
+ va_end(va);
+
+ Common::String str = Common::String::format("@0x%08X: ", _lastInstruction);
+ str += Common::String::format("op %04d: ", _lastOpcode);
+ //debugC(10, DebugChannel::kScript, "PrinceEngine::Script %s %s", str.c_str(), buf);
+ if (!strcmp(_mode, "fg")) {
+ debug(10, "PrinceEngine::Script %s %s", str.c_str(), buf);
+ }
+ //debug("Prince::Script mode %s %s %s", _mode, str.c_str(), buf);
+}
+
+void Interpreter::stepBg() {
+ if (_bgOpcodePC) {
+ _mode = "bg";
+ _bgOpcodePC = step(_bgOpcodePC);
+ }
+}
+
+void Interpreter::stepFg() {
+ if (_fgOpcodePC) {
+ _mode = "fg";
+ _fgOpcodePC = step(_fgOpcodePC);
+ }
+}
+
+uint32 Interpreter::step(uint32 opcodePC) {
+ _currentInstruction = opcodePC;
+
+ while (!_opcodeNF) {
+ _lastInstruction = _currentInstruction;
+
+ // Get the current opcode
+ _lastOpcode = readScript16();
+
+ if (_lastOpcode >= kNumOpcodes)
+ error(
+ "Trying to execute unknown opcode @0x%04X: %02d",
+ _currentInstruction,
+ _lastOpcode);
+
+ // Execute the current opcode
+ OpcodeFunc op = _opcodes[_lastOpcode];
+ (this->*op)();
+ if (_opcodeNF) {
+ _opcodeNF = 0;
+ break;
+ }
+ }
+
+ if (_opcodeEnd) {
+ _vm->quitGame();
+ }
+
+ return _currentInstruction;
+}
+
+void Interpreter::storeNewPC(int opcodePC) {
+ if (_flags->getFlagValue(Flags::GETACTION) == 1) {
+ _flags->setFlagValue(Flags::GETACTIONDATA, opcodePC);
+ opcodePC = _flags->getFlagValue(Flags::GETACTIONBACK);
+ }
+ _fgOpcodePC = opcodePC;
+}
+
+int Interpreter::getLastOPCode() {
+ return _lastOpcode;
+}
+
+int Interpreter::getFgOpcodePC() {
+ return _fgOpcodePC;
+}
+
+uint32 Interpreter::getCurrentString() {
+ return _currentString;
+}
+
+void Interpreter::setCurrentString(uint32 value) {
+ _currentString = value;
+}
+
+byte *Interpreter::getString() {
+ return _string;
+}
+
+void Interpreter::setString(byte *newString) {
+ _string = newString;
+}
+
+void Interpreter::increaseString() {
+ while (*_string) {
+ _string++;
+ }
+ _string++;
+}
+
+void Interpreter::setResult(byte value) {
+ _result = value;
+}
+
+void Interpreter::setBgOpcodePC(uint32 value) {
+ _bgOpcodePC = value;
+}
+
+void Interpreter::setFgOpcodePC(uint32 value) {
+ _fgOpcodePC = value;
+}
+
+uint16 Interpreter::readScript16() {
+ uint16 data = _script->readScript16(_currentInstruction);
+ _currentInstruction += sizeof(uint16);
+ return data;
+}
+
+uint32 Interpreter::readScript32() {
+ uint32 data = _script->readScript32(_currentInstruction);
+ _currentInstruction += sizeof(uint32);
+ return data;
+}
+
+int32 Interpreter::readScriptFlagValue() {
+ uint16 value = readScript16();
+ if (value & InterpreterFlags::kFlagMask) {
+ return _flags->getFlagValue((Flags::Id)value);
+ }
+ return value;
+}
+
+Flags::Id Interpreter::readScriptFlagId() {
+ return (Flags::Id)readScript16();
+}
+
+void Interpreter::O_WAITFOREVER() {
+ _vm->changeCursor(_vm->_currentPointerNumber);
+ _opcodeNF = 1;
+ _currentInstruction -= 2;
+ //debugInterpreter("O_WAITFOREVER");
+}
+
+void Interpreter::O_BLACKPALETTE() {
+ _vm->blackPalette();
+ debugInterpreter("O_BLACKPALETTE");
+}
+
+void Interpreter::O_SETUPPALETTE() {
+ _vm->setPalette(_vm->_roomBmp->getPalette());
+ debugInterpreter("O_SETUPPALETTE");
+}
+
+void Interpreter::O_INITROOM() {
+ int32 roomId = readScriptFlagValue();
+ _vm->loadLocation(roomId);
+ _opcodeNF = 1;
+ debugInterpreter("O_INITROOM %d", roomId);
+}
+
+void Interpreter::O_SETSAMPLE() {
+ int32 sampleId = readScriptFlagValue();
+ int32 sampleNameOffset = readScript32();
+ const char *sampleName = _script->getString(_currentInstruction + sampleNameOffset - 4);
+ _vm->loadSample(sampleId, sampleName);
+ debugInterpreter("O_SETSAMPLE %d %s", sampleId, sampleName);
+}
+
+void Interpreter::O_FREESAMPLE() {
+ int32 sampleId = readScriptFlagValue();
+ _vm->freeSample(sampleId);
+ debugInterpreter("O_FREESAMPLE sampleId: %d", sampleId);
+}
+
+void Interpreter::O_PLAYSAMPLE() {
+ int32 sampleId = readScriptFlagValue();
+ uint16 loopType = readScript16();
+ _vm->playSample(sampleId, loopType);
+ debugInterpreter("O_PLAYSAMPLE sampleId %d loopType %d", sampleId, loopType);
+}
+
+void Interpreter::O_PUTOBJECT() {
+ int32 roomId = readScriptFlagValue();
+ int32 slot = readScriptFlagValue();
+ int32 objectId = readScriptFlagValue();
+ Room *room = new Room();
+ room->loadRoom(_script->getRoomOffset(roomId));
+ _vm->_script->setObjId(room->_obj, slot, objectId);
+ if (_vm->_locationNr == roomId) {
+ _vm->_objSlot[slot] = objectId;
+ }
+ delete room;
+ debugInterpreter("O_PUTOBJECT roomId %d, slot %d, objectId %d", roomId, slot, objectId);
+}
+
+void Interpreter::O_REMOBJECT() {
+ int32 roomId = readScriptFlagValue();
+ int32 slot = readScriptFlagValue();
+ Room *room = new Room();
+ room->loadRoom(_script->getRoomOffset(roomId));
+ _vm->_script->setObjId(room->_obj, slot, 0xFF);
+ if (_vm->_locationNr == roomId) {
+ _vm->_objSlot[slot] = 0xFF;
+ }
+ delete room;
+ debugInterpreter("O_REMOBJECT roomId %d slot %d", roomId, slot);
+}
+
+void Interpreter::O_SHOWANIM() {
+ int32 slot = readScriptFlagValue();
+ int32 animId = readScriptFlagValue();
+ _vm->freeNormAnim(slot);
+ Anim &anim = _vm->_normAnimList[slot];
+ AnimListItem &animList = _vm->_animList[animId];
+ anim._currFrame = 0;
+ anim._packFlag = 0;
+ anim._state = 0;
+ anim._frame = animList._startPhase;
+ anim._showFrame = animList._startPhase;
+ anim._lastFrame = animList._endPhase;
+ anim._loopFrame = animList._loopPhase;
+ anim._x = animList._x;
+ anim._y = animList._y;
+ anim._loopType = animList._loopType;
+ anim._shadowBack = animList._type;
+ anim._flags = animList._flags;
+ anim._nextAnim = animList._nextAnim;
+ int fileNumber = animList._fileNumber;
+ const Common::String animName = Common::String::format("AN%02d", fileNumber);
+ const Common::String shadowName = Common::String::format("AN%02dS", fileNumber);
+ anim._animData = new Animation();
+ anim._shadowData = new Animation();
+ Resource::loadResource(anim._animData, animName.c_str(), true);
+ if (!Resource::loadResource(anim._shadowData, shadowName.c_str(), false)) {
+ delete anim._shadowData;
+ anim._shadowData = nullptr;
+ }
+
+ // WALKAROUND: fix for turning off bard's wife background animation
+ // in front of bard's house (location 7) after giving her poem (item 33)
+ // in script: GiveLetter (line 11082)
+ if (_currentInstruction == kGiveLetterScriptFix) {
+ _vm->_backAnimList[1].backAnims[0]._state = 1;
+ }
+
+ debugInterpreter("O_SHOWANIM slot %d, animId %d", slot, animId);
+}
+
+void Interpreter::O_CHECKANIMEND() {
+ int32 slot = readScriptFlagValue();
+ if (_vm->_normAnimList[slot]._frame != _vm->_normAnimList[slot]._lastFrame - 1) {
+ _currentInstruction -= 4;
+ _opcodeNF = 1;
+ }
+ debugInterpreter("O_CHECKANIMEND slot %d", slot);
+}
+
+void Interpreter::O_FREEANIM() {
+ int32 slot = readScriptFlagValue();
+ _vm->freeNormAnim(slot);
+ debugInterpreter("O_FREEANIM slot %d", slot);
+}
+
+void Interpreter::O_CHECKANIMFRAME() {
+ int32 slot = readScriptFlagValue();
+ int32 frameNumber = readScriptFlagValue();
+ if (_vm->_normAnimList[slot]._frame != frameNumber - 1) {
+ _currentInstruction -= 6;
+ _opcodeNF = 1;
+ }
+ debugInterpreter("O_CHECKANIMFRAME slot %d, frameNumber %d", slot, frameNumber);
+}
+
+void Interpreter::O_PUTBACKANIM() {
+ int32 roomId = readScriptFlagValue();
+ int32 slot = readScriptFlagValue();
+ int32 animId = readScript32();
+ Room *room = new Room();
+ room->loadRoom(_script->getRoomOffset(roomId));
+ _vm->_script->setBackAnimId(room->_backAnim, slot, animId);
+ if (_vm->_locationNr == roomId) {
+ _vm->_script->installSingleBackAnim(_vm->_backAnimList, slot, room->_backAnim);
+ }
+ delete room;
+
+ // WALKAROUND: fix for turning on 'walking bird' background animation too soon,
+ // after completing 'throw a rock' mini-game in Silmaniona location.
+ // Second bird shouldn't appear when normal animation is still in use
+ // in script lines 13814 and 13848
+ if (_currentInstruction == kSecondBirdAnimationScriptFix) {
+ if (_vm->_normAnimList[1]._state == 0) {
+ _vm->_backAnimList[0].backAnims[0]._state = 1;
+ }
+ }
+
+ debugInterpreter("O_PUTBACKANIM roomId %d, slot %d, animId %d", roomId, slot, animId);
+}
+
+void Interpreter::O_REMBACKANIM() {
+ int32 roomId = readScriptFlagValue();
+ int32 slot = readScriptFlagValue();
+ if (_vm->_locationNr == roomId) {
+ _vm->removeSingleBackAnim(slot);
+ }
+ Room *room = new Room();
+ room->loadRoom(_script->getRoomOffset(roomId));
+ _vm->_script->setBackAnimId(room->_backAnim, slot, 0);
+ delete room;
+ debugInterpreter("O_REMBACKANIM roomId %d, slot %d", roomId, slot);
+}
+
+void Interpreter::O_CHECKBACKANIMFRAME() {
+ int32 slotId = readScriptFlagValue();
+ int32 frameId = readScriptFlagValue();
+ int currAnim = _vm->_backAnimList[slotId]._seq._currRelative;
+ if (_vm->_backAnimList[slotId].backAnims[currAnim]._frame != frameId - 1) {
+ _currentInstruction -= 6;
+ _opcodeNF = 1;
+ }
+ debugInterpreter("O_CHECKBACKANIMFRAME slotId %d, frameId %d", slotId, frameId);
+}
+
+// Not used in script
+void Interpreter::O_FREEALLSAMPLES() {
+ error("O_FREEALLSAMPLES");
+}
+
+void Interpreter::O_SETMUSIC() {
+ uint16 musicId = readScript16();
+ _vm->loadMusic(musicId);
+ debugInterpreter("O_SETMUSIC musicId %d", musicId);
+}
+
+void Interpreter::O_STOPMUSIC() {
+ _vm->stopMusic();
+ debugInterpreter("O_STOPMUSIC");
+}
+
+void Interpreter::O__WAIT() {
+ int32 pause = readScriptFlagValue();
+ debugInterpreter("O__WAIT pause %d", pause);
+ if (!_waitFlag) {
+ // set new wait flag value and continue
+ _waitFlag = pause;
+ _opcodeNF = 1;
+ _currentInstruction -= 4;
+ return;
+ }
+ _waitFlag--;
+ if (_waitFlag > 0) {
+ _opcodeNF = 1;
+ _currentInstruction -= 4;
+ return;
+ }
+}
+
+// Not used in script
+void Interpreter::O_UPDATEOFF() {
+ error("O_UPDATEOFF");
+}
+
+// Not used in script
+void Interpreter::O_UPDATEON() {
+ error("O_UPDATEON");
+}
+
+// Not used in script
+void Interpreter::O_UPDATE () {
+ error("O_UPDATE");
+}
+
+// Not used in script
+void Interpreter::O_CLS() {
+ error("O_CLS");
+}
+
+void Interpreter::O__CALL() {
+ int32 address = readScript32();
+ _stack[_stacktop] = _currentInstruction;
+ _stacktop++;
+ _currentInstruction += address - 4;
+ debugInterpreter("O__CALL 0x%04X", _currentInstruction);
+}
+
+void Interpreter::O_RETURN() {
+ if (_stacktop > 0) {
+ _stacktop--;
+ _currentInstruction = _stack[_stacktop];
+ debugInterpreter("O_RETURN 0x%04X", _currentInstruction);
+ } else {
+ error("O_RETURN: Stack is empty");
+ }
+}
+
+void Interpreter::O_GO() {
+ int32 opPC = readScript32();
+ _currentInstruction += opPC - 4;
+ debugInterpreter("O_GO 0x%04X", opPC);
+}
+
+void Interpreter::O_BACKANIMUPDATEOFF() {
+ int32 slotId = readScriptFlagValue();
+ int currAnim = _vm->_backAnimList[slotId]._seq._currRelative;
+ if (!_vm->_backAnimList[slotId].backAnims.empty()) {
+ _vm->_backAnimList[slotId].backAnims[currAnim]._state = 1;
+ }
+ debugInterpreter("O_BACKANIMUPDATEOFF slotId %d", slotId);
+}
+
+void Interpreter::O_BACKANIMUPDATEON() {
+ int32 slotId = readScriptFlagValue();
+ int currAnim = _vm->_backAnimList[slotId]._seq._currRelative;
+ if (!_vm->_backAnimList[slotId].backAnims.empty()) {
+ _vm->_backAnimList[slotId].backAnims[currAnim]._state = 0;
+ }
+ debugInterpreter("O_BACKANIMUPDATEON slotId %d", slotId);
+}
+
+void Interpreter::O_CHANGECURSOR() {
+ int32 cursorId = readScriptFlagValue();
+ _vm->changeCursor(cursorId);
+ debugInterpreter("O_CHANGECURSOR %x", cursorId);
+}
+
+// Not used in script
+void Interpreter::O_CHANGEANIMTYPE() {
+ error("O_CHANGEANIMTYPE");
+}
+
+void Interpreter::O__SETFLAG() {
+ Flags::Id flagId = readScriptFlagId();
+ int32 value = readScriptFlagValue();
+ _flags->setFlagValue((Flags::Id)(flagId), value);
+ debugInterpreter("O__SETFLAG 0x%04X (%s) = %d", flagId, Flags::getFlagName(flagId), value);
+}
+
+void Interpreter::O_COMPARE() {
+ Flags::Id flagId = readScriptFlagId();
+ int32 value = readScriptFlagValue();
+ _result = _flags->getFlagValue(flagId) != value;
+ debugInterpreter("O_COMPARE flagId 0x%04X (%s), value %d == %d (%d)", flagId, Flags::getFlagName(flagId), value, _flags->getFlagValue(flagId), _result);
+}
+
+void Interpreter::O_JUMPZ() {
+ int32 offset = readScript32();
+ if (!_result) {
+ _currentInstruction += offset - 4;
+ }
+ debugInterpreter("O_JUMPZ result = %d, next %08x, offset 0x%08X", _result, _currentInstruction, offset);
+}
+
+void Interpreter::O_JUMPNZ() {
+ int32 offset = readScript32();
+ if (_result) {
+ _currentInstruction += offset - 4;
+ }
+ debugInterpreter("O_JUMPNZ result = %d, next %08x, offset 0x%08X", _result, _currentInstruction, offset);
+}
+
+void Interpreter::O_EXIT() {
+ int32 exitCode = readScriptFlagValue();
+ _opcodeEnd = true;
+ _opcodeNF = 1;
+ if (exitCode == 0x2EAD) {
+ _vm->scrollCredits();
+ }
+ debugInterpreter("O_EXIT exitCode %d", exitCode);
+}
+
+void Interpreter::O_ADDFLAG() {
+ Flags::Id flagId = readScriptFlagId();
+ int32 value = readScriptFlagValue();
+ _flags->setFlagValue(flagId, _flags->getFlagValue(flagId) + value);
+ if (_flags->getFlagValue(flagId)) {
+ _result = 1;
+ }
+ else {
+ _result = 0;
+ }
+ debugInterpreter("O_ADDFLAG flagId %04x (%s), value %d", flagId, Flags::getFlagName(flagId), value);
+}
+
+void Interpreter::O_TALKANIM() {
+ int32 animNumber = readScriptFlagValue();
+ int32 slot = readScriptFlagValue();
+ _vm->doTalkAnim(animNumber, slot, kNormalAnimation);
+ debugInterpreter("O_TALKANIM animNumber %d, slot %d", animNumber, slot);
+}
+
+void Interpreter::O_SUBFLAG() {
+ Flags::Id flagId = readScriptFlagId();
+ int32 value = readScriptFlagValue();
+ _flags->setFlagValue(flagId, _flags->getFlagValue(flagId) - value);
+ if (_flags->getFlagValue(flagId)) {
+ _result = 1;
+ }
+ else {
+ _result = 0;
+ }
+ debugInterpreter("O_SUBFLAG flagId %d, value %d", flagId, value);
+}
+
+void Interpreter::O_SETSTRING() {
+ int32 offset = readScript32();
+ _currentString = offset;
+ if (offset >= 80000) {
+ _string = _vm->_variaTxt->getString(offset - 80000);
+ debugInterpreter("GetVaria %s", _string);
+ }
+ else if (offset < 2000) {
+ _vm->_dialogData = &_vm->_dialogDat[offset * 4 - 4];
+ uint32 of = READ_LE_UINT32(_vm->_talkTxt + offset * 4);
+ const char *txt = (const char *)&_vm->_talkTxt[of];
+ _string = &_vm->_talkTxt[of];
+ debugInterpreter("TalkTxt %d %s", of, txt);
+ }
+ debugInterpreter("O_SETSTRING %04d", offset);
+}
+
+void Interpreter::O_ANDFLAG() {
+ Flags::Id flagId = readScriptFlagId();
+ int32 value = readScriptFlagValue();
+ _flags->setFlagValue(flagId, _flags->getFlagValue(flagId) & value);
+ if (_flags->getFlagValue(flagId)) {
+ _result = 1;
+ } else {
+ _result = 0;
+ }
+ debugInterpreter("O_ANDFLAG flagId %d, value %d", flagId, value);
+}
+
+void Interpreter::O_GETMOBDATA() {
+ Flags::Id flagId = readScriptFlagId();
+ int32 mobId = readScriptFlagValue();
+ int32 mobOffset = readScriptFlagValue();
+ int16 value = _vm->_mobList[mobId].getData((Mob::AttrId)mobOffset);
+ _flags->setFlagValue(flagId, value);
+ debugInterpreter("O_GETMOBDATA flagId %d, modId %d, mobOffset %d", flagId, mobId, mobOffset);
+}
+
+void Interpreter::O_ORFLAG() {
+ Flags::Id flagId = readScriptFlagId();
+ int32 value = readScriptFlagValue();
+ _flags->setFlagValue(flagId, _flags->getFlagValue(flagId) | value);
+ if (_flags->getFlagValue(flagId)) {
+ _result = 1;
+ } else {
+ _result = 0;
+ }
+ debugInterpreter("O_ORFLAG flagId %d, value %d", flagId, value);
+}
+
+void Interpreter::O_SETMOBDATA() {
+ int32 mobId = readScriptFlagValue();
+ int32 mobOffset = readScriptFlagValue();
+ int32 value = readScriptFlagValue();
+ _vm->_mobList[mobId].setData((Mob::AttrId)mobOffset, value);
+ debugInterpreter("O_SETMOBDATA mobId %d, mobOffset %d, value %d", mobId, mobOffset, value);
+}
+
+void Interpreter::O_XORFLAG() {
+ Flags::Id flagId = readScriptFlagId();
+ int32 value = readScriptFlagValue();
+ _flags->setFlagValue(flagId, _flags->getFlagValue(flagId) ^ value);
+ if (_flags->getFlagValue(flagId)) {
+ _result = 1;
+ } else {
+ _result = 0;
+ }
+ debugInterpreter("O_XORFLAG flagId %d, value %d", flagId, value);
+}
+
+void Interpreter::O_GETMOBTEXT() {
+ int32 mob = readScriptFlagValue();
+ _currentString = _vm->_locationNr * 100 + mob + 60001;
+ _string = (byte *)_vm->_mobList[mob]._examText.c_str();
+ debugInterpreter("O_GETMOBTEXT mob %d", mob);
+}
+
+void Interpreter::O_MOVEHERO() {
+ int32 heroId = readScriptFlagValue();
+ int32 x = readScriptFlagValue();
+ int32 y = readScriptFlagValue();
+ int32 dir = readScriptFlagValue();
+ _vm->moveRunHero(heroId, x, y, dir, false);
+ debugInterpreter("O_MOVEHERO heroId %d, x %d, y %d, dir %d", heroId, x, y, dir);
+}
+
+void Interpreter::O_WALKHERO() {
+ int32 heroId = readScriptFlagValue();
+ Hero *hero = nullptr;
+ if (!heroId) {
+ hero = _vm->_mainHero;
+ } else if (heroId == 1) {
+ hero = _vm->_secondHero;
+ }
+ if (hero != nullptr) {
+ if (hero->_state != Hero::kHeroStateStay) {
+ _currentInstruction -= 4;
+ _opcodeNF = 1;
+ }
+ }
+ debugInterpreter("O_WALKHERO %d", heroId);
+}
+
+void Interpreter::O_SETHERO() {
+ int32 heroId = readScriptFlagValue();
+ int32 x = readScriptFlagValue();
+ int32 y = readScriptFlagValue();
+ int32 dir = readScriptFlagValue();
+ Hero *hero = nullptr;
+ if (!heroId) {
+ hero = _vm->_mainHero;
+ } else if (heroId == 1) {
+ hero = _vm->_secondHero;
+ }
+ if (hero != nullptr) {
+ hero->setPos(x, y);
+ hero->_lastDirection = dir;
+ hero->_visible = 1;
+ hero->countDrawPosition();
+ }
+ debugInterpreter("O_SETHERO heroId %d, x %d, y %d, dir %d", heroId, x, y, dir);
+}
+
+void Interpreter::O_HEROOFF() {
+ int32 heroId = readScriptFlagValue();
+ Hero *hero = nullptr;
+ if (!heroId) {
+ hero = _vm->_mainHero;
+ } else if (heroId == 1) {
+ hero = _vm->_secondHero;
+ }
+ if (hero != nullptr) {
+ hero->setVisible(false);
+ }
+ debugInterpreter("O_HEROOFF %d", heroId);
+}
+
+void Interpreter::O_HEROON() {
+ int32 heroId = readScriptFlagValue();
+ Hero *hero = nullptr;
+ if (!heroId) {
+ hero = _vm->_mainHero;
+ } else if (heroId == 1) {
+ hero = _vm->_secondHero;
+ }
+ if (hero != nullptr) {
+ hero->setVisible(true);
+ }
+ debugInterpreter("O_HEROON %d", heroId);
+}
+
+void Interpreter::O_CLSTEXT() {
+ int32 slot = readScriptFlagValue();
+ _vm->_textSlots[slot]._str = nullptr;
+ _vm->_textSlots[slot]._time = 0;
+ debugInterpreter("O_CLSTEXT slot %d", slot);
+}
+
+void Interpreter::O_CALLTABLE() {
+ Flags::Id flagId = readScriptFlagId();
+ int roomNr = _flags->getFlagValue(flagId);
+ int32 tableOffset = readScript32();
+ int initLocationScript = _script->getLocationInitScript(tableOffset, roomNr);
+ if (initLocationScript) {
+ _stack[_stacktop] = _currentInstruction;
+ _stacktop++;
+ _currentInstruction = initLocationScript;
+ }
+ debugInterpreter("O_CALLTABLE loc %d", roomNr);
+}
+
+void Interpreter::O_CHANGEMOB() {
+ int32 mob = readScriptFlagValue();
+ int32 value = readScriptFlagValue();
+ value ^= 1;
+ _vm->_script->setMobVisible(_vm->_room->_mobs, mob, value);
+ _vm->_mobList[mob]._visible = value;
+ debugInterpreter("O_CHANGEMOB mob %d, value %d", mob, value);
+}
+
+void Interpreter::O_ADDINV() {
+ int32 hero = readScriptFlagValue();
+ int32 item = readScriptFlagValue();
+ _vm->addInv(hero, item, false);
+ debugInterpreter("O_ADDINV hero %d, item %d", hero, item);
+}
+
+void Interpreter::O_REMINV() {
+ int32 hero = readScriptFlagValue();
+ int32 item = readScriptFlagValue();
+ _vm->remInv(hero, item);
+ debugInterpreter("O_REMINV hero %d, item %d", hero, item);
+}
+
+// Not used in script
+void Interpreter::O_REPINV() {
+ error("O_REPINV");
+}
+
+// Not used in script
+void Interpreter::O_OBSOLETE_GETACTION() {
+ error("O_OBSOLETE_GETACTION");
+}
+
+// Not used in script
+void Interpreter::O_ADDWALKAREA() {
+ error("O_ADDWALKAREA");
+}
+
+// Not used in script
+void Interpreter::O_REMWALKAREA() {
+ error("O_REMWALKAREA");
+}
+
+ // Not used in script
+void Interpreter::O_RESTOREWALKAREA() {
+ error("O_RESTOREWALKAREA");
+}
+
+void Interpreter::O_WAITFRAME() {
+ _opcodeNF = true;
+ debugInterpreter("O_WAITFRAME");
+}
+
+void Interpreter::O_SETFRAME() {
+ int32 anim = readScriptFlagValue();
+ int32 frame = readScriptFlagValue();
+ _vm->_normAnimList[anim]._frame = frame;
+ debugInterpreter("O_SETFRAME anim %d, frame %d", anim, frame);
+}
+
+// Not used in script
+void Interpreter::O_RUNACTION() {
+ error("O_RUNACTION");
+}
+
+void Interpreter::O_COMPAREHI() {
+ Flags::Id flag = readScriptFlagId();
+ int32 value = readScriptFlagValue();
+ int32 flagValue = _flags->getFlagValue(flag);
+ if (flagValue > value) {
+ _result = 0;
+ } else {
+ _result = 1;
+ }
+ debugInterpreter("O_COMPAREHI flag %04x - (%s), value %d, flagValue %d, result %d", flag, Flags::getFlagName(flag), value, flagValue, _result);
+}
+
+void Interpreter::O_COMPARELO() {
+ Flags::Id flag = readScriptFlagId();
+ int32 value = readScriptFlagValue();
+ int32 flagValue = _flags->getFlagValue(flag);
+ if (flagValue < value) {
+ _result = 0;
+ } else {
+ _result = 1;
+ }
+ debugInterpreter("O_COMPARELO flag %04x - (%s), value %d, flagValue %d, result %d", flag, Flags::getFlagName(flag), value, flagValue, _result);
+}
+
+// Not used in script
+void Interpreter::O_PRELOADSET() {
+ error("O_PRELOADSET");
+}
+
+// Not used in script
+void Interpreter::O_FREEPRELOAD() {
+ error("O_FREEPRELOAD");
+}
+
+// Not used in script
+void Interpreter::O_CHECKINV() {
+ error("O_CHECKINV");
+}
+
+void Interpreter::O_TALKHERO() {
+ int32 hero = readScriptFlagValue();
+ _vm->talkHero(hero);
+ debugInterpreter("O_TALKHERO hero %d", hero);
+}
+
+void Interpreter::O_WAITTEXT() {
+ int32 slot = readScriptFlagValue();
+ Text &text = _vm->_textSlots[slot];
+ if (text._time && text._str) {
+ if (_flags->getFlagValue(Flags::ESCAPED)) {
+ text._time = 1;
+ if (!slot) {
+ _vm->_mainHero->_talkTime = 1;
+ } else if (slot == 1) {
+ _vm->_secondHero->_talkTime = 1;
+ }
+ } else {
+ _opcodeNF = 1;
+ _currentInstruction -= 4;
+ }
+ }
+ //debugInterpreter("O_WAITTEXT slot %d", slot);
+}
+
+void Interpreter::O_SETHEROANIM() {
+ int32 heroId = readScriptFlagValue();
+ int32 offset = readScript32();
+ Hero *hero = nullptr;
+ if (!heroId) {
+ hero = _vm->_mainHero;
+ } else {
+ hero = _vm->_secondHero;
+ }
+ if (hero != nullptr) {
+ hero->freeHeroAnim();
+ if (hero ->_specAnim == nullptr) {
+ hero->_specAnim = new Animation();
+ if (offset < 100) {
+ const Common::String animName = Common::String::format("AN%02d", offset);
+ Resource::loadResource(hero->_specAnim, animName.c_str(), true);
+ } else {
+ const Common::String animName = Common::String((const char *)_script->getHeroAnimName(offset));
+ Common::String normalizedPath = lastPathComponent(animName, '\\');
+ Resource::loadResource(hero->_specAnim, normalizedPath.c_str(), true);
+ }
+ hero->_phase = 0;
+ hero->_state = Hero::kHeroStateSpec;
+ }
+ }
+ debugInterpreter("O_SETHEROANIM hero %d, offset %d", hero, offset);
+}
+
+void Interpreter::O_WAITHEROANIM() {
+ int32 heroId = readScriptFlagValue();
+ Hero *hero = nullptr;
+ if (!heroId) {
+ hero = _vm->_mainHero;
+ } else {
+ hero = _vm->_secondHero;
+ }
+ if (hero != nullptr) {
+ if (hero->_state == Hero::kHeroStateSpec) {
+ _currentInstruction -= 4;
+ _opcodeNF = 1;
+ }
+ }
+ debugInterpreter("O_WAITHEROANIM heroId %d", heroId);
+}
+
+void Interpreter::O_GETHERODATA() {
+ Flags::Id flagId = readScriptFlagId();
+ int32 heroId = readScriptFlagValue();
+ int32 heroOffset = readScriptFlagValue();
+ Hero *hero = nullptr;
+ if (!heroId) {
+ hero = _vm->_mainHero;
+ } else {
+ hero = _vm->_secondHero;
+ }
+ if (hero != nullptr) {
+ _flags->setFlagValue(flagId, hero->getData((Hero::AttrId)heroOffset));
+ }
+ debugInterpreter("O_GETHERODATA flag %04x - (%s), heroId %d, heroOffset %d", flagId, Flags::getFlagName(flagId), heroId, heroOffset);
+}
+
+// No need of implementation here
+void Interpreter::O_GETMOUSEBUTTON() {
+ debugInterpreter("O_GETMOUSEBUTTON");
+}
+
+void Interpreter::O_CHANGEFRAMES() {
+ int32 anim = readScriptFlagValue();
+ int32 frame = readScriptFlagValue();
+ int32 lastFrame = readScriptFlagValue();
+ int32 loopFrame = readScriptFlagValue();
+ _vm->_normAnimList[anim]._frame = frame;
+ _vm->_normAnimList[anim]._lastFrame = lastFrame;
+ _vm->_normAnimList[anim]._loopFrame = loopFrame;
+ debugInterpreter("O_CHANGFRAMES anim %d, frame %d, lastFrame %d, loopFrame %d", anim, frame, lastFrame, loopFrame);
+}
+
+void Interpreter::O_CHANGEBACKFRAMES() {
+ int32 anim = readScriptFlagValue();
+ int32 frame = readScriptFlagValue();
+ int32 lastFrame = readScriptFlagValue();
+ int32 loopFrame = readScriptFlagValue();
+ int currAnim = _vm->_backAnimList[anim]._seq._currRelative;
+ Anim &backAnim = _vm->_backAnimList[anim].backAnims[currAnim];
+ backAnim._frame = frame;
+ backAnim._lastFrame = lastFrame;
+ backAnim._loopFrame = loopFrame;
+ debugInterpreter("O_CHANGEBACKFRAMES anim %d, frame %d, lastFrame %d, loopFrame %d", anim, frame, lastFrame, loopFrame);
+}
+
+void Interpreter::O_GETBACKANIMDATA() {
+ Flags::Id flagId = readScriptFlagId();
+ int32 animNumber = readScriptFlagValue();
+ int32 animDataOffset = readScriptFlagValue();
+ int currAnim = _vm->_backAnimList[animNumber]._seq._currRelative;
+ int16 value = _vm->_backAnimList[animNumber].backAnims[currAnim].getAnimData((Anim::AnimOffsets)(animDataOffset));
+ _flags->setFlagValue((Flags::Id)(flagId), value);
+ debugInterpreter("O_GETBACKANIMDATA flag %04X (%s), animNumber %d, animDataOffset %d, value %d", flagId, Flags::getFlagName(flagId), animNumber, animDataOffset, value);
+}
+
+void Interpreter::O_GETANIMDATA() {
+ Flags::Id flagId = readScriptFlagId();
+ int32 anim = readScriptFlagValue();
+ int32 animOffset = readScriptFlagValue();
+ if (_vm->_normAnimList[anim]._animData != nullptr) {
+ _flags->setFlagValue(flagId, _vm->_normAnimList[anim].getAnimData((Anim::AnimOffsets)(animOffset)));
+ }
+ debugInterpreter("O_GETANIMDATA flag %04X (%s), anim %d, animOffset %d", flagId, Flags::getFlagName(flagId), anim, animOffset);
+}
+
+void Interpreter::O_SETBGCODE() {
+ int32 offset = readScript32();
+ _bgOpcodePC = _currentInstruction + offset - 4;
+ debugInterpreter("O_SETBGCODE next %08x, offset %08x", _bgOpcodePC, offset);
+}
+
+void Interpreter::O_SETBACKFRAME() {
+ int32 anim = readScriptFlagValue();
+ int32 frame = readScriptFlagValue();
+ int currAnim = _vm->_backAnimList[anim]._seq._currRelative;
+ if (_vm->_backAnimList[anim].backAnims[currAnim]._animData != nullptr) {
+ _vm->_backAnimList[anim].backAnims[currAnim]._frame = frame;
+ }
+ debugInterpreter("O_SETBACKFRAME anim %d, frame %d", anim, frame);
+}
+
+void Interpreter::O_GETRND() {
+ Flags::Id flag = readScriptFlagId();
+ uint16 rndSeed = readScript16();
+ int value = _vm->_randomSource.getRandomNumber(rndSeed - 1);
+ _flags->setFlagValue(flag, value);
+ debugInterpreter("O_GETRND flag %d, rndSeed %d, value %d", flag, rndSeed, value);
+}
+
+void Interpreter::O_TALKBACKANIM() {
+ int32 animNumber = readScriptFlagValue();
+ int32 slot = readScriptFlagValue();
+ _vm->doTalkAnim(animNumber, slot, kBackgroundAnimation);
+ debugInterpreter("O_TALKBACKANIM animNumber %d, slot %d", animNumber, slot);
+}
+
+// Simplifying, because used only once in Location 20
+void Interpreter::O_LOADPATH() {
+ readScript32();
+ _vm->loadPath("path2");
+ debugInterpreter("O_LOADPATH - path2");
+}
+
+void Interpreter::O_GETCHAR() {
+ Flags::Id flagId = readScriptFlagId();
+ _flags->setFlagValue(flagId, *_string);
+ _string++;
+ debugInterpreter("O_GETCHAR %04X (%s) %02x", flagId, Flags::getFlagName(flagId), _flags->getFlagValue(flagId));
+}
+
+void Interpreter::O_SETDFLAG() {
+ Flags::Id flagId = readScriptFlagId();
+ int32 address = readScript32();
+ _flags->setFlagValue((Flags::Id)(flagId), _currentInstruction + address - 4);
+ debugInterpreter("O_SETDFLAG 0x%04X (%s) = 0x%04X", flagId, Flags::getFlagName(flagId), _currentInstruction + address - 4);
+}
+
+void Interpreter::O_CALLDFLAG() {
+ Flags::Id flagId = readScriptFlagId();
+ _stack[_stacktop] = _currentInstruction;
+ _stacktop++;
+ _currentInstruction = _flags->getFlagValue(flagId);
+ debugInterpreter("O_CALLDFLAG 0x%04X (%s) = 0x%04X", flagId, Flags::getFlagName(flagId), _currentInstruction);
+}
+
+void Interpreter::O_PRINTAT() {
+ int32 slot = readScriptFlagValue();
+ int32 x = readScriptFlagValue();
+ int32 y = readScriptFlagValue();
+ int32 color = _flags->getFlagValue(Flags::KOLOR);
+ _vm->printAt(slot, color, (char *)_string, x, y);
+ increaseString();
+ debugInterpreter("O_PRINTAT slot %d, x %d, y %d", slot, x, y);
+}
+
+void Interpreter::O_ZOOMIN() {
+ int32 slot = readScriptFlagValue();
+ _vm->initZoomIn(slot);
+ debugInterpreter("O_ZOOMIN slot %04d", slot);
+}
+
+void Interpreter::O_ZOOMOUT() {
+ int32 slot = readScriptFlagValue();
+ _vm->initZoomOut(slot);
+ debugInterpreter("O_ZOOMOUT slot %d", slot);
+}
+
+// Not used in script
+void Interpreter::O_SETSTRINGOFFSET() {
+ error("O_SETSTRINGOFFSET");
+}
+
+void Interpreter::O_GETOBJDATA() {
+ Flags::Id flag = readScriptFlagId();
+ int32 slot = readScriptFlagValue();
+ int32 objOffset = readScriptFlagValue();
+ int nr = _vm->_objSlot[slot];
+ if (nr != 0xFF) {
+ int16 value = _vm->_objList[nr]->getData((Object::AttrId)objOffset);
+ _flags->setFlagValue(flag, value);
+ }
+ debugInterpreter("O_GETOBJDATA flag %d, objSlot %d, objOffset %d", flag, slot, objOffset);
+}
+
+void Interpreter::O_SETOBJDATA() {
+ int32 slot = readScriptFlagValue();
+ int32 objOffset = readScriptFlagValue();
+ int32 value = readScriptFlagValue();
+ int nr = _vm->_objSlot[slot];
+ if (nr != 0xFF) {
+ _vm->_objList[nr]->setData((Object::AttrId)objOffset, value);
+ }
+ debugInterpreter("O_SETOBJDATA objSlot %d, objOffset %d, value %d", slot, objOffset, value);
+}
+
+// Not used in script
+void Interpreter::O_SWAPOBJECTS() {
+ error("O_SWAPOBJECTS");
+}
+
+void Interpreter::O_CHANGEHEROSET() {
+ int32 heroId = readScriptFlagValue();
+ int32 heroSet = readScriptFlagValue();
+ if (!heroId) {
+ _vm->_mainHero->loadAnimSet(heroSet);
+ } else if (heroId == 1) {
+ _vm->_secondHero->loadAnimSet(heroSet);
+ }
+ debugInterpreter("O_CHANGEHEROSET hero %d, heroSet %d", heroId, heroSet);
+}
+
+// Not used in script
+void Interpreter::O_ADDSTRING() {
+ error("O_ADDSTRING");
+}
+
+void Interpreter::O_SUBSTRING() {
+ int32 value = readScriptFlagValue();
+ _string -= value;
+ debugInterpreter("O_SUBSTRING value %d", value);
+}
+
+int Interpreter::checkSeq(byte *string) {
+ int freeHSlotIncrease = 0;
+ byte c;
+ while ((c = string[0]) != 0xFF) {
+ string++;
+ if (c < 0xF0) {
+ freeHSlotIncrease++;
+ while ((c = string[0])) {
+ string++;
+ }
+ string++;
+ } else if (c != 0xFE) {
+ string++;
+ }
+ }
+ return freeHSlotIncrease;
+}
+
+void Interpreter::O_INITDIALOG() {
+ if (_string[0] == 255) {
+ byte *stringCurrOff = _string;
+ byte *string = _string;
+ stringCurrOff++;
+ int32 adressOfFirstSequence = (int)READ_LE_UINT16(stringCurrOff);
+ stringCurrOff += 2;
+ _string = string + adressOfFirstSequence;
+
+ for (int i = 0; i < 32; i++) {
+ _vm->_dialogBoxAddr[i] = 0;
+ _vm->_dialogOptAddr[i] = 0;
+ }
+
+ for (int i = 0; i < 4 * 32; i++) {
+ _vm->_dialogOptLines[i] = 0;
+ }
+
+ int16 off;
+ byte *line = nullptr;
+
+ int dialogBox = 0;
+ while ((off = (int)READ_LE_UINT16(stringCurrOff)) != -1) {
+ stringCurrOff += 2;
+ if (off) {
+ line = string + off;
+ }
+ _vm->_dialogBoxAddr[dialogBox] = line;
+ dialogBox++;
+ }
+ stringCurrOff += 2;
+
+ int dialogOpt = 0;
+ while ((off = (int)READ_LE_UINT16(stringCurrOff)) != -1) {
+ stringCurrOff += 2;
+ if (off) {
+ line = string + off;
+ }
+ _vm->_dialogOptAddr[dialogOpt] = line;
+ dialogOpt++;
+ }
+
+ _flags->setFlagValue(Flags::VOICE_A_LINE, 0);
+ _flags->setFlagValue(Flags::VOICE_B_LINE, 0); // bx in original?
+
+ int freeHSlot = 0;
+ for (int i = 31; i >= 0; i--) {
+ if (_vm->_dialogOptAddr[i] != 0) {
+ i++;
+ freeHSlot = i;
+ _flags->setFlagValue(Flags::VOICE_H_LINE, i);
+ break;
+ }
+ }
+
+ freeHSlot += checkSeq(_string);
+
+ for (int i = 0; i < 32; i++) {
+ _vm->_dialogOptLines[i * 4] = freeHSlot;
+ _vm->_dialogOptLines[i * 4 + 1] = freeHSlot;
+ _vm->_dialogOptLines[i * 4 + 2] = freeHSlot;
+ if (_vm->_dialogOptAddr[i]) {
+ freeHSlot += checkSeq(_vm->_dialogOptAddr[i]);
+ }
+ }
+ }
+ debugInterpreter("O_INITDIALOG");
+}
+
+void Interpreter::O_ENABLEDIALOGOPT() {
+ int32 opt = readScriptFlagValue();
+ int dialogDataValue = (int)READ_LE_UINT32(_vm->_dialogData);
+ dialogDataValue &= ~(1u << opt);
+ WRITE_LE_UINT32(_vm->_dialogData, dialogDataValue);
+ debugInterpreter("O_ENABLEDIALOGOPT opt %d", opt);
+}
+
+void Interpreter::O_DISABLEDIALOGOPT() {
+ int32 opt = readScriptFlagValue();
+ int dialogDataValue = (int)READ_LE_UINT32(_vm->_dialogData);
+ dialogDataValue |= (1u << opt);
+ WRITE_LE_UINT32(_vm->_dialogData, dialogDataValue);
+ debugInterpreter("O_DISABLEDIALOGOPT opt %d", opt);
+}
+
+void Interpreter::O_SHOWDIALOGBOX() {
+ int32 box = readScriptFlagValue();
+ uint32 currInstr = _currentInstruction;
+ _vm->createDialogBox(box);
+ _flags->setFlagValue(Flags::DIALINES, _vm->_dialogLines);
+ if (_vm->_dialogLines) {
+ _vm->changeCursor(1);
+ _vm->dialogRun();
+ _vm->changeCursor(0);
+ }
+ _currentInstruction = currInstr;
+ debugInterpreter("O_SHOWDIALOGBOX box %d", box);
+}
+
+void Interpreter::O_STOPSAMPLE() {
+ int32 slot = readScriptFlagValue();
+ _vm->stopSample(slot);
+ debugInterpreter("O_STOPSAMPLE slot %d", slot);
+}
+
+void Interpreter::O_BACKANIMRANGE() {
+ int32 slotId = readScriptFlagValue();
+ uint16 animId = readScript16();
+ int32 low = readScriptFlagValue();
+ int32 high = readScriptFlagValue();
+ if (animId != 0xFFFF) {
+ if (animId & InterpreterFlags::kFlagMask) {
+ animId = _flags->getFlagValue((Flags::Id)animId);
+ }
+ }
+ _result = 1;
+ if (!_vm->_backAnimList[slotId].backAnims.empty()) {
+ int currAnim = _vm->_backAnimList[slotId]._seq._currRelative;
+ if (_vm->_backAnimList[slotId].backAnims[currAnim]._animData != nullptr) {
+ if (animId == 0xFFFF || _vm->_backAnimList[slotId]._seq._current == animId) {
+ Anim &backAnim = _vm->_backAnimList[slotId].backAnims[currAnim];
+ if (!backAnim._state) {
+ if (backAnim._frame >= low) {
+ if (backAnim._frame <= high) {
+ _result = 0;
+ }
+ }
+ }
+ }
+ }
+ }
+ debugInterpreter("O_BACKANIMRANGE slotId %d, animId %d, low %d, high %d, _result %d", slotId, animId, low, high, _result);
+}
+
+void Interpreter::O_CLEARPATH() {
+ for (uint i = 0; i < _vm->kPathBitmapLen; i++) {
+ _vm->_roomPathBitmap[i] = 255;
+ }
+ debugInterpreter("O_CLEARPATH");
+}
+
+void Interpreter::O_SETPATH() {
+ _vm->loadPath("path");
+ debugInterpreter("O_SETPATH");
+}
+
+void Interpreter::O_GETHEROX() {
+ int32 heroId = readScriptFlagValue();
+ Flags::Id flagId = readScriptFlagId();
+ if (!heroId) {
+ _flags->setFlagValue(flagId, _vm->_mainHero->_middleX);
+ } else if (heroId == 1) {
+ _flags->setFlagValue(flagId, _vm->_secondHero->_middleX);
+ }
+ debugInterpreter("O_GETHEROX heroId %d, flagId %d", heroId, flagId);
+}
+
+void Interpreter::O_GETHEROY() {
+ int32 heroId = readScriptFlagValue();
+ Flags::Id flagId = readScriptFlagId();
+ if (!heroId) {
+ _flags->setFlagValue(flagId, _vm->_mainHero->_middleY);
+ } else if (heroId == 1) {
+ _flags->setFlagValue(flagId, _vm->_secondHero->_middleY);
+ }
+ debugInterpreter("O_GETHEROY heroId %d, flagId %d", heroId, flagId);
+}
+
+void Interpreter::O_GETHEROD() {
+ int32 heroId = readScriptFlagValue();
+ Flags::Id flagId = readScriptFlagId();
+ if (!heroId) {
+ _flags->setFlagValue(flagId, _vm->_mainHero->_lastDirection);
+ } else if (heroId == 1) {
+ _flags->setFlagValue(flagId, _vm->_secondHero->_lastDirection);
+ }
+ debugInterpreter("O_GETHEROD heroId %d, flagId %d", heroId, flagId);
+}
+
+void Interpreter::O_PUSHSTRING() {
+ _stringStack.string = _string;
+ _stringStack.dialogData = _vm->_dialogData;
+ _stringStack.currentString = _currentString;
+ debugInterpreter("O_PUSHSTRING");
+}
+
+void Interpreter::O_POPSTRING() {
+ _string = _stringStack.string;
+ _vm->_dialogData = _stringStack.dialogData;
+ _currentString = _stringStack.currentString;
+ debugInterpreter("O_POPSTRING");
+}
+
+void Interpreter::O_SETFGCODE() {
+ int32 offset = readScript32();
+ _fgOpcodePC = _currentInstruction + offset - 4;
+ debugInterpreter("O_SETFGCODE next %08x, offset %08x", _fgOpcodePC, offset);
+}
+
+void Interpreter::O_STOPHERO() {
+ int32 heroId = readScriptFlagValue();
+ if (!heroId) {
+ _vm->_mainHero->freeOldMove();
+ } else if (heroId == 1) {
+ _vm->_secondHero->freeOldMove();
+ }
+ debugInterpreter("O_STOPHERO heroId %d", heroId);
+}
+
+void Interpreter::O_ANIMUPDATEOFF() {
+ int32 slotId = readScriptFlagValue();
+ _vm->_normAnimList[slotId]._state = 1;
+ debugInterpreter("O_ANIMUPDATEOFF slotId %d", slotId);
+}
+
+void Interpreter::O_ANIMUPDATEON() {
+ int32 slotId = readScriptFlagValue();
+ _vm->_normAnimList[slotId]._state = 0;
+ debugInterpreter("O_ANIMUPDATEON slotId %d", slotId);
+}
+
+void Interpreter::O_FREECURSOR() {
+ _vm->changeCursor(0);
+ _vm->_currentPointerNumber = 1;
+ // free memory here?
+ debugInterpreter("O_FREECURSOR");
+}
+
+void Interpreter::O_ADDINVQUIET() {
+ int32 hero = readScriptFlagValue();
+ int32 item = readScriptFlagValue();
+ _vm->addInv(hero, item, true);
+ debugInterpreter("O_ADDINVQUIET hero %d, item %d", hero, item);
+}
+
+void Interpreter::O_RUNHERO() {
+ int32 heroId = readScriptFlagValue();
+ int32 x = readScriptFlagValue();
+ int32 y = readScriptFlagValue();
+ int32 dir = readScriptFlagValue();
+ _vm->moveRunHero(heroId, x, y, dir, true);
+ debugInterpreter("O_RUNHERO heroId %d, x %d, y %d, dir %d", heroId, x, y, dir);
+}
+
+void Interpreter::O_SETBACKANIMDATA() {
+ uint16 animNumber = readScript16();
+ uint16 animDataOffset = readScript16();
+ Flags::Id flagId = readScriptFlagId();
+ uint16 value = _flags->getFlagValue((Flags::Id)(flagId));
+ int currAnim = _vm->_backAnimList[animNumber]._seq._currRelative;
+ _vm->_backAnimList[animNumber].backAnims[currAnim].setAnimData((Anim::AnimOffsets)(animDataOffset), value);
+ debugInterpreter("O_SETBACKANIMDATA flag %04X (%s), animNumber %d, animDataOffset %d, value %d", flagId, Flags::getFlagName(flagId), animNumber, animDataOffset, value);
+}
+
+void Interpreter::O_VIEWFLC() {
+ int32 animNr = readScriptFlagValue();
+ _vm->_flcFrameSurface = nullptr;
+ _vm->loadAnim(animNr, false);
+ debugInterpreter("O_VIEWFLC animNr %d", animNr);
+}
+
+void Interpreter::O_CHECKFLCFRAME() {
+ int32 frameNr = readScriptFlagValue();
+ debugInterpreter("O_CHECKFLCFRAME frame number %d", frameNr);
+ if (_vm->_flicPlayer.getCurFrame() != frameNr) {
+ _currentInstruction -= 4;
+ _opcodeNF = 1;
+ }
+}
+
+void Interpreter::O_CHECKFLCEND() {
+ const Video::FlicDecoder &flicPlayer = _vm->_flicPlayer;
+ debugInterpreter("O_CHECKFLCEND frameCount %d, currentFrame %d", flicPlayer.getFrameCount(), flicPlayer.getCurFrame());
+ if (flicPlayer.getFrameCount() - flicPlayer.getCurFrame() > 1) {
+ _currentInstruction -= 2;
+ _opcodeNF = 1;
+ }
+}
+
+void Interpreter::O_FREEFLC() {
+ _vm->_flcFrameSurface = nullptr;
+ debugInterpreter("O_FREEFLC");
+}
+
+void Interpreter::O_TALKHEROSTOP() {
+ int32 heroId = readScriptFlagValue();
+ if (!heroId) {
+ _vm->_mainHero->_state = Hero::kHeroStateStay;
+ } else if (heroId == 1) {
+ _vm->_secondHero->_state = Hero::kHeroStateStay;
+ }
+ debugInterpreter("O_TALKHEROSTOP %d", heroId);
+}
+
+void Interpreter::O_HEROCOLOR() {
+ int32 heroId = readScriptFlagValue();
+ int32 color = readScriptFlagValue();
+ if (!heroId) {
+ _vm->_mainHero->_color = color;
+ } else if (heroId == 1) {
+ _vm->_secondHero->_color = color;
+ }
+ debugInterpreter("O_HEROCOLOR heroId %d, color %d", heroId, color);
+}
+
+void Interpreter::O_GRABMAPA() {
+ _vm->grabMap();
+ debugInterpreter("O_GRABMAPA");
+}
+
+void Interpreter::O_ENABLENAK() {
+ int32 nakId = readScriptFlagValue();
+ _vm->_maskList[nakId]._flags = 0;
+ debugInterpreter("O_ENABLENAK nakId %d", nakId);
+}
+
+void Interpreter::O_DISABLENAK() {
+ int32 nakId = readScriptFlagValue();
+ _vm->_maskList[nakId]._flags = 1;
+ debugInterpreter("O_DISABLENAK nakId %d", nakId);
+}
+
+void Interpreter::O_GETMOBNAME() {
+ int32 modId = readScriptFlagValue();
+ _string = (byte *)_vm->_mobList[modId]._name.c_str();
+ debugInterpreter("O_GETMOBNAME modId %d", modId);
+}
+
+void Interpreter::O_SWAPINVENTORY() {
+ int32 hero = readScriptFlagValue();
+ _vm->swapInv(hero);
+ debugInterpreter("O_SWAPINVENTORY hero %d", hero);
+}
+
+void Interpreter::O_CLEARINVENTORY() {
+ int32 hero = readScriptFlagValue();
+ _vm->clearInv(hero);
+ debugInterpreter("O_CLEARINVENTORY hero %d", hero);
+}
+
+void Interpreter::O_SKIPTEXT() {
+ increaseString();
+ debugInterpreter("O_SKIPTEXT");
+}
+
+void Interpreter::O_SETVOICEH() {
+ int32 slot = readScriptFlagValue();
+ static const uint32 VOICE_H_SLOT = 28;
+ uint16 voiceLineH = _flags->getFlagValue(Flags::VOICE_H_LINE);
+ _vm->setVoice(slot, VOICE_H_SLOT, voiceLineH);
+}
+
+void Interpreter::O_SETVOICEA() {
+ int32 slot = readScriptFlagValue();
+ static const uint32 VOICE_A_SLOT = 29;
+ uint16 voiceLineH = _flags->getFlagValue(Flags::VOICE_H_LINE);
+ _vm->setVoice(slot, VOICE_A_SLOT, voiceLineH);
+}
+
+void Interpreter::O_SETVOICEB() {
+ int32 slot = readScriptFlagValue();
+ static const uint32 VOICE_B_SLOT = 30;
+ uint16 voiceLineH = _flags->getFlagValue(Flags::VOICE_H_LINE);
+ _vm->setVoice(slot, VOICE_B_SLOT, voiceLineH);
+}
+
+void Interpreter::O_SETVOICEC() {
+ int32 slot = readScriptFlagValue();
+ static const uint32 VOICE_C_SLOT = 31;
+ uint16 voiceLineH = _flags->getFlagValue(Flags::VOICE_H_LINE);
+ _vm->setVoice(slot, VOICE_C_SLOT, voiceLineH);
+}
+
+void Interpreter::O_SETVOICED() {
+ int32 slot = readScriptFlagValue();
+ static const uint32 VOICE_D_SLOT = 32;
+ uint16 voiceLineH = _flags->getFlagValue(Flags::VOICE_H_LINE);
+ _vm->setVoice(slot, VOICE_D_SLOT, voiceLineH);
+}
+
+void Interpreter::O_VIEWFLCLOOP() {
+ int32 animId = readScriptFlagValue();
+ _vm->loadAnim(animId, true);
+ debugInterpreter("O_VIEWFLCLOOP animId %d", animId);
+}
+
+// Not used in script
+void Interpreter::O_FLCSPEED() {
+ int32 speed = readScriptFlagValue();
+ error("O_FLCSPEED speed %d", speed);
+}
+
+void Interpreter::O_OPENINVENTORY() {
+ _vm->_showInventoryFlag = true;
+ _opcodeNF = 1;
+ debugInterpreter("O_OPENINVENTORY");
+}
+
+void Interpreter::O_KRZYWA() {
+ _vm->makeCurve();
+ debugInterpreter("O_KRZYWA");
+}
+
+void Interpreter::O_GETKRZYWA() {
+ _vm->getCurve();
+ debugInterpreter("O_GETKRZYWA");
+}
+
+void Interpreter::O_GETMOB() {
+ Flags::Id flagId = readScriptFlagId();
+ int32 posX = readScriptFlagValue();
+ int32 posY = readScriptFlagValue();
+ int mobNumber = _vm->getMob(_vm->_mobList, true, posX, posY);
+ _flags->setFlagValue(flagId, mobNumber + 1);
+ debugInterpreter("O_GETMOB flagId %d, posX %d, posY %d", flagId, posX, posY);
+}
+
+// Not used in game
+void Interpreter::O_INPUTLINE() {
+ error("O_INPUTLINE");
+}
+
+// Not used in script
+void Interpreter::O_BREAK_POINT() {
+ error("O_BREAK_POINT");
+}
+
+Interpreter::OpcodeFunc Interpreter::_opcodes[kNumOpcodes] = {
+ &Interpreter::O_WAITFOREVER,
+ &Interpreter::O_BLACKPALETTE,
+ &Interpreter::O_SETUPPALETTE,
+ &Interpreter::O_INITROOM,
+ &Interpreter::O_SETSAMPLE,
+ &Interpreter::O_FREESAMPLE,
+ &Interpreter::O_PLAYSAMPLE,
+ &Interpreter::O_PUTOBJECT,
+ &Interpreter::O_REMOBJECT,
+ &Interpreter::O_SHOWANIM,
+ &Interpreter::O_CHECKANIMEND,
+ &Interpreter::O_FREEANIM,
+ &Interpreter::O_CHECKANIMFRAME,
+ &Interpreter::O_PUTBACKANIM,
+ &Interpreter::O_REMBACKANIM,
+ &Interpreter::O_CHECKBACKANIMFRAME,
+ &Interpreter::O_FREEALLSAMPLES,
+ &Interpreter::O_SETMUSIC,
+ &Interpreter::O_STOPMUSIC,
+ &Interpreter::O__WAIT,
+ &Interpreter::O_UPDATEOFF,
+ &Interpreter::O_UPDATEON,
+ &Interpreter::O_UPDATE ,
+ &Interpreter::O_CLS,
+ &Interpreter::O__CALL,
+ &Interpreter::O_RETURN,
+ &Interpreter::O_GO,
+ &Interpreter::O_BACKANIMUPDATEOFF,
+ &Interpreter::O_BACKANIMUPDATEON,
+ &Interpreter::O_CHANGECURSOR,
+ &Interpreter::O_CHANGEANIMTYPE,
+ &Interpreter::O__SETFLAG,
+ &Interpreter::O_COMPARE,
+ &Interpreter::O_JUMPZ,
+ &Interpreter::O_JUMPNZ,
+ &Interpreter::O_EXIT,
+ &Interpreter::O_ADDFLAG,
+ &Interpreter::O_TALKANIM,
+ &Interpreter::O_SUBFLAG,
+ &Interpreter::O_SETSTRING,
+ &Interpreter::O_ANDFLAG,
+ &Interpreter::O_GETMOBDATA,
+ &Interpreter::O_ORFLAG,
+ &Interpreter::O_SETMOBDATA,
+ &Interpreter::O_XORFLAG,
+ &Interpreter::O_GETMOBTEXT,
+ &Interpreter::O_MOVEHERO,
+ &Interpreter::O_WALKHERO,
+ &Interpreter::O_SETHERO,
+ &Interpreter::O_HEROOFF,
+ &Interpreter::O_HEROON,
+ &Interpreter::O_CLSTEXT,
+ &Interpreter::O_CALLTABLE,
+ &Interpreter::O_CHANGEMOB,
+ &Interpreter::O_ADDINV,
+ &Interpreter::O_REMINV,
+ &Interpreter::O_REPINV,
+ &Interpreter::O_OBSOLETE_GETACTION,
+ &Interpreter::O_ADDWALKAREA,
+ &Interpreter::O_REMWALKAREA,
+ &Interpreter::O_RESTOREWALKAREA,
+ &Interpreter::O_WAITFRAME,
+ &Interpreter::O_SETFRAME,
+ &Interpreter::O_RUNACTION,
+ &Interpreter::O_COMPAREHI,
+ &Interpreter::O_COMPARELO,
+ &Interpreter::O_PRELOADSET,
+ &Interpreter::O_FREEPRELOAD,
+ &Interpreter::O_CHECKINV,
+ &Interpreter::O_TALKHERO,
+ &Interpreter::O_WAITTEXT,
+ &Interpreter::O_SETHEROANIM,
+ &Interpreter::O_WAITHEROANIM,
+ &Interpreter::O_GETHERODATA,
+ &Interpreter::O_GETMOUSEBUTTON,
+ &Interpreter::O_CHANGEFRAMES,
+ &Interpreter::O_CHANGEBACKFRAMES,
+ &Interpreter::O_GETBACKANIMDATA,
+ &Interpreter::O_GETANIMDATA,
+ &Interpreter::O_SETBGCODE,
+ &Interpreter::O_SETBACKFRAME,
+ &Interpreter::O_GETRND,
+ &Interpreter::O_TALKBACKANIM,
+ &Interpreter::O_LOADPATH,
+ &Interpreter::O_GETCHAR,
+ &Interpreter::O_SETDFLAG,
+ &Interpreter::O_CALLDFLAG,
+ &Interpreter::O_PRINTAT,
+ &Interpreter::O_ZOOMIN,
+ &Interpreter::O_ZOOMOUT,
+ &Interpreter::O_SETSTRINGOFFSET,
+ &Interpreter::O_GETOBJDATA,
+ &Interpreter::O_SETOBJDATA,
+ &Interpreter::O_SWAPOBJECTS,
+ &Interpreter::O_CHANGEHEROSET,
+ &Interpreter::O_ADDSTRING,
+ &Interpreter::O_SUBSTRING,
+ &Interpreter::O_INITDIALOG,
+ &Interpreter::O_ENABLEDIALOGOPT,
+ &Interpreter::O_DISABLEDIALOGOPT,
+ &Interpreter::O_SHOWDIALOGBOX,
+ &Interpreter::O_STOPSAMPLE,
+ &Interpreter::O_BACKANIMRANGE,
+ &Interpreter::O_CLEARPATH,
+ &Interpreter::O_SETPATH,
+ &Interpreter::O_GETHEROX,
+ &Interpreter::O_GETHEROY,
+ &Interpreter::O_GETHEROD,
+ &Interpreter::O_PUSHSTRING,
+ &Interpreter::O_POPSTRING,
+ &Interpreter::O_SETFGCODE,
+ &Interpreter::O_STOPHERO,
+ &Interpreter::O_ANIMUPDATEOFF,
+ &Interpreter::O_ANIMUPDATEON,
+ &Interpreter::O_FREECURSOR,
+ &Interpreter::O_ADDINVQUIET,
+ &Interpreter::O_RUNHERO,
+ &Interpreter::O_SETBACKANIMDATA,
+ &Interpreter::O_VIEWFLC,
+ &Interpreter::O_CHECKFLCFRAME,
+ &Interpreter::O_CHECKFLCEND,
+ &Interpreter::O_FREEFLC,
+ &Interpreter::O_TALKHEROSTOP,
+ &Interpreter::O_HEROCOLOR,
+ &Interpreter::O_GRABMAPA,
+ &Interpreter::O_ENABLENAK,
+ &Interpreter::O_DISABLENAK,
+ &Interpreter::O_GETMOBNAME,
+ &Interpreter::O_SWAPINVENTORY,
+ &Interpreter::O_CLEARINVENTORY,
+ &Interpreter::O_SKIPTEXT,
+ &Interpreter::O_SETVOICEH,
+ &Interpreter::O_SETVOICEA,
+ &Interpreter::O_SETVOICEB,
+ &Interpreter::O_SETVOICEC,
+ &Interpreter::O_VIEWFLCLOOP,
+ &Interpreter::O_FLCSPEED,
+ &Interpreter::O_OPENINVENTORY,
+ &Interpreter::O_KRZYWA,
+ &Interpreter::O_GETKRZYWA,
+ &Interpreter::O_GETMOB,
+ &Interpreter::O_INPUTLINE,
+ &Interpreter::O_SETVOICED,
+ &Interpreter::O_BREAK_POINT,
+};
+
+} // End of namespace Prince
diff --git a/engines/prince/script.h b/engines/prince/script.h
new file mode 100644
index 0000000000..fe79cf5f96
--- /dev/null
+++ b/engines/prince/script.h
@@ -0,0 +1,398 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public 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 PRINCE_SCRIPT_H
+#define PRINCE_SCRIPT_H
+
+#include "common/random.h"
+#include "common/endian.h"
+#include "common/array.h"
+#include "common/stream.h"
+
+#include "prince/flags.h"
+
+namespace Prince {
+
+class PrinceEngine;
+class Animation;
+class Object;
+struct Anim;
+struct BackgroundAnim;
+struct Mask;
+
+class Room {
+public:
+ Room();
+ int _mobs; // mob flag offset
+ int _backAnim; // offset to array of animation numbers
+ int _obj; // offset to array of object numbers
+ int _nak; // offset to array of masks
+ int _itemUse;
+ int _itemGive;
+ int _walkTo; // offset to array of WALKTO events or 0
+ int _examine; // offset to array of EXAMINE events or 0
+ int _pickup;
+ int _use;
+ int _pushOpen;
+ int _pullClose;
+ int _talk;
+ int _give;
+
+ bool loadStream(Common::SeekableReadStream &stream);
+ bool loadRoom(byte *roomData);
+ int getOptionOffset(int option);
+
+private:
+
+ typedef void (Room::*LoadingStep)(Common::SeekableReadStream &stream);
+
+ void nextLoadStep(Common::SeekableReadStream &stream, LoadingStep step);
+
+ void loadMobs(Common::SeekableReadStream &stream);
+ void loadBackAnim(Common::SeekableReadStream &stream);
+ void loadObj(Common::SeekableReadStream &stream);
+ void loadNak(Common::SeekableReadStream &stream);
+ void loadItemUse(Common::SeekableReadStream &stream);
+ void loadItemGive(Common::SeekableReadStream &stream);
+ void loadWalkTo(Common::SeekableReadStream &stream);
+ void loadExamine(Common::SeekableReadStream &stream);
+ void loadPickup(Common::SeekableReadStream &stream);
+ void loadUse(Common::SeekableReadStream &stream);
+ void loadPushOpen(Common::SeekableReadStream &stream);
+ void loadPullClose(Common::SeekableReadStream &stream);
+ void loadTalk(Common::SeekableReadStream &stream);
+ void loadGive(Common::SeekableReadStream &stream);
+};
+
+
+class Script {
+public:
+ static const int16 kMaxRooms = 60;
+
+ Script(PrinceEngine *vm);
+ ~Script();
+
+ struct ScriptInfo {
+ int rooms;
+ int startGame;
+ int restoreGame;
+ int stdExamine;
+ int stdPickup;
+ int stdUse;
+ int stdOpen;
+ int stdClose;
+ int stdTalk;
+ int stdGive;
+ int usdCode;
+ int invObjExam;
+ int invObjUse;
+ int invObjUU;
+ int stdUseItem;
+ int lightSources;
+ int specRout;
+ int invObjGive;
+ int stdGiveItem;
+ int goTester;
+ };
+
+ ScriptInfo _scriptInfo;
+
+ bool loadStream(Common::SeekableReadStream &stream);
+
+ uint16 readScript16(uint32 address);
+ uint32 readScript32(uint32 address);
+
+ uint32 getStartGameOffset();
+ uint32 getLocationInitScript(int initRoomTableOffset, int roomNr);
+ int16 getLightX(int locationNr);
+ int16 getLightY(int locationNr);
+ int32 getShadowScale(int locationNr);
+ uint8 *getRoomOffset(int locationNr);
+ int32 getOptionStandardOffset(int option);
+ uint8 *getHeroAnimName(int offset);
+
+ void installBackAnims(Common::Array<BackgroundAnim> &backAnimList, int roomBackAnimOffset);
+ void installSingleBackAnim(Common::Array<BackgroundAnim> &backAnimList, int slot, int roomBackAnimOffset);
+ void installObjects(int offset);
+ bool loadAllMasks(Common::Array<Mask> &maskList, int offset);
+
+ int scanMobEvents(int mobMask, int dataEventOffset);
+ int scanMobEventsWithItem(int mobMask, int dataEventOffset, int itemMask);
+
+ byte getMobVisible(int roomMobOffset, uint16 mob);
+ void setMobVisible(int roomMobOffset, uint16 mob, byte value);
+
+ uint32 getBackAnimId(int roomBackAnimOffset, int slot);
+ void setBackAnimId(int roomBackAnimOffset, int slot, int animId);
+
+ byte getObjId(int roomObjOffset, int slot);
+ void setObjId(int roomObjOffset, int slot, byte objectId);
+
+ const char *getString(uint32 offset) {
+ return (const char *)(&_data[offset]);
+ }
+
+private:
+ PrinceEngine *_vm;
+ uint8 *_data;
+ uint32 _dataSize;
+ Common::Array<Room> _roomList;
+};
+
+class InterpreterFlags {
+public:
+ InterpreterFlags();
+
+ void setFlagValue(Flags::Id flag, int32 value);
+ int32 getFlagValue(Flags::Id flag);
+
+ void resetAllFlags();
+
+ static const uint16 kFlagMask = 0x8000;
+ static const uint16 kMaxFlags = 2000;
+private:
+ int32 _flags[kMaxFlags];
+};
+
+class Interpreter {
+public:
+ Interpreter(PrinceEngine *vm, Script *script, InterpreterFlags *flags);
+
+ void stopBg() { _bgOpcodePC = 0; }
+
+ void stepBg();
+ void stepFg();
+ void storeNewPC(int opcodePC);
+ int getLastOPCode();
+ int getFgOpcodePC();
+
+ void setBgOpcodePC(uint32 value);
+ void setFgOpcodePC(uint32 value);
+
+ uint32 getCurrentString();
+ void setCurrentString(uint32 value);
+
+ byte *getString();
+ void setString(byte *newString);
+ void increaseString();
+
+ void setResult(byte value);
+
+private:
+ PrinceEngine *_vm;
+ Script *_script;
+ InterpreterFlags *_flags;
+
+ uint32 _currentInstruction;
+
+ uint32 _bgOpcodePC;
+ uint32 _fgOpcodePC;
+
+ uint16 _lastOpcode;
+ uint32 _lastInstruction;
+ byte _result;
+
+ bool _opcodeNF; // break interpreter loop
+ bool _opcodeEnd; // end of a game flag
+
+ static const uint32 _STACK_SIZE = 500;
+ uint32 _stack[_STACK_SIZE];
+ struct stringStack {
+ byte *string;
+ byte *dialogData;
+ uint32 currentString;
+ } _stringStack;
+ uint8 _stacktop;
+ uint32 _waitFlag;
+
+ byte *_string;
+ uint32 _currentString;
+ const char *_mode;
+
+ // Helper functions
+ uint32 step(uint32 opcodePC);
+ uint16 readScript16();
+ uint32 readScript32();
+ int32 readScriptFlagValue();
+ Flags::Id readScriptFlagId();
+ int checkSeq(byte *string);
+
+ void debugInterpreter(const char *s, ...);
+
+ typedef void (Interpreter::*OpcodeFunc)();
+ static OpcodeFunc _opcodes[];
+
+ static const uint kGiveLetterScriptFix = 79002;
+ static const uint kSecondBirdAnimationScriptFix = 45658;
+
+ // Keep opcode handlers names as they are in original code
+ // making it easier to switch back and forth
+ void O_WAITFOREVER();
+ void O_BLACKPALETTE();
+ void O_SETUPPALETTE();
+ void O_INITROOM();
+ void O_SETSAMPLE();
+ void O_FREESAMPLE();
+ void O_PLAYSAMPLE();
+ void O_PUTOBJECT();
+ void O_REMOBJECT();
+ void O_SHOWANIM();
+ void O_CHECKANIMEND();
+ void O_FREEANIM();
+ void O_CHECKANIMFRAME();
+ void O_PUTBACKANIM();
+ void O_REMBACKANIM();
+ void O_CHECKBACKANIMFRAME();
+ void O_FREEALLSAMPLES();
+ void O_SETMUSIC();
+ void O_STOPMUSIC();
+ void O__WAIT();
+ void O_UPDATEOFF();
+ void O_UPDATEON();
+ void O_UPDATE ();
+ void O_CLS();
+ void O__CALL();
+ void O_RETURN();
+ void O_GO();
+ void O_BACKANIMUPDATEOFF();
+ void O_BACKANIMUPDATEON();
+ void O_CHANGECURSOR();
+ void O_CHANGEANIMTYPE();
+ void O__SETFLAG();
+ void O_COMPARE();
+ void O_JUMPZ();
+ void O_JUMPNZ();
+ void O_EXIT();
+ void O_ADDFLAG();
+ void O_TALKANIM();
+ void O_SUBFLAG();
+ void O_SETSTRING();
+ void O_ANDFLAG();
+ void O_GETMOBDATA();
+ void O_ORFLAG();
+ void O_SETMOBDATA();
+ void O_XORFLAG();
+ void O_GETMOBTEXT();
+ void O_MOVEHERO();
+ void O_WALKHERO();
+ void O_SETHERO();
+ void O_HEROOFF();
+ void O_HEROON();
+ void O_CLSTEXT();
+ void O_CALLTABLE();
+ void O_CHANGEMOB();
+ void O_ADDINV();
+ void O_REMINV();
+ void O_REPINV();
+ void O_OBSOLETE_GETACTION();
+ void O_ADDWALKAREA();
+ void O_REMWALKAREA();
+ void O_RESTOREWALKAREA();
+ void O_WAITFRAME();
+ void O_SETFRAME();
+ void O_RUNACTION();
+ void O_COMPAREHI();
+ void O_COMPARELO();
+ void O_PRELOADSET();
+ void O_FREEPRELOAD();
+ void O_CHECKINV();
+ void O_TALKHERO();
+ void O_WAITTEXT();
+ void O_SETHEROANIM();
+ void O_WAITHEROANIM();
+ void O_GETHERODATA();
+ void O_GETMOUSEBUTTON();
+ void O_CHANGEFRAMES();
+ void O_CHANGEBACKFRAMES();
+ void O_GETBACKANIMDATA();
+ void O_GETANIMDATA();
+ void O_SETBGCODE();
+ void O_SETBACKFRAME();
+ void O_GETRND();
+ void O_TALKBACKANIM();
+ void O_LOADPATH();
+ void O_GETCHAR();
+ void O_SETDFLAG();
+ void O_CALLDFLAG();
+ void O_PRINTAT();
+ void O_ZOOMIN();
+ void O_ZOOMOUT();
+ void O_SETSTRINGOFFSET();
+ void O_GETOBJDATA();
+ void O_SETOBJDATA();
+ void O_SWAPOBJECTS();
+ void O_CHANGEHEROSET();
+ void O_ADDSTRING();
+ void O_SUBSTRING();
+ void O_INITDIALOG();
+ void O_ENABLEDIALOGOPT();
+ void O_DISABLEDIALOGOPT();
+ void O_SHOWDIALOGBOX();
+ void O_STOPSAMPLE();
+ void O_BACKANIMRANGE();
+ void O_CLEARPATH();
+ void O_SETPATH();
+ void O_GETHEROX();
+ void O_GETHEROY();
+ void O_GETHEROD();
+ void O_PUSHSTRING();
+ void O_POPSTRING();
+ void O_SETFGCODE();
+ void O_STOPHERO();
+ void O_ANIMUPDATEOFF();
+ void O_ANIMUPDATEON();
+ void O_FREECURSOR();
+ void O_ADDINVQUIET();
+ void O_RUNHERO();
+ void O_SETBACKANIMDATA();
+ void O_VIEWFLC();
+ void O_CHECKFLCFRAME();
+ void O_CHECKFLCEND();
+ void O_FREEFLC();
+ void O_TALKHEROSTOP();
+ void O_HEROCOLOR();
+ void O_GRABMAPA();
+ void O_ENABLENAK();
+ void O_DISABLENAK();
+ void O_GETMOBNAME();
+ void O_SWAPINVENTORY();
+ void O_CLEARINVENTORY();
+ void O_SKIPTEXT();
+ void O_SETVOICEH();
+ void O_SETVOICEA();
+ void O_SETVOICEB();
+ void O_SETVOICEC();
+ void O_VIEWFLCLOOP();
+ void O_FLCSPEED();
+ void O_OPENINVENTORY();
+ void O_KRZYWA();
+ void O_GETKRZYWA();
+ void O_GETMOB();
+ void O_INPUTLINE();
+ void O_SETVOICED();
+ void O_BREAK_POINT();
+
+};
+
+} // End of namespace Prince
+
+#endif
diff --git a/engines/prince/sound.cpp b/engines/prince/sound.cpp
new file mode 100644
index 0000000000..032297ee43
--- /dev/null
+++ b/engines/prince/sound.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 "prince/prince.h"
+#include "prince/sound.h"
+#include "prince/musNum.h"
+
+#include "common/config-manager.h"
+#include "common/memstream.h"
+#include "common/archive.h"
+#include "audio/decoders/raw.h"
+#include "audio/audiostream.h"
+
+namespace Prince {
+
+const char *MusicPlayer::_musTable[] = {
+ "",
+ "Battlfld.mid",
+ "Cave.mid",
+ "Cemetery.mid",
+ "Credits.mid",
+ "Fjord.mid",
+ "Guitar.mid",
+ "Hell.mid",
+ "Jingle.mid",
+ "Main.mid",
+ "Night.mid",
+ "Reality.mid",
+ "Sunlord.mid",
+ "Tavern.mid",
+ "Temple.mid",
+ "Boruta.mid",
+ "Intro.mid"
+};
+
+const uint8 MusicPlayer::_musRoomTable[] = {
+ 0,
+ ROOM01MUS,
+ ROOM02MUS,
+ ROOM03MUS,
+ ROOM04MUS,
+ ROOM05MUS,
+ ROOM06MUS,
+ ROOM07MUS,
+ ROOM08MUS,
+ ROOM09MUS,
+ ROOM10MUS,
+ ROOM11MUS,
+ ROOM12MUS,
+ ROOM13MUS,
+ ROOM14MUS,
+ ROOM15MUS,
+ ROOM16MUS,
+ ROOM17MUS,
+ ROOM18MUS,
+ ROOM19MUS,
+ ROOM20MUS,
+ ROOM21MUS,
+ ROOM22MUS,
+ ROOM23MUS,
+ ROOM24MUS,
+ ROOM25MUS,
+ ROOM26MUS,
+ ROOM27MUS,
+ ROOM28MUS,
+ ROOM29MUS,
+ ROOM30MUS,
+ ROOM31MUS,
+ ROOM32MUS,
+ ROOM33MUS,
+ ROOM34MUS,
+ ROOM35MUS,
+ ROOM36MUS,
+ ROOM37MUS,
+ ROOM38MUS,
+ ROOM39MUS,
+ ROOM40MUS,
+ ROOM41MUS,
+ ROOM42MUS,
+ ROOM43MUS,
+ 0,
+ 0,
+ ROOM46MUS,
+ ROOM47MUS,
+ ROOM48MUS,
+ ROOM49MUS,
+ ROOM50MUS,
+ ROOM51MUS,
+ ROOM52MUS,
+ ROOM53MUS,
+ ROOM54MUS,
+ ROOM55MUS,
+ ROOM56MUS,
+ ROOM57MUS,
+ ROOM58MUS,
+ ROOM59MUS,
+ ROOM60MUS,
+ ROOM61MUS
+};
+
+
+MusicPlayer::MusicPlayer(PrinceEngine *vm) : _vm(vm) {
+ _data = nullptr;
+ _isGM = false;
+
+ MidiPlayer::createDriver();
+
+ int ret = _driver->open();
+ if (ret == 0) {
+ if (_nativeMT32)
+ _driver->sendMT32Reset();
+ else
+ _driver->sendGMReset();
+
+ _driver->setTimerCallback(this, &timerCallback);
+ }
+}
+
+MusicPlayer::~MusicPlayer() {
+ killMidi();
+}
+
+void MusicPlayer::killMidi() {
+ Audio::MidiPlayer::stop();
+
+ free(_data);
+ _data = nullptr;
+}
+
+void MusicPlayer::loadMidi(const char *name) {
+ Common::SeekableReadStream *stream = SearchMan.createReadStreamForMember(name);
+ if (!stream) {
+ debug("Can't load midi stream %s", name);
+ return;
+ }
+
+ // Stop any currently playing MIDI file
+ killMidi();
+
+ // Read in the data for the file
+ _dataSize = stream->size();
+ _data = (byte *)malloc(_dataSize);
+ stream->read(_data, _dataSize);
+
+ delete stream;
+
+ // Start playing the music
+ sndMidiStart();
+}
+
+void MusicPlayer::sndMidiStart() {
+ _isGM = true;
+
+ MidiParser *parser = MidiParser::createParser_SMF();
+ if (parser->loadMusic(_data, _dataSize)) {
+ parser->setTrack(0);
+ parser->setMidiDriver(this);
+ parser->setTimerRate(_driver->getBaseTempo());
+ parser->property(MidiParser::mpCenterPitchWheelOnUnload, 1);
+
+ _parser = parser;
+
+ syncVolume();
+
+ // Al the tracks are supposed to loop
+ _isLooping = true;
+ _isPlaying = true;
+ }
+}
+
+void MusicPlayer::send(uint32 b) {
+ if ((b & 0xF0) == 0xC0 && !_isGM && !_nativeMT32) {
+ b = (b & 0xFFFF00FF) | MidiDriver::_mt32ToGm[(b >> 8) & 0xFF] << 8;
+ }
+
+ Audio::MidiPlayer::send(b);
+}
+
+void MusicPlayer::sendToChannel(byte channel, uint32 b) {
+ if (!_channelsTable[channel]) {
+ _channelsTable[channel] = (channel == 9) ? _driver->getPercussionChannel() : _driver->allocateChannel();
+ // If a new channel is allocated during the playback, make sure
+ // its volume is correctly initialized.
+ if (_channelsTable[channel])
+ _channelsTable[channel]->volume(_channelsVolume[channel] * _masterVolume / 255);
+ }
+
+ if (_channelsTable[channel])
+ _channelsTable[channel]->send(b);
+}
+
+} // End of namespace Prince
diff --git a/engines/prince/sound.h b/engines/prince/sound.h
new file mode 100644
index 0000000000..cc44b0a110
--- /dev/null
+++ b/engines/prince/sound.h
@@ -0,0 +1,67 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef PRINCE_SOUND_H
+#define PRINCE_SOUND_H
+
+#include "audio/audiostream.h"
+#include "audio/decoders/wave.h"
+#include "audio/fmopl.h"
+#include "audio/mididrv.h"
+#include "audio/midiparser.h"
+#include "audio/midiplayer.h"
+#include "audio/mixer.h"
+#include "common/memstream.h"
+
+namespace Prince {
+
+class PrinceEngine;
+
+class MusicPlayer: public Audio::MidiPlayer {
+private:
+ PrinceEngine *_vm;
+ byte *_data;
+ int _dataSize;
+ bool _isGM;
+
+ // Start MIDI File
+ void sndMidiStart();
+
+ // Stop MIDI File
+ void sndMidiStop();
+public:
+ MusicPlayer(PrinceEngine *vm);
+ ~MusicPlayer();
+
+ void loadMidi(const char *);
+ void killMidi();
+
+ virtual void send(uint32 b);
+ virtual void sendToChannel(byte channel, uint32 b);
+
+ static const char *_musTable[];
+ static const uint8 _musRoomTable[];
+};
+
+} // End of namespace Prince
+
+#endif
diff --git a/engines/prince/variatxt.cpp b/engines/prince/variatxt.cpp
new file mode 100644
index 0000000000..c38c65ce5d
--- /dev/null
+++ b/engines/prince/variatxt.cpp
@@ -0,0 +1,55 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "prince/variatxt.h"
+#include "common/debug.h"
+
+namespace Prince {
+
+VariaTxt::VariaTxt() : _dataSize(0), _data(nullptr) {
+}
+
+VariaTxt::~VariaTxt() {
+ _dataSize = 0;
+ if (_data != nullptr) {
+ free(_data);
+ _data = nullptr;
+ }
+}
+
+
+bool VariaTxt::loadStream(Common::SeekableReadStream &stream) {
+ _dataSize = stream.size();
+ _data = (byte *)malloc(_dataSize);
+ stream.read(_data, _dataSize);
+ return true;
+}
+
+byte *VariaTxt::getString(uint32 stringId) {
+ uint32 stringOffset = READ_LE_UINT32(_data + stringId * 4);
+ if (stringOffset > _dataSize) {
+ assert(false);
+ }
+ return _data + stringOffset;
+}
+
+} // End of namespace Prince
diff --git a/engines/prince/variatxt.h b/engines/prince/variatxt.h
new file mode 100644
index 0000000000..04c34bc0ef
--- /dev/null
+++ b/engines/prince/variatxt.h
@@ -0,0 +1,40 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "common/stream.h"
+
+namespace Prince {
+
+class VariaTxt {
+public:
+ VariaTxt();
+ ~VariaTxt();
+
+ bool loadStream(Common::SeekableReadStream &stream);
+ byte *getString(uint32 stringId);
+
+private:
+ uint32 _dataSize;
+ byte *_data;
+};
+
+} // End of namespace Prince
diff --git a/engines/queen/POTFILES b/engines/queen/POTFILES
index 1baf9c24de..28624662ca 100644
--- a/engines/queen/POTFILES
+++ b/engines/queen/POTFILES
@@ -1 +1 @@
-engines/queen/queen.cpp
+engines/queen/detection.cpp
diff --git a/engines/queen/logic.cpp b/engines/queen/logic.cpp
index d48bb8a498..664a9a15f9 100644
--- a/engines/queen/logic.cpp
+++ b/engines/queen/logic.cpp
@@ -2115,9 +2115,15 @@ void LogicInterview::setupSpecialMoveTable() {
}
void LogicGame::useJournal() {
+ _vm->input()->clearKeyVerb();
+ _vm->input()->clearMouseButton();
+
_vm->command()->clear(false);
_journal->use();
_vm->walk()->stopJoe();
+
+ _vm->input()->clearKeyVerb();
+ _vm->input()->clearMouseButton();
}
bool LogicGame::changeToSpecialRoom() {
diff --git a/engines/queen/talk.cpp b/engines/queen/talk.cpp
index 1b9d72babc..e86a53d448 100644
--- a/engines/queen/talk.cpp
+++ b/engines/queen/talk.cpp
@@ -189,7 +189,7 @@ void Talk::talk(const char *filename, int personInRoom, char *cutawayFilename) {
}
}
- if (_vm->input()->talkQuit())
+ if (_vm->input()->talkQuit() || _vm->shouldQuit())
break;
retval = _dialogueTree[level][selectedSentence].dialogueNodeValue1;
@@ -1250,15 +1250,12 @@ int16 Talk::selectSentence() {
}
_vm->input()->clearKeyVerb();
+ _vm->input()->clearMouseButton();
if (sentenceCount > 0) {
int oldZone = 0;
- while (0 == selectedSentence) {
-
- if (_vm->input()->talkQuit())
- break;
-
+ while (0 == selectedSentence && !_vm->input()->talkQuit() && !_vm->shouldQuit()) {
_vm->update();
Common::Point mouse = _vm->input()->getMousePos();
@@ -1328,6 +1325,9 @@ int16 Talk::selectSentence() {
}
}
+ _vm->input()->clearKeyVerb();
+ _vm->input()->clearMouseButton();
+
debug(6, "Selected sentence %i", selectedSentence);
arrowBobUp->active = false;
diff --git a/engines/saga/actor.h b/engines/saga/actor.h
index b8a5436d76..8dc27c74be 100644
--- a/engines/saga/actor.h
+++ b/engines/saga/actor.h
@@ -468,7 +468,6 @@ public:
int actorIdToIndex(uint16 id) { return (id == ID_PROTAG) ? 0 : objectIdToIndex(id); }
uint16 actorIndexToId(int index) { return (index == 0) ? ID_PROTAG : objectIndexToId(kGameObjectActor, index); }
ActorData *getActor(uint16 actorId);
- ActorData *getFirstActor() { return &_actors.front(); }
// clarification: Obj - means game object, such Hat, Spoon etc, Object - means Actor,Obj,HitZone,StepZone
diff --git a/engines/saga/introproc_ite.cpp b/engines/saga/introproc_ite.cpp
index 0c1a2ce233..0b129dbcc0 100644
--- a/engines/saga/introproc_ite.cpp
+++ b/engines/saga/introproc_ite.cpp
@@ -374,7 +374,7 @@ int Scene::ITEIntroCaveCommonProc(int param, int caveScene) {
lang = 2;
int n_dialogues = 0;
-
+
switch (caveScene) {
case 1:
n_dialogues = ARRAYSIZE(introDialogueCave1[lang]);
diff --git a/engines/saga/saveload.cpp b/engines/saga/saveload.cpp
index 90ba62070b..e659e09ce8 100644
--- a/engines/saga/saveload.cpp
+++ b/engines/saga/saveload.cpp
@@ -215,8 +215,7 @@ void SagaEngine::save(const char *fileName, const char *saveName) {
#ifdef ENABLE_IHNM
if (getGameId() == GID_IHNM) {
out->writeSint32LE(_scene->currentChapterNumber());
- // Protagonist
- out->writeSint32LE(_scene->currentProtag());
+ out->writeSint32LE(0); // obsolete, was used for the protagonist
out->writeSint32LE(_scene->getCurrentMusicTrack());
out->writeSint32LE(_scene->getCurrentMusicRepeat());
}
@@ -316,7 +315,7 @@ void SagaEngine::load(const char *fileName) {
if (getGameId() == GID_IHNM) {
int currentChapter = _scene->currentChapterNumber();
_scene->setChapterNumber(in->readSint32LE());
- _scene->setProtag(in->readSint32LE());
+ in->skip(4); // obsolete, was used for setting the protagonist
if (_scene->currentChapterNumber() != currentChapter)
_scene->changeScene(-2, 0, kTransitionFade, _scene->currentChapterNumber());
_scene->setCurrentMusicTrack(in->readSint32LE());
@@ -366,30 +365,6 @@ void SagaEngine::load(const char *fileName) {
int volume = _music->getVolume();
_music->setVolume(0);
-#ifdef ENABLE_IHNM
- // Protagonist swapping
- if (getGameId() == GID_IHNM) {
- if (_scene->currentProtag() != 0 && _scene->currentChapterNumber() != 6) {
- ActorData *actor1 = _actor->getFirstActor();
- ActorData *actor2;
- // The original gets actor2 from the current protagonist ID, but this is sometimes wrong
- // If the current protagonist ID is not correct, use the stored protagonist
- if (!_actor->validActorId(_scene->currentProtag())) {
- actor2 = _actor->_protagonist;
- } else {
- actor2 = _actor->getActor(_scene->currentProtag());
- }
-
- SWAP(actor1->_location, actor2->_location);
-
- actor2->_flags &= ~kProtagonist;
- actor1->_flags |= kProtagonist;
- _actor->_protagonist = _actor->_centerActor = actor1;
- _scene->setProtag(actor1->_id);
- }
- }
-#endif
-
_scene->clearSceneQueue();
_scene->changeScene(sceneNumber, ACTOR_NO_ENTRANCE, kTransitionNoFade);
diff --git a/engines/saga/scene.h b/engines/saga/scene.h
index 6a9571d282..410713c5d5 100644
--- a/engines/saga/scene.h
+++ b/engines/saga/scene.h
@@ -286,8 +286,6 @@ class Scene {
#endif
return _sceneLUT[sceneNumber];
}
- int currentProtag() const { return _currentProtag; }
- void setProtag(int pr) { _currentProtag = pr; }
int currentSceneNumber() const { return _sceneNumber; }
int currentChapterNumber() const { return _chapterNumber; }
void setChapterNumber(int ch) { _chapterNumber = ch; }
@@ -341,7 +339,6 @@ class Scene {
Common::Array<uint16> _sceneLUT;
SceneQueueList _sceneQueue;
bool _sceneLoaded;
- int _currentProtag;
int _sceneNumber;
int _chapterNumber;
int _outsetSceneNumber;
diff --git a/engines/saga/sfuncs.cpp b/engines/saga/sfuncs.cpp
index cb963e23ac..2175d8f40a 100644
--- a/engines/saga/sfuncs.cpp
+++ b/engines/saga/sfuncs.cpp
@@ -748,14 +748,10 @@ void Script::sfSwapActors(SCRIPTFUNC_PARAMS) {
actor1->_flags &= ~kProtagonist;
actor2->_flags |= kProtagonist;
_vm->_actor->_protagonist = _vm->_actor->_centerActor = actor2;
- if (_vm->getGameId() == GID_IHNM)
- _vm->_scene->setProtag(actorId2);
} else if (actor2->_flags & kProtagonist) {
actor2->_flags &= ~kProtagonist;
actor1->_flags |= kProtagonist;
_vm->_actor->_protagonist = _vm->_actor->_centerActor = actor1;
- if (_vm->getGameId() == GID_IHNM)
- _vm->_scene->setProtag(actorId1);
}
}
diff --git a/engines/saga/shorten.cpp b/engines/saga/shorten.cpp
index edb12a3dd9..1e1c397212 100644
--- a/engines/saga/shorten.cpp
+++ b/engines/saga/shorten.cpp
@@ -438,7 +438,7 @@ byte *loadShortenFromStream(Common::ReadStream &stream, int &size, int &rate, by
for (i = 0; i < 64; ++i)
oldValues[curChannel][i] = 0;
- int arrayTerminator = MIN<int>(64, blockSize);
+ uint arrayTerminator = MIN<int>(64, blockSize);
for (i = 0; i < arrayTerminator; ++i)
oldValues[curChannel][i] = buffer[curChannel][blockSize - (i + 1)];
diff --git a/engines/savestate.h b/engines/savestate.h
index 970e01485d..54eff0f8cb 100644
--- a/engines/savestate.h
+++ b/engines/savestate.h
@@ -140,7 +140,7 @@ public:
* Sets the time the game was played before the save state was created.
*
* @param hours How many hours the user played the game so far.
- * @param min How many minutes the user played the game so far.
+ * @param minutes How many minutes the user played the game so far.
*/
void setPlayTime(int hours, int minutes);
diff --git a/engines/sci/console.cpp b/engines/sci/console.cpp
index 565e9752c3..e233c4cba4 100644
--- a/engines/sci/console.cpp
+++ b/engines/sci/console.cpp
@@ -485,6 +485,7 @@ bool Console::cmdGetVersion(int argc, const char **argv) {
#endif
debugPrintf("View type: %s\n", viewTypeDesc[g_sci->getResMan()->getViewType()]);
debugPrintf("Uses palette merging: %s\n", g_sci->_gfxPalette->isMerging() ? "yes" : "no");
+ debugPrintf("Uses 16 bit color matching: %s\n", g_sci->_gfxPalette->isUsing16bitColorMatch() ? "yes" : "no");
debugPrintf("Resource volume version: %s\n", g_sci->getResMan()->getVolVersionDesc());
debugPrintf("Resource map version: %s\n", g_sci->getResMan()->getMapVersionDesc());
debugPrintf("Contains selector vocabulary (vocab.997): %s\n", hasVocab997 ? "yes" : "no");
@@ -663,7 +664,7 @@ bool Console::cmdDiskDump(int argc, const char **argv) {
int resNumFrom = 0;
int resNumTo = 0;
int resNumCur = 0;
-
+
if (argc != 3) {
debugPrintf("Dumps the specified resource to disk as a patch file\n");
debugPrintf("Usage: %s <resource type> <resource number>\n", argv[0]);
@@ -671,7 +672,7 @@ bool Console::cmdDiskDump(int argc, const char **argv) {
cmdResourceTypes(argc, argv);
return true;
}
-
+
if (strcmp(argv[2], "*") == 0) {
resNumFrom = 0;
resNumTo = 65535;
diff --git a/engines/sci/detection.cpp b/engines/sci/detection.cpp
index 4f28738508..85ff1c0062 100644
--- a/engines/sci/detection.cpp
+++ b/engines/sci/detection.cpp
@@ -563,31 +563,28 @@ const ADGameDescription *SciMetaEngine::fallbackDetect(const FileMap &allFiles,
// If these files aren't found, it can't be SCI
- if (!foundResMap && !foundRes000) {
+ if (!foundResMap && !foundRes000)
return 0;
- }
ResourceManager resMan;
- resMan.addAppropriateSources(fslist);
- resMan.init(true);
+ resMan.addAppropriateSourcesForDetection(fslist);
+ resMan.initForDetection();
// TODO: Add error handling.
#ifndef ENABLE_SCI32
// Is SCI32 compiled in? If not, and this is a SCI32 game,
// stop here
- if (getSciVersion() >= SCI_VERSION_2) {
- return (const ADGameDescription *)&s_fallbackDesc;
- }
+ if (getSciVersionForDetection() >= SCI_VERSION_2)
+ return 0;
#endif
ViewType gameViews = resMan.getViewType();
// Have we identified the game views? If not, stop here
- // Can't be SCI (or unsupported SCI views). Pinball Creep by sierra also uses resource.map/resource.000 files
- // but doesnt share sci format at all, if we dont return 0 here we will detect this game as SCI
- if (gameViews == kViewUnknown) {
+ // Can't be SCI (or unsupported SCI views). Pinball Creep by Sierra also uses resource.map/resource.000 files
+ // but doesn't share SCI format at all
+ if (gameViews == kViewUnknown)
return 0;
- }
// Set the platform to Amiga if the game is using Amiga views
if (gameViews == kViewAmiga)
@@ -597,9 +594,8 @@ const ADGameDescription *SciMetaEngine::fallbackDetect(const FileMap &allFiles,
Common::String sierraGameId = resMan.findSierraGameId();
// If we don't have a game id, the game is not SCI
- if (sierraGameId.empty()) {
+ if (sierraGameId.empty())
return 0;
- }
Common::String gameId = convertSierraGameId(sierraGameId, &s_fallbackDesc.flags, resMan);
strncpy(s_fallbackGameIdBuf, gameId.c_str(), sizeof(s_fallbackGameIdBuf) - 1);
diff --git a/engines/sci/detection_tables.h b/engines/sci/detection_tables.h
index 344298ce9a..0fddaa51b4 100644
--- a/engines/sci/detection_tables.h
+++ b/engines/sci/detection_tables.h
@@ -1832,15 +1832,12 @@ static const struct ADGameDescription SciGameDescriptions[] = {
AD_LISTEND},
Common::EN_ANY, Common::kPlatformDOS, 0, GUIO4(GUIO_NOSPEECH, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
-#if 0
- // The resource.002 file, contained in disk 3, is broken in this version
- // (it contains a large chunk of zeroes and several broken resources,
- // e.g. pic 250 and views 250 and 251).
- // Thus this detection entry isn't accurate.
-
- // Larry 1 Remake - English Amiga (from www.back2roots.org)
+ // Larry 1 Remake - English Amiga
// Executable scanning reports "1.004.024"
// SCI interpreter version 1.000.784
+ // NOTE: The resource.002 file, contained in disk 3, is broken in the
+ // www.back2roots.org version (it contains a large chunk of zeroes and
+ // several broken resources, e.g. pic 250 and views 250 and 251).
{"lsl1sci", "SCI", {
{"resource.map", 0, "7d115a9e27dc8ac71e8d5ef33d589bd5", 3366},
{"resource.000", 0, "e67fd129d5810fc7ad8ea509d891cc00", 363073},
@@ -1849,7 +1846,6 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resource.003", 0, "4a34c3367c2fe7eb380d741374da1989", 572251},
AD_LISTEND},
Common::EN_ANY, Common::kPlatformAmiga, 0, GUIO4(GUIO_NOSPEECH, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
-#endif
// Larry 1 VGA Remake - English DOS (from spookypeanut)
// Executable scanning reports "1.000.577", VERSION file reports "2.1"
@@ -2607,6 +2603,25 @@ 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) },
+ // Phantasmagoria - French DOS
+ // Supplied by Kervala in bug #6574
+ {"phantasmagoria", "", {
+ {"resmap.001", 0, "4da82dd336d4b9cd8c16f3cc11f0c615", 11524},
+ {"ressci.001", 0, "3aae6559aa1df273bc542d5ac6330d75", 69963685},
+ {"resmap.002", 0, "4f40f43f2b60bf765864433069752bb9", 12064},
+ {"ressci.002", 0, "3aae6559aa1df273bc542d5ac6330d75", 78362841},
+ {"resmap.003", 0, "6a392a86f14b6ddb4422978ee71e54ac", 12340},
+ {"ressci.003", 0, "3aae6559aa1df273bc542d5ac6330d75", 80431189},
+ {"resmap.004", 0, "df2e9462c41202de5f3843908c95a715", 12562},
+ {"ressci.004", 0, "3aae6559aa1df273bc542d5ac6330d75", 82542844},
+ {"resmap.005", 0, "43efd3fe834286c70a2c8b4cd747c1e2", 12616},
+ {"ressci.005", 0, "3aae6559aa1df273bc542d5ac6330d75", 83790486},
+ {"resmap.006", 0, "b3065e54a00190752a06dacd201b5058", 12538},
+ {"ressci.006", 0, "3aae6559aa1df273bc542d5ac6330d75", 85415107},
+ {"resmap.007", 0, "5633960bc106c39ca91d2d8fce18fd2d", 7984},
+ AD_LISTEND},
+ Common::FR_FRA, Common::kPlatformDOS, ADGF_UNSTABLE, GUIO5(GUIO_NOSPEECH, GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+
// Phantasmagoria - English DOS Demo
// Executable scanning reports "2.100.002"
{"phantasmagoria", "Demo", {
@@ -4100,6 +4115,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
FANMADE("Knight's Quest Demo 1.0", "5e816edf993956752ed06fccfeeae6d9", 1260, "959321f88a22905fa1f8c6d897874744", 703836),
FANMADE("LockerGnome Quest", "3eeff9130206cad0c4e1551e2b9dd2c5", 420, "ae05ca90806fd90cc43f147c82d3547c", 158906),
FANMADE("LockerGnome Quest Redux", "55b0081dbdd77a07807c76cec3606970", 492, "75c9c5e8a475a7b5f1a6cb18edad67f2", 168069),
+ FANMADE("LockerGnome Quest Redux", "6299578d8ab709cc181baea6b984a0a7", 492, "c0ff4bfcc62fb111337343967e4001fd", 167383),
FANMADE("New Year's Mystery", "e4dcab1b1d3cb4a2c070a07a9c9589e0", 708, "e00ca5e44fd4e98d8174b467b31b0f21", 295425),
FANMADE("New Year's Mystery (Updated)", "efd1beb5120293725065c95959144f81", 714, "b3bd3c2372ed6efa28adb12403c4c31a", 305027),
FANMADE("Ocean Battle", "c2304a0568e0eb84f8e9a0915f01170a", 408, "46c520c1ac9b63528854d0f58c7e1b74", 142234),
diff --git a/engines/sci/engine/features.cpp b/engines/sci/engine/features.cpp
index 31e7ca4931..be062dba64 100644
--- a/engines/sci/engine/features.cpp
+++ b/engines/sci/engine/features.cpp
@@ -344,9 +344,9 @@ bool GameFeatures::autoDetectGfxFunctionsType(int methodNum) {
if (kFuncNum == 8) { // kDrawPic (SCI0 - SCI11)
// If kDrawPic is called with 6 parameters from the overlay
// selector, the game is using old graphics functions.
- // Otherwise, if it's called with 8 parameters, it's using new
- // graphics functions.
- _gfxFunctionsType = (argc == 8) ? SCI_VERSION_0_LATE : SCI_VERSION_0_EARLY;
+ // Otherwise, if it's called with 8 parameters (e.g. SQ3) or 4 parameters
+ // (e.g. Hoyle 1/2), it's using new graphics functions.
+ _gfxFunctionsType = (argc == 6) ? SCI_VERSION_0_EARLY : SCI_VERSION_0_LATE;
return true;
}
}
diff --git a/engines/sci/engine/kernel.h b/engines/sci/engine/kernel.h
index dddf845222..a65bcb7df5 100644
--- a/engines/sci/engine/kernel.h
+++ b/engines/sci/engine/kernel.h
@@ -145,7 +145,7 @@ public:
*/
Kernel(ResourceManager *resMan, SegManager *segMan);
~Kernel();
-
+
void init();
uint getSelectorNamesSize() const;
@@ -161,7 +161,7 @@ public:
* @return The appropriate selector ID, or -1 on error
*/
int findSelector(const char *selectorName) const;
-
+
bool selectorNamesAvailable();
// Script dissection/dumping functions
diff --git a/engines/sci/engine/kernel_tables.h b/engines/sci/engine/kernel_tables.h
index fc46d16b8d..0c2fd4e3ea 100644
--- a/engines/sci/engine/kernel_tables.h
+++ b/engines/sci/engine/kernel_tables.h
@@ -468,7 +468,8 @@ static SciKernelMapEntry s_kernelMap[] = {
{ MAP_CALL(TimesSin), SIG_EVERYWHERE, "ii", NULL, NULL },
{ "SinMult", kTimesSin, SIG_EVERYWHERE, "ii", NULL, NULL },
{ MAP_CALL(TimesTan), SIG_EVERYWHERE, "ii", NULL, NULL },
- { MAP_CALL(UnLoad), SIG_EVERYWHERE, "i[ri]", NULL, kUnLoad_workarounds },
+ { MAP_CALL(UnLoad), SIG_EVERYWHERE, "i[ir!]", NULL, kUnLoad_workarounds },
+ // ^ We allow invalid references here (e.g. bug #6600), since they will be invalidated anyway by the call itself
{ MAP_CALL(ValidPath), SIG_EVERYWHERE, "r", NULL, NULL },
{ MAP_CALL(Wait), SIG_EVERYWHERE, "i", NULL, NULL },
diff --git a/engines/sci/engine/kfile.cpp b/engines/sci/engine/kfile.cpp
index 61fb717567..c56eb09482 100644
--- a/engines/sci/engine/kfile.cpp
+++ b/engines/sci/engine/kfile.cpp
@@ -37,6 +37,7 @@
#include "sci/engine/state.h"
#include "sci/engine/kernel.h"
#include "sci/engine/savegame.h"
+#include "sci/graphics/menu.h"
#include "sci/sound/audio.h"
#include "sci/console.h"
@@ -913,6 +914,25 @@ reg_t kRestoreGame(EngineState *s, int argc, reg_t *argv) {
// code concerning this via script patch.
s->variables[VAR_GLOBAL][0xB3].setOffset(SAVEGAMEID_OFFICIALRANGE_START + savegameId);
break;
+ case GID_JONES:
+ // HACK: The code that enables certain menu items isn't called when a game is restored from the
+ // launcher, or the "Restore game" option in the game's main menu - bugs #6537 and #6723.
+ // These menu entries are disabled when the game is launched, and are enabled when a new game is
+ // started. The code for enabling these entries is is all in script 1, room1::init, but that code
+ // path is never followed in these two cases (restoring game from the menu, or restoring a game
+ // from the ScummVM launcher). Thus, we perform the calls to enable the menus ourselves here.
+ // These two are needed when restoring from the launcher
+ // FIXME: The original interpreter saves and restores the menu state, so these attributes
+ // are automatically reset there. We may want to do the same.
+ g_sci->_gfxMenu->kernelSetAttribute(257 >> 8, 257 & 0xFF, SCI_MENU_ATTRIBUTE_ENABLED, TRUE_REG); // Sierra -> About Jones
+ g_sci->_gfxMenu->kernelSetAttribute(258 >> 8, 258 & 0xFF, SCI_MENU_ATTRIBUTE_ENABLED, TRUE_REG); // Sierra -> Help
+ // The rest are normally enabled from room1::init
+ g_sci->_gfxMenu->kernelSetAttribute(769 >> 8, 769 & 0xFF, SCI_MENU_ATTRIBUTE_ENABLED, TRUE_REG); // Options -> Delete current player
+ g_sci->_gfxMenu->kernelSetAttribute(513 >> 8, 513 & 0xFF, SCI_MENU_ATTRIBUTE_ENABLED, TRUE_REG); // Game -> Save Game
+ g_sci->_gfxMenu->kernelSetAttribute(515 >> 8, 515 & 0xFF, SCI_MENU_ATTRIBUTE_ENABLED, TRUE_REG); // Game -> Restore Game
+ g_sci->_gfxMenu->kernelSetAttribute(1025 >> 8, 1025 & 0xFF, SCI_MENU_ATTRIBUTE_ENABLED, TRUE_REG); // Status -> Statistics
+ g_sci->_gfxMenu->kernelSetAttribute(1026 >> 8, 1026 & 0xFF, SCI_MENU_ATTRIBUTE_ENABLED, TRUE_REG); // Status -> Goals
+ break;
default:
break;
}
diff --git a/engines/sci/engine/kgraphics.cpp b/engines/sci/engine/kgraphics.cpp
index c2089bcd4d..ee2249bd9d 100644
--- a/engines/sci/engine/kgraphics.cpp
+++ b/engines/sci/engine/kgraphics.cpp
@@ -354,13 +354,16 @@ reg_t kTextSize(EngineState *s, int argc, reg_t *argv) {
}
textWidth = dest[3].toUint16(); textHeight = dest[2].toUint16();
+
+ uint16 languageSplitter = 0;
+ Common::String splitText = g_sci->strSplitLanguage(text.c_str(), &languageSplitter, sep);
#ifdef ENABLE_SCI32
if (g_sci->_gfxText32)
- g_sci->_gfxText32->kernelTextSize(g_sci->strSplit(text.c_str(), sep).c_str(), font_nr, maxwidth, &textWidth, &textHeight);
+ g_sci->_gfxText32->kernelTextSize(splitText.c_str(), font_nr, maxwidth, &textWidth, &textHeight);
else
#endif
- g_sci->_gfxText16->kernelTextSize(g_sci->strSplit(text.c_str(), sep).c_str(), font_nr, maxwidth, &textWidth, &textHeight);
+ g_sci->_gfxText16->kernelTextSize(splitText.c_str(), languageSplitter, font_nr, maxwidth, &textWidth, &textHeight);
// One of the game texts in LB2 German contains loads of spaces in
// its end. We trim the text here, otherwise the graphics code will
@@ -376,7 +379,7 @@ reg_t kTextSize(EngineState *s, int argc, reg_t *argv) {
// Copy over the trimmed string...
s->_segMan->strcpy(argv[1], text.c_str());
// ...and recalculate bounding box dimensions
- g_sci->_gfxText16->kernelTextSize(g_sci->strSplit(text.c_str(), sep).c_str(), font_nr, maxwidth, &textWidth, &textHeight);
+ g_sci->_gfxText16->kernelTextSize(splitText.c_str(), languageSplitter, font_nr, maxwidth, &textWidth, &textHeight);
}
}
@@ -818,16 +821,29 @@ void _k_GenericDrawControl(EngineState *s, reg_t controlObject, bool hilite) {
if (!textReference.isNull())
text = s->_segMan->getString(textReference);
+ uint16 languageSplitter = 0;
+ Common::String splitText;
+
+ switch (type) {
+ case SCI_CONTROLS_TYPE_BUTTON:
+ case SCI_CONTROLS_TYPE_TEXTEDIT:
+ splitText = g_sci->strSplitLanguage(text.c_str(), &languageSplitter, NULL);
+ break;
+ case SCI_CONTROLS_TYPE_TEXT:
+ splitText = g_sci->strSplitLanguage(text.c_str(), &languageSplitter);
+ break;
+ }
+
switch (type) {
case SCI_CONTROLS_TYPE_BUTTON:
debugC(kDebugLevelGraphics, "drawing button %04x:%04x to %d,%d", PRINT_REG(controlObject), x, y);
- g_sci->_gfxControls16->kernelDrawButton(rect, controlObject, g_sci->strSplit(text.c_str(), NULL).c_str(), fontId, style, hilite);
+ g_sci->_gfxControls16->kernelDrawButton(rect, controlObject, splitText.c_str(), languageSplitter, fontId, style, hilite);
return;
case SCI_CONTROLS_TYPE_TEXT:
alignment = readSelectorValue(s->_segMan, controlObject, SELECTOR(mode));
debugC(kDebugLevelGraphics, "drawing text %04x:%04x ('%s') to %d,%d, mode=%d", PRINT_REG(controlObject), text.c_str(), x, y, alignment);
- g_sci->_gfxControls16->kernelDrawText(rect, controlObject, g_sci->strSplit(text.c_str()).c_str(), fontId, alignment, style, hilite);
+ g_sci->_gfxControls16->kernelDrawText(rect, controlObject, splitText.c_str(), languageSplitter, fontId, alignment, style, hilite);
s->r_acc = g_sci->_gfxText16->allocAndFillReferenceRectArray();
return;
@@ -841,7 +857,7 @@ void _k_GenericDrawControl(EngineState *s, reg_t controlObject, bool hilite) {
writeSelectorValue(s->_segMan, controlObject, SELECTOR(cursor), cursorPos);
}
debugC(kDebugLevelGraphics, "drawing edit control %04x:%04x (text %04x:%04x, '%s') to %d,%d", PRINT_REG(controlObject), PRINT_REG(textReference), text.c_str(), x, y);
- g_sci->_gfxControls16->kernelDrawTextEdit(rect, controlObject, g_sci->strSplit(text.c_str(), NULL).c_str(), fontId, mode, style, cursorPos, maxChars, hilite);
+ g_sci->_gfxControls16->kernelDrawTextEdit(rect, controlObject, splitText.c_str(), languageSplitter, fontId, mode, style, cursorPos, maxChars, hilite);
return;
case SCI_CONTROLS_TYPE_ICON:
@@ -1165,8 +1181,11 @@ reg_t kDisplay(EngineState *s, int argc, reg_t *argv) {
argc--; argc--; argv++; argv++;
text = g_sci->getKernel()->lookupText(textp, index);
}
+
+ uint16 languageSplitter = 0;
+ Common::String splitText = g_sci->strSplitLanguage(text.c_str(), &languageSplitter);
- return g_sci->_gfxPaint16->kernelDisplay(g_sci->strSplit(text.c_str()).c_str(), argc, argv);
+ return g_sci->_gfxPaint16->kernelDisplay(splitText.c_str(), languageSplitter, argc, argv);
}
reg_t kSetVideoMode(EngineState *s, int argc, reg_t *argv) {
diff --git a/engines/sci/engine/kstring.cpp b/engines/sci/engine/kstring.cpp
index 56dad583e4..eef758a0d9 100644
--- a/engines/sci/engine/kstring.cpp
+++ b/engines/sci/engine/kstring.cpp
@@ -42,10 +42,12 @@ reg_t kStrCat(EngineState *s, int argc, reg_t *argv) {
Common::String s1 = s->_segMan->getString(argv[0]);
Common::String s2 = s->_segMan->getString(argv[1]);
- // The Japanese version of PQ2 splits the two strings here
- // (check bug #3396887).
- if (g_sci->getGameId() == GID_PQ2 &&
- g_sci->getLanguage() == Common::JA_JPN) {
+ // Japanese PC-9801 interpreter splits strings here
+ // see bug #5834
+ // Verified for Police Quest 2 + Quest For Glory 1
+ // However Space Quest 4 PC-9801 doesn't
+ if ((g_sci->getLanguage() == Common::JA_JPN)
+ && (getSciVersion() <= SCI_VERSION_01)) {
s1 = g_sci->strSplit(s1.c_str(), NULL);
s2 = g_sci->strSplit(s2.c_str(), NULL);
}
diff --git a/engines/sci/engine/savegame.cpp b/engines/sci/engine/savegame.cpp
index cdcdcc41e5..9decc4cef6 100644
--- a/engines/sci/engine/savegame.cpp
+++ b/engines/sci/engine/savegame.cpp
@@ -844,6 +844,8 @@ bool gamestate_save(EngineState *s, Common::WriteStream *fh, const Common::Strin
if (voc)
voc->saveLoadWithSerializer(ser);
+ // TODO: SSCI (at least JonesCD, presumably more) also stores the Menu state
+
return true;
}
diff --git a/engines/sci/engine/script_patches.cpp b/engines/sci/engine/script_patches.cpp
index 8bbbd713a6..3d76848a76 100644
--- a/engines/sci/engine/script_patches.cpp
+++ b/engines/sci/engine/script_patches.cpp
@@ -1917,6 +1917,43 @@ static const SciScriptPatcherEntry pq1vgaSignatures[] = {
};
// ===========================================================================
+// At the healer's house there is a bird's nest up on the tree.
+// The player can throw rocks at it until it falls to the ground.
+// The hero will then grab the item, that is in the nest.
+//
+// When running is active, the hero will not reach the actual destination
+// and because of that, the game will get stuck.
+//
+// We just change the coordinate of the destination slightly, so that walking,
+// sneaking and running work.
+//
+// This bug was fixed by Sierra at least in the Japanese PC-9801 version.
+// Applies to at least: English floppy (1.000, 1.012)
+// Responsible method: pickItUp::changeState (script 54)
+// Fixes bug: #6407
+static const uint16 qfg1egaSignatureThrowRockAtNest[] = {
+ 0x4a, 0x04, // send 04 (nest::x)
+ 0x36, // push
+ SIG_MAGICDWORD,
+ 0x35, 0x0f, // ldi 0f (15d)
+ 0x02, // add
+ 0x36, // push
+ SIG_END
+};
+
+static const uint16 qfg1egaPatchThrowRockAtNest[] = {
+ PATCH_ADDTOOFFSET(+3),
+ 0x35, 0x12, // ldi 12 (18d)
+ PATCH_END
+};
+
+// script, description, signature patch
+static const SciScriptPatcherEntry qfg1egaSignatures[] = {
+ { true, 54, "throw rock at nest while running", 1, qfg1egaSignatureThrowRockAtNest, qfg1egaPatchThrowRockAtNest },
+ SCI_SIGNATUREENTRY_TERMINATOR
+};
+
+// ===========================================================================
// script 215 of qfg1vga pointBox::doit actually processes button-presses
// during fighting with monsters. It strangely also calls kGetEvent. Because
// the main User::doit also calls kGetEvent it's pure luck, where the event
@@ -3036,6 +3073,9 @@ void ScriptPatcher::processScript(uint16 scriptNr, byte *scriptData, const uint3
case GID_PQ1:
signatureTable = pq1vgaSignatures;
break;
+ case GID_QFG1:
+ signatureTable = qfg1egaSignatures;
+ break;
case GID_QFG1VGA:
signatureTable = qfg1vgaSignatures;
break;
diff --git a/engines/sci/engine/script_patches.h b/engines/sci/engine/script_patches.h
index 0b35792949..7023ef327e 100644
--- a/engines/sci/engine/script_patches.h
+++ b/engines/sci/engine/script_patches.h
@@ -98,7 +98,7 @@ private:
void enablePatch(const SciScriptPatcherEntry *patchTable, const char *searchDescription);
int32 findSignature(const SciScriptPatcherEntry *patchEntry, SciScriptPatcherRuntimeEntry *runtimeEntry, const byte *scriptData, const uint32 scriptSize, bool isMacSci11);
void applyPatch(const SciScriptPatcherEntry *patchEntry, byte *scriptData, const uint32 scriptSize, int32 signatureOffset, bool isMacSci11);
-
+
Selector *_selectorIdTable;
SciScriptPatcherRuntimeEntry *_runtimeTable;
};
diff --git a/engines/sci/engine/seg_manager.cpp b/engines/sci/engine/seg_manager.cpp
index 3738fd3dcb..58c2b8d3e3 100644
--- a/engines/sci/engine/seg_manager.cpp
+++ b/engines/sci/engine/seg_manager.cpp
@@ -371,7 +371,7 @@ void SegManager::freeHunkEntry(reg_t addr) {
HunkTable *ht = (HunkTable *)getSegment(addr.getSegment(), SEG_TYPE_HUNK);
if (!ht) {
- warning("Attempt to free Hunk from address %04x:%04x: Invalid segment type", PRINT_REG(addr));
+ warning("Attempt to free Hunk from address %04x:%04x: Invalid segment type %d", PRINT_REG(addr), getSegmentType(addr.getSegment()));
return;
}
diff --git a/engines/sci/engine/state.cpp b/engines/sci/engine/state.cpp
index 7701822f6d..c07dc925e0 100644
--- a/engines/sci/engine/state.cpp
+++ b/engines/sci/engine/state.cpp
@@ -203,59 +203,94 @@ static kLanguage charToLanguage(const char c) {
}
}
-Common::String SciEngine::getSciLanguageString(const Common::String &str, kLanguage lang, kLanguage *lang2) const {
- kLanguage secondLang = K_LANG_NONE;
-
- const char *seeker = str.c_str();
- while (*seeker) {
- if ((*seeker == '%') || (*seeker == '#')) {
- secondLang = charToLanguage(*(seeker + 1));
-
- if (secondLang != K_LANG_NONE)
+Common::String SciEngine::getSciLanguageString(const Common::String &str, kLanguage requestedLanguage, kLanguage *secondaryLanguage, uint16 *languageSplitter) const {
+ kLanguage foundLanguage = K_LANG_NONE;
+ const byte *textPtr = (byte *)str.c_str();
+ byte curChar = 0;
+ byte curChar2 = 0;
+
+ while (1) {
+ curChar = *textPtr;
+ if (!curChar)
+ break;
+
+ if ((curChar == '%') || (curChar == '#')) {
+ curChar2 = *(textPtr + 1);
+ foundLanguage = charToLanguage(curChar2);
+
+ if (foundLanguage != K_LANG_NONE) {
+ // Return language splitter
+ if (languageSplitter)
+ *languageSplitter = curChar | ( curChar2 << 8 );
+ // Return the secondary language found in the string
+ if (secondaryLanguage)
+ *secondaryLanguage = foundLanguage;
break;
+ }
}
-
- ++seeker;
+ textPtr++;
}
- // Return the secondary language found in the string
- if (lang2)
- *lang2 = secondLang;
-
- if (secondLang == lang) {
- if (*(++seeker) == 'J') {
+ if (foundLanguage == requestedLanguage) {
+ if (curChar2 == 'J') {
// Japanese including Kanji, displayed with system font
// Convert half-width characters to full-width equivalents
Common::String fullWidth;
- byte c;
+ uint16 mappedChar;
+
+ textPtr += 2; // skip over language splitter
+
+ while (1) {
+ curChar = *textPtr;
+
+ switch (curChar) {
+ case 0: // Terminator NUL
+ return fullWidth;
+ case '\\':
+ // "\n", "\N", "\r" and "\R" were overwritten with SPACE + 0x0D in PC-9801 SSCI
+ // inside GetLongest() (text16). We do it here, because it's much cleaner and
+ // we have to process the text here anyway.
+ // Occurs for example in Police Quest 2 intro
+ curChar2 = *(textPtr + 1);
+ switch (curChar2) {
+ case 'n':
+ case 'N':
+ case 'r':
+ case 'R':
+ fullWidth += ' ';
+ fullWidth += 0x0D; // CR
+ textPtr += 2;
+ continue;
+ }
+ }
+
+ textPtr++;
- while ((c = *(++seeker))) {
- uint16 mappedChar = s_halfWidthSJISMap[c];
+ mappedChar = s_halfWidthSJISMap[curChar];
if (mappedChar) {
fullWidth += mappedChar >> 8;
fullWidth += mappedChar & 0xFF;
} else {
// Copy double-byte character
- char c2 = *(++seeker);
- if (!c2) {
- error("SJIS character %02X is missing second byte", c);
+ curChar2 = *(textPtr++);
+ if (!curChar) {
+ error("SJIS character %02X is missing second byte", curChar);
break;
}
- fullWidth += c;
- fullWidth += c2;
+ fullWidth += curChar;
+ fullWidth += curChar2;
}
}
- return fullWidth;
} else {
- return Common::String(seeker + 1);
+ return Common::String((const char *)(textPtr + 2));
}
}
- if (*seeker)
- return Common::String(str.c_str(), seeker - str.c_str());
- else
- return str;
+ if (curChar)
+ return Common::String(str.c_str(), (const char *)textPtr - str.c_str());
+
+ return str;
}
kLanguage SciEngine::getSciLanguage() {
@@ -314,25 +349,25 @@ void SciEngine::setSciLanguage() {
setSciLanguage(getSciLanguage());
}
-Common::String SciEngine::strSplit(const char *str, const char *sep) {
- kLanguage lang = getSciLanguage();
- kLanguage subLang = K_LANG_NONE;
+Common::String SciEngine::strSplitLanguage(const char *str, uint16 *languageSplitter, const char *sep) {
+ kLanguage activeLanguage = getSciLanguage();
+ kLanguage subtitleLanguage = K_LANG_NONE;
if (SELECTOR(subtitleLang) != -1)
- subLang = (kLanguage)readSelectorValue(_gamestate->_segMan, _gameObjectAddress, SELECTOR(subtitleLang));
+ subtitleLanguage = (kLanguage)readSelectorValue(_gamestate->_segMan, _gameObjectAddress, SELECTOR(subtitleLang));
- kLanguage secondLang;
- Common::String retval = getSciLanguageString(str, lang, &secondLang);
+ kLanguage foundLanguage;
+ Common::String retval = getSciLanguageString(str, activeLanguage, &foundLanguage, languageSplitter);
// Don't add subtitle when separator is not set, subtitle language is not set, or
// string contains only one language
- if ((sep == NULL) || (subLang == K_LANG_NONE) || (secondLang == K_LANG_NONE))
+ if ((sep == NULL) || (subtitleLanguage == K_LANG_NONE) || (foundLanguage == K_LANG_NONE))
return retval;
// Add subtitle, unless the subtitle language doesn't match the languages in the string
- if ((subLang == K_LANG_ENGLISH) || (subLang == secondLang)) {
+ if ((subtitleLanguage == K_LANG_ENGLISH) || (subtitleLanguage == foundLanguage)) {
retval += sep;
- retval += getSciLanguageString(str, subLang);
+ retval += getSciLanguageString(str, subtitleLanguage);
}
return retval;
diff --git a/engines/sci/engine/workarounds.cpp b/engines/sci/engine/workarounds.cpp
index ea4dc2fe71..c5730b5345 100644
--- a/engines/sci/engine/workarounds.cpp
+++ b/engines/sci/engine/workarounds.cpp
@@ -91,7 +91,8 @@ const SciWorkaroundEntry uninitializedReadWorkarounds[] = {
{ GID_HOYLE4, 700, -1, 1, "BridgeDefense", "think", -1, -1, { WORKAROUND_FAKE, 0 } }, // sometimes while playing bridge, temp var 3, 17 and others, objects LeadReturn_Trump, ThirdSeat_Trump and others
{ GID_HOYLE4, 700, 730, 1, "BridgeDefense", "beatTheirBest", -1, 3, { WORKAROUND_FAKE, 0 } }, // rarely while playing bridge
{ GID_HOYLE4, 700, -1, 1, "Code", "doit", -1, -1, { WORKAROUND_FAKE, 0 } }, // when placing a bid in bridge (always), temp var 11, 24, 27, 46, 75, objects compete_tree, compwe_tree, other1_tree, b1 - bugs #5663 and #5794
- { GID_HOYLE4, 700, 921, 0, "Print", "addEdit", -1, -1, { WORKAROUND_FAKE, 0 } }, // when saving the game (may also occur in other situations) - bug #6601
+ { GID_HOYLE4, 700, 921, 0, "Print", "addEdit", -1, 0, { WORKAROUND_FAKE, 118 } }, // when saving the game (may also occur in other situations) - bug #6601, bug #6614
+ { GID_HOYLE4, 700, 921, 0, "Print", "addEdit", -1, 1, { WORKAROUND_FAKE, 1 } }, // see above, Text-control saves its coordinates to temp[0] and temp[1], Edit-control adjusts to those uninitialized temps, who by accident were left over from the Text-control
{ GID_HOYLE4, 300, 300, 0, "", "export 2", 0x1d4d, 0, { WORKAROUND_FAKE, 0 } }, // after passing around cards in hearts
{ GID_HOYLE4, 400, 400, 1, "GinHand", "calcRuns", -1, 4, { WORKAROUND_FAKE, 0 } }, // sometimes while playing Gin Rummy (e.g. when knocking and placing a card) - bug #5665
{ GID_HOYLE4, 500, 17, 1, "Character", "say", -1, 504, { WORKAROUND_FAKE, 0 } }, // sometimes while playing Cribbage (e.g. when the opponent says "Last Card") - bug #5662
diff --git a/engines/sci/event.cpp b/engines/sci/event.cpp
index 511d2014bd..b1c002413d 100644
--- a/engines/sci/event.cpp
+++ b/engines/sci/event.cpp
@@ -262,7 +262,7 @@ SciEvent EventManager::getScummVMEvent() {
// Scancodify if appropriate
if (modifiers & Common::KBD_ALT)
input.character = altify(input.character);
- else if ((modifiers & Common::KBD_CTRL) && input.character > 0 && input.character < 27)
+ if (getSciVersion() <= SCI_VERSION_1_MIDDLE && (modifiers & Common::KBD_CTRL) && input.character > 0 && input.character < 27)
input.character += 96; // 0x01 -> 'a'
// If no actual key was pressed (e.g. if only a modifier key was pressed),
diff --git a/engines/sci/graphics/controls16.cpp b/engines/sci/graphics/controls16.cpp
index f2b2ccdfe6..e2e250cf9d 100644
--- a/engines/sci/graphics/controls16.cpp
+++ b/engines/sci/graphics/controls16.cpp
@@ -280,7 +280,7 @@ int GfxControls16::getPicNotValid() {
return _screen->_picNotValid;
}
-void GfxControls16::kernelDrawButton(Common::Rect rect, reg_t obj, const char *text, int16 fontId, int16 style, bool hilite) {
+void GfxControls16::kernelDrawButton(Common::Rect rect, reg_t obj, const char *text, uint16 languageSplitter, int16 fontId, int16 style, bool hilite) {
int16 sci0EarlyPen = 0, sci0EarlyBack = 0;
if (!hilite) {
if (getSciVersion() == SCI_VERSION_0_EARLY) {
@@ -295,7 +295,7 @@ void GfxControls16::kernelDrawButton(Common::Rect rect, reg_t obj, const char *t
_paint16->frameRect(rect);
rect.grow(-2);
_ports->textGreyedOutput(!(style & SCI_CONTROLS_STYLE_ENABLED));
- _text16->Box(text, false, rect, SCI_TEXT16_ALIGNMENT_CENTER, fontId);
+ _text16->Box(text, languageSplitter, false, rect, SCI_TEXT16_ALIGNMENT_CENTER, fontId);
_ports->textGreyedOutput(false);
rect.grow(1);
if (style & SCI_CONTROLS_STYLE_SELECTED)
@@ -318,12 +318,12 @@ void GfxControls16::kernelDrawButton(Common::Rect rect, reg_t obj, const char *t
}
}
-void GfxControls16::kernelDrawText(Common::Rect rect, reg_t obj, const char *text, int16 fontId, TextAlignment alignment, int16 style, bool hilite) {
+void GfxControls16::kernelDrawText(Common::Rect rect, reg_t obj, const char *text, uint16 languageSplitter, int16 fontId, TextAlignment alignment, int16 style, bool hilite) {
if (!hilite) {
rect.grow(1);
_paint16->eraseRect(rect);
rect.grow(-1);
- _text16->Box(text, false, rect, alignment, fontId);
+ _text16->Box(text, languageSplitter, false, rect, alignment, fontId);
if (style & SCI_CONTROLS_STYLE_SELECTED) {
_paint16->frameRect(rect);
}
@@ -335,7 +335,7 @@ void GfxControls16::kernelDrawText(Common::Rect rect, reg_t obj, const char *tex
}
}
-void GfxControls16::kernelDrawTextEdit(Common::Rect rect, reg_t obj, const char *text, int16 fontId, int16 mode, int16 style, int16 cursorPos, int16 maxChars, bool hilite) {
+void GfxControls16::kernelDrawTextEdit(Common::Rect rect, reg_t obj, const char *text, uint16 languageSplitter, int16 fontId, int16 mode, int16 style, int16 cursorPos, int16 maxChars, bool hilite) {
Common::Rect textRect = rect;
uint16 oldFontId = _text16->GetFontId();
@@ -343,7 +343,7 @@ void GfxControls16::kernelDrawTextEdit(Common::Rect rect, reg_t obj, const char
_texteditCursorVisible = false;
texteditCursorErase();
_paint16->eraseRect(rect);
- _text16->Box(text, false, textRect, SCI_TEXT16_ALIGNMENT_LEFT, fontId);
+ _text16->Box(text, languageSplitter, false, textRect, SCI_TEXT16_ALIGNMENT_LEFT, fontId);
_paint16->frameRect(rect);
if (style & SCI_CONTROLS_STYLE_SELECTED) {
_text16->SetFont(fontId);
diff --git a/engines/sci/graphics/controls16.h b/engines/sci/graphics/controls16.h
index 6a70c71aae..39ffa243fb 100644
--- a/engines/sci/graphics/controls16.h
+++ b/engines/sci/graphics/controls16.h
@@ -55,9 +55,9 @@ public:
GfxControls16(SegManager *segMan, GfxPorts *ports, GfxPaint16 *paint16, GfxText16 *text16, GfxScreen *screen);
~GfxControls16();
- void kernelDrawButton(Common::Rect rect, reg_t obj, const char *text, int16 fontId, int16 style, bool hilite);
- void kernelDrawText(Common::Rect rect, reg_t obj, const char *text, int16 fontId, int16 alignment, int16 style, bool hilite);
- void kernelDrawTextEdit(Common::Rect rect, reg_t obj, const char *text, int16 fontId, int16 mode, int16 style, int16 cursorPos, int16 maxChars, bool hilite);
+ void kernelDrawButton(Common::Rect rect, reg_t obj, const char *text, uint16 languageSplitter, int16 fontId, int16 style, bool hilite);
+ void kernelDrawText(Common::Rect rect, reg_t obj, const char *text, uint16 languageSplitter, int16 fontId, int16 alignment, int16 style, bool hilite);
+ void kernelDrawTextEdit(Common::Rect rect, reg_t obj, const char *text, uint16 languageSplitter, int16 fontId, int16 mode, int16 style, int16 cursorPos, int16 maxChars, bool hilite);
void kernelDrawIcon(Common::Rect rect, reg_t obj, GuiResourceId viewId, int16 loopNo, int16 celNo, int16 priority, int16 style, bool hilite);
void kernelDrawList(Common::Rect rect, reg_t obj, int16 maxChars, int16 count, const char **entries, GuiResourceId fontId, int16 style, int16 upperPos, int16 cursorPos, bool isAlias, bool hilite);
void kernelTexteditChange(reg_t controlObject, reg_t eventObject);
diff --git a/engines/sci/graphics/cursor.cpp b/engines/sci/graphics/cursor.cpp
index 048ec1e9b9..1a58de073c 100644
--- a/engines/sci/graphics/cursor.cpp
+++ b/engines/sci/graphics/cursor.cpp
@@ -47,7 +47,7 @@ GfxCursor::GfxCursor(ResourceManager *resMan, GfxPalette *palette, GfxScreen *sc
_isVisible = true;
// center mouse cursor
- setPosition(Common::Point(_screen->getWidth() / 2, _screen->getHeight() / 2));
+ setPosition(Common::Point(_screen->getScriptWidth() / 2, _screen->getScriptHeight() / 2));
_moveZoneActive = false;
_zoomZoneActive = false;
@@ -151,14 +151,14 @@ void GfxCursor::kernelSetShape(GuiResourceId resourceId) {
colorMapping[0] = 0; // Black is hardcoded
colorMapping[1] = _screen->getColorWhite(); // White is also hardcoded
colorMapping[2] = SCI_CURSOR_SCI0_TRANSPARENCYCOLOR;
- colorMapping[3] = _palette->matchColor(170, 170, 170); // Grey
+ colorMapping[3] = _palette->matchColor(170, 170, 170) & SCI_PALETTE_MATCH_COLORMASK; // Grey
// TODO: Figure out if the grey color is hardcoded
// HACK for the magnifier cursor in LB1, fixes its color (bug #3487092)
if (g_sci->getGameId() == GID_LAURABOW && resourceId == 1)
colorMapping[3] = _screen->getColorWhite();
// HACK for Longbow cursors, fixes the shade of grey they're using (bug #3489101)
if (g_sci->getGameId() == GID_LONGBOW)
- colorMapping[3] = _palette->matchColor(223, 223, 223); // Light Grey
+ colorMapping[3] = _palette->matchColor(223, 223, 223) & SCI_PALETTE_MATCH_COLORMASK; // Light Grey
// Seek to actual data
resourceData += 4;
@@ -481,7 +481,7 @@ void GfxCursor::kernelSetPos(Common::Point pos) {
void GfxCursor::kernelMoveCursor(Common::Point pos) {
_coordAdjuster->moveCursor(pos);
- if (pos.x > _screen->getWidth() || pos.y > _screen->getHeight()) {
+ if (pos.x > _screen->getScriptWidth() || pos.y > _screen->getScriptHeight()) {
warning("attempt to place cursor at invalid coordinates (%d, %d)", pos.y, pos.x);
return;
}
diff --git a/engines/sci/graphics/font.cpp b/engines/sci/graphics/font.cpp
index e4684ff134..2268ec0459 100644
--- a/engines/sci/graphics/font.cpp
+++ b/engines/sci/graphics/font.cpp
@@ -48,8 +48,8 @@ GfxFontFromResource::GfxFontFromResource(ResourceManager *resMan, GfxScreen *scr
// filling info for every char
for (int16 i = 0; i < _numChars; i++) {
_chars[i].offset = READ_SCI32ENDIAN_UINT16(_resourceData + 6 + i * 2);
- _chars[i].w = _resourceData[_chars[i].offset];
- _chars[i].h = _resourceData[_chars[i].offset + 1];
+ _chars[i].width = _resourceData[_chars[i].offset];
+ _chars[i].height = _resourceData[_chars[i].offset + 1];
}
}
@@ -66,10 +66,10 @@ byte GfxFontFromResource::getHeight() {
return _fontHeight;
}
byte GfxFontFromResource::getCharWidth(uint16 chr) {
- return chr < _numChars ? _chars[chr].w : 0;
+ return chr < _numChars ? _chars[chr].width : 0;
}
byte GfxFontFromResource::getCharHeight(uint16 chr) {
- return chr < _numChars ? _chars[chr].h : 0;
+ return chr < _numChars ? _chars[chr].height : 0;
}
byte *GfxFontFromResource::getCharData(uint16 chr) {
return chr < _numChars ? _resourceData + _chars[chr].offset + 2 : 0;
diff --git a/engines/sci/graphics/font.h b/engines/sci/graphics/font.h
index 58b2ba4813..451261f315 100644
--- a/engines/sci/graphics/font.h
+++ b/engines/sci/graphics/font.h
@@ -71,9 +71,11 @@ private:
byte *_resourceData;
struct Charinfo {
- byte w, h;
+ byte width;
+ byte height;
int16 offset;
};
+
byte _fontHeight;
uint16 _numChars;
Charinfo *_chars;
diff --git a/engines/sci/graphics/frameout.cpp b/engines/sci/graphics/frameout.cpp
index a322eb8e61..ccc362dc37 100644
--- a/engines/sci/graphics/frameout.cpp
+++ b/engines/sci/graphics/frameout.cpp
@@ -524,6 +524,10 @@ void GfxFrameout::showVideo() {
RobotDecoder *videoDecoder = g_sci->_robotDecoder;
uint16 x = videoDecoder->getPos().x;
uint16 y = videoDecoder->getPos().y;
+ uint16 screenWidth = _screen->getWidth();
+ uint16 screenHeight = _screen->getHeight();
+ uint16 outputWidth;
+ uint16 outputHeight;
if (videoDecoder->hasDirtyPalette())
g_system->getPaletteManager()->setPalette(videoDecoder->getPalette(), 0, 256);
@@ -532,7 +536,11 @@ void GfxFrameout::showVideo() {
if (videoDecoder->needsUpdate()) {
const Graphics::Surface *frame = videoDecoder->decodeNextFrame();
if (frame) {
- g_system->copyRectToScreen(frame->getPixels(), frame->pitch, x, y, frame->w, frame->h);
+ // We need to clip here
+ // At least Phantasmagoria shows a 640x390 video on a 630x450 screen during the intro
+ outputWidth = frame->w > screenWidth ? screenWidth : frame->w;
+ outputHeight = frame->h > screenHeight ? screenHeight : frame->h;
+ g_system->copyRectToScreen(frame->getPixels(), frame->pitch, x, y, outputWidth, outputHeight);
if (videoDecoder->hasDirtyPalette())
g_system->getPaletteManager()->setPalette(videoDecoder->getPalette(), 0, 256);
@@ -782,11 +790,12 @@ void GfxFrameout::kernelFrameout() {
// TODO: For some reason, the top left nsRect coordinates get
// swapped in the GK1 inventory screen, investigate why.
- // HACK: Fix the coordinates by explicitly setting them here.
- Common::Rect objNSRect = g_sci->_gfxCompare->getNSRect(itemEntry->object);
- if (objNSRect.top == nsRect.left && objNSRect.left == nsRect.top && nsRect.top != 0 && nsRect.left != 0) {
+ // This is also needed for GK1 rooms 710 and 720 (catacombs, inner and
+ // outer circle), for handling the tiles and talking to Wolfgang.
+ // HACK: Fix the coordinates by explicitly setting them here for GK1.
+ // Also check bug #6729, for another case where this is needed.
+ if (g_sci->getGameId() == GID_GK1)
g_sci->_gfxCompare->setNSRect(itemEntry->object, nsRect);
- }
}
// Don't attempt to draw sprites that are outside the visible
diff --git a/engines/sci/graphics/paint16.cpp b/engines/sci/graphics/paint16.cpp
index b835eb92ca..f80703e14d 100644
--- a/engines/sci/graphics/paint16.cpp
+++ b/engines/sci/graphics/paint16.cpp
@@ -476,7 +476,7 @@ void GfxPaint16::kernelGraphRedrawBox(Common::Rect rect) {
#define SCI_DISPLAY_DUMMY3 117
#define SCI_DISPLAY_DONTSHOWBITS 121
-reg_t GfxPaint16::kernelDisplay(const char *text, int argc, reg_t *argv) {
+reg_t GfxPaint16::kernelDisplay(const char *text, uint16 languageSplitter, int argc, reg_t *argv) {
reg_t displayArg;
TextAlignment alignment = SCI_TEXT16_ALIGNMENT_LEFT;
int16 colorPen = -1, colorBack = -1, width = -1, bRedraw = 1;
@@ -572,7 +572,7 @@ reg_t GfxPaint16::kernelDisplay(const char *text, int argc, reg_t *argv) {
}
// now drawing the text
- _text16->Size(rect, text, -1, width);
+ _text16->Size(rect, text, languageSplitter, -1, width);
rect.moveTo(_ports->getPort()->curLeft, _ports->getPort()->curTop);
// Note: This code has been found in SCI1 middle and newer games. It was
// previously only for SCI1 late and newer, but the LSL1 interpreter contains
@@ -588,7 +588,7 @@ reg_t GfxPaint16::kernelDisplay(const char *text, int argc, reg_t *argv) {
result = bitsSave(rect, GFX_SCREEN_MASK_VISUAL);
if (colorBack != -1)
fillRect(rect, GFX_SCREEN_MASK_VISUAL, colorBack, 0, 0);
- _text16->Box(text, false, rect, alignment, -1);
+ _text16->Box(text, languageSplitter, false, rect, alignment, -1);
if (_screen->_picNotValid == 0 && bRedraw)
bitsShow(rect);
// restoring port and cursor pos
diff --git a/engines/sci/graphics/paint16.h b/engines/sci/graphics/paint16.h
index 882f311a5b..955cfdec8f 100644
--- a/engines/sci/graphics/paint16.h
+++ b/engines/sci/graphics/paint16.h
@@ -80,7 +80,7 @@ public:
void kernelGraphUpdateBox(const Common::Rect &rect, bool hiresMode);
void kernelGraphRedrawBox(Common::Rect rect);
- reg_t kernelDisplay(const char *text, int argc, reg_t *argv);
+ reg_t kernelDisplay(const char *text, uint16 languageSplitter, int argc, reg_t *argv);
reg_t kernelPortraitLoad(const Common::String &resourceName);
void kernelPortraitShow(const Common::String &resourceName, Common::Point position, uint16 resourceNum, uint16 noun, uint16 verb, uint16 cond, uint16 seq);
diff --git a/engines/sci/graphics/paint32.cpp b/engines/sci/graphics/paint32.cpp
index 7d106b5b02..a210a469f1 100644
--- a/engines/sci/graphics/paint32.cpp
+++ b/engines/sci/graphics/paint32.cpp
@@ -46,7 +46,7 @@ void GfxPaint32::fillRect(Common::Rect rect, byte color) {
Common::Rect clipRect = rect;
clipRect.clip(_screen->getWidth(), _screen->getHeight());
-
+
for (y = clipRect.top; y < clipRect.bottom; y++) {
for (x = clipRect.left; x < clipRect.right; x++) {
_screen->putPixel(x, y, GFX_SCREEN_MASK_VISUAL, color, 0, 0);
diff --git a/engines/sci/graphics/palette.cpp b/engines/sci/graphics/palette.cpp
index a3624c7959..59abef5550 100644
--- a/engines/sci/graphics/palette.cpp
+++ b/engines/sci/graphics/palette.cpp
@@ -65,14 +65,21 @@ GfxPalette::GfxPalette(ResourceManager *resMan, GfxScreen *screen)
// the real merging done in earlier games. If we use the copying over, we
// will get issues because some views have marked all colors as being used
// and those will overwrite the current palette in that case
- if (getSciVersion() < SCI_VERSION_1_1)
+ if (getSciVersion() < SCI_VERSION_1_1) {
_useMerging = true;
- else if (getSciVersion() == SCI_VERSION_1_1)
+ _use16bitColorMatch = true;
+ } else if (getSciVersion() == SCI_VERSION_1_1) {
// there are some games that use inbetween SCI1.1 interpreter, so we have
// to detect if the current game is merging or copying
_useMerging = _resMan->detectPaletteMergingSci11();
- else // SCI32
+ _use16bitColorMatch = _useMerging;
+ // Note: Laura Bow 2 floppy uses the new palette format and is detected
+ // as 8 bit color matching because of that.
+ } else {
+ // SCI32
_useMerging = false;
+ _use16bitColorMatch = false; // not verified that SCI32 uses 8-bit color matching
+ }
palVaryInit();
@@ -120,6 +127,10 @@ bool GfxPalette::isMerging() {
return _useMerging;
}
+bool GfxPalette::isUsing16bitColorMatch() {
+ return _use16bitColorMatch;
+}
+
// meant to get called only once during init of engine
void GfxPalette::setDefault() {
if (_resMan->getViewType() == kViewEga)
@@ -464,8 +475,8 @@ bool GfxPalette::merge(Palette *newPalette, bool force, bool forceRealMerge) {
// check if exact color could be matched
res = matchColor(newPalette->colors[i].r, newPalette->colors[i].g, newPalette->colors[i].b);
- if (res & 0x8000) { // exact match was found
- newPalette->mapping[i] = res & 0xFF;
+ if (res & SCI_PALETTE_MATCH_PERFECT) { // exact match was found
+ newPalette->mapping[i] = res & SCI_PALETTE_MATCH_COLORMASK;
continue;
}
@@ -486,8 +497,8 @@ bool GfxPalette::merge(Palette *newPalette, bool force, bool forceRealMerge) {
// if still no luck - set an approximate color
if (j == 256) {
- newPalette->mapping[i] = res & 0xFF;
- _sysPalette.colors[res & 0xFF].used |= 0x10;
+ newPalette->mapping[i] = res & SCI_PALETTE_MATCH_COLORMASK;
+ _sysPalette.colors[res & SCI_PALETTE_MATCH_COLORMASK].used |= 0x10;
}
}
@@ -509,29 +520,47 @@ void GfxPalette::drewPicture(GuiResourceId pictureId) {
}
}
-uint16 GfxPalette::matchColor(byte r, byte g, byte b) {
- byte found = 0xFF;
- int diff = 0x2FFFF, cdiff;
- int16 dr,dg,db;
-
- for (int i = 1; i < 255; i++) {
- if ((!_sysPalette.colors[i].used))
- continue;
- dr = _sysPalette.colors[i].r - r;
- dg = _sysPalette.colors[i].g - g;
- db = _sysPalette.colors[i].b - b;
-// minimum squares match
- cdiff = (dr*dr) + (dg*dg) + (db*db);
-// minimum sum match (Sierra's)
-// cdiff = ABS(dr) + ABS(dg) + ABS(db);
- if (cdiff < diff) {
- if (cdiff == 0)
- return i | 0x8000; // setting this flag to indicate exact match
- found = i;
- diff = cdiff;
+uint16 GfxPalette::matchColor(byte matchRed, byte matchGreen, byte matchBlue) {
+ int16 colorNr;
+ int16 differenceRed, differenceGreen, differenceBlue;
+ int16 differenceTotal = 0;
+ int16 bestDifference = 0x7FFF;
+ uint16 bestColorNr = 255;
+
+ if (_use16bitColorMatch) {
+ // used by SCI0 to SCI1, also by the first few SCI1.1 games
+ for (colorNr = 0; colorNr < 256; colorNr++) {
+ if ((!_sysPalette.colors[colorNr].used))
+ continue;
+ differenceRed = ABS(_sysPalette.colors[colorNr].r - matchRed);
+ differenceGreen = ABS(_sysPalette.colors[colorNr].g - matchGreen);
+ differenceBlue = ABS(_sysPalette.colors[colorNr].b - matchBlue);
+ differenceTotal = differenceRed + differenceGreen + differenceBlue;
+ if (differenceTotal <= bestDifference) {
+ bestDifference = differenceTotal;
+ bestColorNr = colorNr;
+ }
+ }
+ } else {
+ // SCI1.1, starting with QfG3 introduced a bug in the matching code
+ // we have to implement it as well, otherwise some colors will be "wrong" in comparison to the original interpreter
+ // See Space Quest 5 bug #6455
+ for (colorNr = 0; colorNr < 256; colorNr++) {
+ if ((!_sysPalette.colors[colorNr].used))
+ continue;
+ differenceRed = (uint8)ABS<int8>(_sysPalette.colors[colorNr].r - matchRed);
+ differenceGreen = (uint8)ABS<int8>(_sysPalette.colors[colorNr].g - matchGreen);
+ differenceBlue = (uint8)ABS<int8>(_sysPalette.colors[colorNr].b - matchBlue);
+ differenceTotal = differenceRed + differenceGreen + differenceBlue;
+ if (differenceTotal <= bestDifference) {
+ bestDifference = differenceTotal;
+ bestColorNr = colorNr;
+ }
}
}
- return found;
+ if (differenceTotal == 0) // original interpreter does not do this, instead it does 2 calls for merges in the worst case
+ return bestColorNr | SCI_PALETTE_MATCH_PERFECT; // we set this flag, so that we can optimize during palette merge
+ return bestColorNr;
}
void GfxPalette::getSys(Palette *pal) {
@@ -621,7 +650,7 @@ void GfxPalette::kernelSetIntensity(uint16 fromColor, uint16 toColor, uint16 int
}
int16 GfxPalette::kernelFindColor(uint16 r, uint16 g, uint16 b) {
- return matchColor(r, g, b) & 0xFF;
+ return matchColor(r, g, b) & SCI_PALETTE_MATCH_COLORMASK;
}
// Returns true, if palette got changed
diff --git a/engines/sci/graphics/palette.h b/engines/sci/graphics/palette.h
index 347695deb8..500a45eccf 100644
--- a/engines/sci/graphics/palette.h
+++ b/engines/sci/graphics/palette.h
@@ -31,6 +31,10 @@ namespace Sci {
class ResourceManager;
class GfxScreen;
+// Special flag implemented by us for optimization in palette merge
+#define SCI_PALETTE_MATCH_PERFECT 0x8000
+#define SCI_PALETTE_MATCH_COLORMASK 0xFF
+
enum ColorRemappingType {
kRemappingNone = 0,
kRemappingByRange = 1,
@@ -46,6 +50,7 @@ public:
~GfxPalette();
bool isMerging();
+ bool isUsing16bitColorMatch();
void setDefault();
void createFromData(byte *data, int bytesLeft, Palette *paletteOut);
@@ -124,6 +129,7 @@ private:
bool _sysPaletteChanged;
bool _useMerging;
+ bool _use16bitColorMatch;
Common::Array<PalSchedule> _schedules;
diff --git a/engines/sci/graphics/picture.cpp b/engines/sci/graphics/picture.cpp
index 434a490109..d7ef84dc1e 100644
--- a/engines/sci/graphics/picture.cpp
+++ b/engines/sci/graphics/picture.cpp
@@ -88,10 +88,13 @@ void GfxPicture::draw(int16 animationNr, bool mirroredFlag, bool addToFlag, int1
}
void GfxPicture::reset() {
+ int16 startY = _ports->getPort()->top;
+ int16 startX = 0;
int16 x, y;
- for (y = _ports->getPort()->top; y < _screen->getHeight(); y++) {
- for (x = 0; x < _screen->getWidth(); x++) {
- _screen->putPixel(x, y, GFX_SCREEN_MASK_ALL, 255, 0, 0);
+ _screen->vectorAdjustCoordinate(&startX, &startY);
+ for (y = startY; y < _screen->getHeight(); y++) {
+ for (x = startX; x < _screen->getWidth(); x++) {
+ _screen->vectorPutPixel(x, y, GFX_SCREEN_MASK_ALL, 255, 0, 0);
}
}
}
@@ -246,7 +249,7 @@ void GfxPicture::drawCelData(byte *inbuffer, int size, int headerPos, int rlePos
int16 y, lastY, x, leftX, rightX;
int pixelCount;
uint16 width, height;
-
+
// if the picture is not an overlay and we are also not in EGA mode, use priority 0
if (!isEGA && !_addToFlag)
priority = 0;
@@ -362,7 +365,7 @@ void GfxPicture::drawCelData(byte *inbuffer, int size, int headerPos, int rlePos
ptr = celBitmap;
ptr += skipCelBitmapPixels;
ptr += skipCelBitmapLines * width;
-
+
if ((!isEGA) || (priority < 16)) {
// VGA + EGA, EGA only checks priority, when given priority is below 16
if (!_mirroredFlag) {
@@ -482,6 +485,8 @@ enum {
PIC_OPX_VGA_PRIORITY_TABLE_EXPLICIT = 4
};
+//#define DEBUG_PICTURE_DRAW 1
+
#ifdef DEBUG_PICTURE_DRAW
const char *picOpcodeNames[] = {
"Set color",
@@ -589,6 +594,9 @@ void GfxPicture::drawVectorData(byte *data, int dataSize) {
while (curPos < dataSize) {
#ifdef DEBUG_PICTURE_DRAW
debug("Picture op: %X (%s) at %d", data[curPos], picOpcodeNames[data[curPos] - 0xF0], curPos);
+ _screen->copyToScreen();
+ g_system->updateScreen();
+ g_system->delayMillis(400);
#endif
switch (pic_op = data[curPos++]) {
case PIC_OP_SET_COLOR:
@@ -934,17 +942,17 @@ void GfxPicture::vectorFloodFill(int16 x, int16 y, byte color, byte priority, by
Common::Point p, p1;
byte screenMask = _screen->getDrawingMask(color, priority, control);
byte matchedMask, matchMask;
- int16 w, e, a_set, b_set;
bool isEGA = (_resMan->getViewType() == kViewEga);
p.x = x + curPort->left;
p.y = y + curPort->top;
- stack.push(p);
- byte searchColor = _screen->getVisual(p.x, p.y);
- byte searchPriority = _screen->getPriority(p.x, p.y);
- byte searchControl = _screen->getControl(p.x, p.y);
+ _screen->vectorAdjustCoordinate(&p.x, &p.y);
+
+ byte searchColor = _screen->vectorGetVisual(p.x, p.y);
+ byte searchPriority = _screen->vectorGetPriority(p.x, p.y);
+ byte searchControl = _screen->vectorGetControl(p.x, p.y);
if (isEGA) {
// In EGA games a pixel in the framebuffer is only 4 bits. We store
@@ -991,22 +999,31 @@ void GfxPicture::vectorFloodFill(int16 x, int16 y, byte color, byte priority, by
}
// hard borders for filling
- int l = curPort->rect.left + curPort->left;
- int t = curPort->rect.top + curPort->top;
- int r = curPort->rect.right + curPort->left - 1;
- int b = curPort->rect.bottom + curPort->top - 1;
+ int16 borderLeft = curPort->rect.left + curPort->left;
+ int16 borderTop = curPort->rect.top + curPort->top;
+ int16 borderRight = curPort->rect.right + curPort->left - 1;
+ int16 borderBottom = curPort->rect.bottom + curPort->top - 1;
+ int16 curToLeft, curToRight, a_set, b_set;
+
+ // Translate coordinates, if required (needed for Macintosh 480x300)
+ _screen->vectorAdjustCoordinate(&borderLeft, &borderTop);
+ _screen->vectorAdjustCoordinate(&borderRight, &borderBottom);
+ //return;
+
+ stack.push(p);
+
while (stack.size()) {
p = stack.pop();
- if ((matchedMask = _screen->isFillMatch(p.x, p.y, matchMask, searchColor, searchPriority, searchControl, isEGA)) == 0) // already filled
+ if ((matchedMask = _screen->vectorIsFillMatch(p.x, p.y, matchMask, searchColor, searchPriority, searchControl, isEGA)) == 0) // already filled
continue;
- _screen->putPixel(p.x, p.y, screenMask, color, priority, control);
- w = p.x;
- e = p.x;
+ _screen->vectorPutPixel(p.x, p.y, screenMask, color, priority, control);
+ curToLeft = p.x;
+ curToRight = p.x;
// moving west and east pointers as long as there is a matching color to fill
- while (w > l && (matchedMask = _screen->isFillMatch(w - 1, p.y, matchMask, searchColor, searchPriority, searchControl, isEGA)))
- _screen->putPixel(--w, p.y, screenMask, color, priority, control);
- while (e < r && (matchedMask = _screen->isFillMatch(e + 1, p.y, matchMask, searchColor, searchPriority, searchControl, isEGA)))
- _screen->putPixel(++e, p.y, screenMask, color, priority, control);
+ while (curToLeft > borderLeft && (matchedMask = _screen->vectorIsFillMatch(curToLeft - 1, p.y, matchMask, searchColor, searchPriority, searchControl, isEGA)))
+ _screen->vectorPutPixel(--curToLeft, p.y, screenMask, color, priority, control);
+ while (curToRight < borderRight && (matchedMask = _screen->vectorIsFillMatch(curToRight + 1, p.y, matchMask, searchColor, searchPriority, searchControl, isEGA)))
+ _screen->vectorPutPixel(++curToRight, p.y, screenMask, color, priority, control);
#if 0
// debug code for floodfill
_screen->copyToScreen();
@@ -1015,10 +1032,10 @@ void GfxPicture::vectorFloodFill(int16 x, int16 y, byte color, byte priority, by
#endif
// checking lines above and below for possible flood targets
a_set = b_set = 0;
- while (w <= e) {
- if (p.y > t && (matchedMask = _screen->isFillMatch(w, p.y - 1, matchMask, searchColor, searchPriority, searchControl, isEGA))) { // one line above
+ while (curToLeft <= curToRight) {
+ if (p.y > borderTop && (matchedMask = _screen->vectorIsFillMatch(curToLeft, p.y - 1, matchMask, searchColor, searchPriority, searchControl, isEGA))) { // one line above
if (a_set == 0) {
- p1.x = w;
+ p1.x = curToLeft;
p1.y = p.y - 1;
stack.push(p1);
a_set = 1;
@@ -1026,16 +1043,16 @@ void GfxPicture::vectorFloodFill(int16 x, int16 y, byte color, byte priority, by
} else
a_set = 0;
- if (p.y < b && (matchedMask = _screen->isFillMatch(w, p.y + 1, matchMask, searchColor, searchPriority, searchControl, isEGA))) { // one line below
+ if (p.y < borderBottom && (matchedMask = _screen->vectorIsFillMatch(curToLeft, p.y + 1, matchMask, searchColor, searchPriority, searchControl, isEGA))) { // one line below
if (b_set == 0) {
- p1.x = w;
+ p1.x = curToLeft;
p1.y = p.y + 1;
stack.push(p1);
b_set = 1;
}
} else
b_set = 0;
- w++;
+ curToLeft++;
}
}
}
@@ -1173,7 +1190,7 @@ void GfxPicture::vectorPatternBox(Common::Rect box, byte color, byte prio, byte
for (y = box.top; y < box.bottom; y++) {
for (x = box.left; x < box.right; x++) {
- _screen->putPixel(x, y, flag, color, prio, control);
+ _screen->vectorPutPixel(x, y, flag, color, prio, control);
}
}
}
@@ -1186,7 +1203,7 @@ void GfxPicture::vectorPatternTexturedBox(Common::Rect box, byte color, byte pri
for (y = box.top; y < box.bottom; y++) {
for (x = box.left; x < box.right; x++) {
if (*textureData) {
- _screen->putPixel(x, y, flag, color, prio, control);
+ _screen->vectorPutPixel(x, y, flag, color, prio, control);
}
textureData++;
}
@@ -1203,7 +1220,7 @@ void GfxPicture::vectorPatternCircle(Common::Rect box, byte size, byte color, by
for (y = box.top; y < box.bottom; y++) {
for (x = box.left; x < box.right; x++) {
if (bitmap & 1) {
- _screen->putPixel(x, y, flag, color, prio, control);
+ _screen->vectorPutPixel(x, y, flag, color, prio, control);
}
bitNo++;
if (bitNo == 8) {
@@ -1222,12 +1239,12 @@ void GfxPicture::vectorPatternTexturedCircle(Common::Rect box, byte size, byte c
byte bitNo = 0;
const bool *textureData = &vectorPatternTextures[vectorPatternTextureOffset[texture]];
int y, x;
-
+
for (y = box.top; y < box.bottom; y++) {
for (x = box.left; x < box.right; x++) {
if (bitmap & 1) {
if (*textureData) {
- _screen->putPixel(x, y, flag, color, prio, control);
+ _screen->vectorPutPixel(x, y, flag, color, prio, control);
}
textureData++;
}
@@ -1252,7 +1269,10 @@ void GfxPicture::vectorPattern(int16 x, int16 y, byte color, byte priority, byte
rect.top = y; rect.left = x;
rect.setHeight((size*2)+1); rect.setWidth((size*2)+2);
_ports->offsetRect(rect);
- rect.clip(_screen->getWidth(), _screen->getHeight());
+ rect.clip(_screen->getScriptWidth(), _screen->getScriptHeight());
+
+ _screen->vectorAdjustCoordinate(&rect.left, &rect.top);
+ _screen->vectorAdjustCoordinate(&rect.right, &rect.bottom);
if (code & SCI_PATTERN_CODE_RECTANGLE) {
// Rectangle
diff --git a/engines/sci/graphics/portrait.cpp b/engines/sci/graphics/portrait.cpp
index 488450485d..668de616fb 100644
--- a/engines/sci/graphics/portrait.cpp
+++ b/engines/sci/graphics/portrait.cpp
@@ -134,34 +134,34 @@ void Portrait::init() {
// raw lip-sync ID table follows
uint32 lipSyncIDTableSize;
-
+
lipSyncIDTableSize = READ_LE_UINT32(data);
data += 4;
assert( lipSyncIDTableSize == (_lipSyncIDCount * 4) );
_lipSyncIDTable = data;
data += lipSyncIDTableSize;
-
+
// raw lip-sync frame table follows
uint32 lipSyncDataTableSize;
uint32 lipSyncDataTableLastOffset;
byte lipSyncData;
uint16 lipSyncDataNr;
uint16 lipSyncCurOffset;
-
+
lipSyncDataTableSize = READ_LE_UINT32(data);
data += 4;
assert( lipSyncDataTableSize == 0x220 ); // always this size, just a safety-check
-
+
_lipSyncData = data;
lipSyncDataTableLastOffset = lipSyncDataTableSize - 1;
_lipSyncDataOffsetTable = new uint16[ _lipSyncIDCount ];
-
+
lipSyncDataNr = 0;
lipSyncCurOffset = 0;
while ( (lipSyncCurOffset < lipSyncDataTableSize) && (lipSyncDataNr < _lipSyncIDCount) ) {
// We are currently at the start of ID-frame data
_lipSyncDataOffsetTable[lipSyncDataNr] = lipSyncCurOffset;
-
+
// Look for end of ID-frame data
lipSyncData = *data++; lipSyncCurOffset++;
while ( (lipSyncData != 0xFF) && (lipSyncCurOffset < lipSyncDataTableLastOffset) ) {
@@ -195,7 +195,7 @@ void Portrait::doit(Common::Point position, uint16 resourceId, uint16 noun, uint
Resource *syncResource = _resMan->findResource(syncResourceId, true);
uint syncOffset = 0;
#endif
-
+
#ifdef DEBUG_PORTRAIT
// prints out the current lip sync ASCII data
char debugPrint[4000];
@@ -246,7 +246,7 @@ void Portrait::doit(Common::Point position, uint16 resourceId, uint16 noun, uint
warning("kPortrait: no rave resource %d %X", resourceId, audioNumber);
return;
}
-
+
// Do animation depending on rave resource till audio is done playing
int16 raveTicks;
uint16 raveID;
@@ -264,7 +264,7 @@ void Portrait::doit(Common::Point position, uint16 resourceId, uint16 noun, uint
raveTicks = raveGetTicks(raveResource, &raveOffset);
if (raveTicks < 0)
break;
-
+
// get lipSyncID
raveID = raveGetID(raveResource, &raveOffset);
if (raveID) {
@@ -272,7 +272,7 @@ void Portrait::doit(Common::Point position, uint16 resourceId, uint16 noun, uint
} else {
raveLipSyncData = NULL;
}
-
+
timerPosition += raveTicks;
// Wait till syncTime passed, then show specific animation bitmap
@@ -287,7 +287,7 @@ void Portrait::doit(Common::Point position, uint16 resourceId, uint16 noun, uint
curPosition = _audio->getAudioPosition();
} while ((curPosition != -1) && (curPosition < timerPosition) && (!userAbort));
}
-
+
if (raveLipSyncData) {
// lip sync data is
// Tick:Byte, Bitmap-Nr:BYTE
@@ -308,7 +308,7 @@ void Portrait::doit(Common::Point position, uint16 resourceId, uint16 noun, uint
} while ((curPosition != -1) && (curPosition < timerPositionWithin) && (!userAbort));
raveLipSyncBitmapNr = *raveLipSyncData++;
-
+
// bitmap nr within sync data is base 1, we need base 0
raveLipSyncBitmapNr--;
@@ -319,7 +319,7 @@ void Portrait::doit(Common::Point position, uint16 resourceId, uint16 noun, uint
} else {
warning("kPortrait: rave lip sync data tried to draw non-existent bitmap %d", raveLipSyncBitmapNr);
}
-
+
raveLipSyncTicks = *raveLipSyncData++;
}
}
@@ -372,7 +372,7 @@ void Portrait::doit(Common::Point position, uint16 resourceId, uint16 noun, uint
}
}
#endif
-
+
// Reset the portrait bitmap to "closed mouth" state (rave.dll seems to do the same)
drawBitmap(0);
bitsShow();
@@ -393,10 +393,10 @@ int16 Portrait::raveGetTicks(Resource *resource, uint *offset) {
byte *curData = resource->data + curOffset;
byte curByte;
uint16 curValue = 0;
-
+
if (curOffset >= resource->size)
return -1;
-
+
while (curOffset < resource->size) {
curByte = *curData++; curOffset++;
if ( curByte == ' ' )
@@ -418,7 +418,7 @@ uint16 Portrait::raveGetID(Resource *resource, uint *offset) {
byte *curData = resource->data + curOffset;
byte curByte = 0;
uint16 curValue = 0;
-
+
while (curOffset < resource->size) {
curByte = *curData++; curOffset++;
if ( curByte == ' ' )
@@ -429,7 +429,7 @@ uint16 Portrait::raveGetID(Resource *resource, uint *offset) {
curValue |= curByte;
}
}
-
+
*offset = curOffset;
return curValue;
}
@@ -440,17 +440,17 @@ byte *Portrait::raveGetLipSyncData(uint16 raveID) {
byte *lipSyncIDPtr = _lipSyncIDTable;
byte lipSyncIDByte1, lipSyncIDByte2;
uint16 lipSyncID;
-
+
lipSyncIDPtr++; // skip over first byte
while (lipSyncIDNr < _lipSyncIDCount) {
lipSyncIDByte1 = *lipSyncIDPtr++;
lipSyncIDByte2 = *lipSyncIDPtr++;
lipSyncID = ( lipSyncIDByte1 << 8 ) | lipSyncIDByte2;
-
+
if ( lipSyncID == raveID ) {
return _lipSyncData + _lipSyncDataOffsetTable[lipSyncIDNr];
}
-
+
lipSyncIDNr++;
lipSyncIDPtr += 2; // ID is every 4 bytes
}
diff --git a/engines/sci/graphics/portrait.h b/engines/sci/graphics/portrait.h
index 877b253bcf..e0888daa86 100644
--- a/engines/sci/graphics/portrait.h
+++ b/engines/sci/graphics/portrait.h
@@ -72,7 +72,7 @@ private:
Common::String _resourceName;
byte *_fileData;
-
+
uint32 _lipSyncIDCount;
byte *_lipSyncIDTable;
diff --git a/engines/sci/graphics/ports.cpp b/engines/sci/graphics/ports.cpp
index 56c63a7b12..bcc991081e 100644
--- a/engines/sci/graphics/ports.cpp
+++ b/engines/sci/graphics/ports.cpp
@@ -63,10 +63,10 @@ void GfxPorts::init(bool usesOldGfxFunctions, GfxPaint16 *paint16, GfxText16 *te
openPort(_menuPort);
setPort(_menuPort);
_text16->SetFont(0);
- _menuPort->rect = Common::Rect(0, 0, _screen->getWidth(), _screen->getHeight());
- _menuBarRect = Common::Rect(0, 0, _screen->getWidth(), 9);
- _menuRect = Common::Rect(0, 0, _screen->getWidth(), 10);
- _menuLine = Common::Rect(0, 9, _screen->getWidth(), 10);
+ _menuPort->rect = Common::Rect(0, 0, _screen->getScriptWidth(), _screen->getScriptHeight());
+ _menuBarRect = Common::Rect(0, 0, _screen->getScriptWidth(), 9);
+ _menuRect = Common::Rect(0, 0, _screen->getScriptWidth(), 10);
+ _menuLine = Common::Rect(0, 9, _screen->getScriptWidth(), 10);
_wmgrPort = new Port(1);
_windowsById.resize(2);
@@ -122,13 +122,13 @@ void GfxPorts::init(bool usesOldGfxFunctions, GfxPaint16 *paint16, GfxText16 *te
} else {
_wmgrPort->rect.bottom = _screen->getHeight();
}
- _wmgrPort->rect.right = _screen->getWidth();
+ _wmgrPort->rect.right = _screen->getScriptWidth();
_wmgrPort->rect.moveTo(0, 0);
_wmgrPort->curTop = 0;
_wmgrPort->curLeft = 0;
_windowList.push_front(_wmgrPort);
- _picWind = addWindow(Common::Rect(0, offTop, _screen->getWidth(), _screen->getHeight()), 0, 0, SCI_WINDOWMGR_STYLE_TRANSPARENT | SCI_WINDOWMGR_STYLE_NOFRAME, 0, true);
+ _picWind = addWindow(Common::Rect(0, offTop, _screen->getScriptWidth(), _screen->getScriptHeight()), 0, 0, SCI_WINDOWMGR_STYLE_TRANSPARENT | SCI_WINDOWMGR_STYLE_NOFRAME, 0, true);
// For SCI0 games till kq4 (.502 - not including) we set _picWind top to offTop instead
// Because of the menu/status bar
if (_usesOldGfxFunctions)
@@ -321,13 +321,13 @@ Window *GfxPorts::addWindow(const Common::Rect &dims, const Common::Rect *restor
// their interpreter even in the newer VGA games.
r.left = r.left & 0xFFFE;
- if (r.width() > _screen->getWidth()) {
+ if (r.width() > _screen->getScriptWidth()) {
// We get invalid dimensions at least at the end of sq3 (script bug!).
// Same happens very often in lsl5, sierra sci didnt fix it but it looked awful.
// Also happens frequently in the demo of GK1.
warning("Fixing too large window, left: %d, right: %d", dims.left, dims.right);
r.left = 0;
- r.right = _screen->getWidth() - 1;
+ r.right = _screen->getScriptWidth() - 1;
if ((style != _styleUser) && !(style & SCI_WINDOWMGR_STYLE_NOFRAME))
r.right--;
}
diff --git a/engines/sci/graphics/screen.cpp b/engines/sci/graphics/screen.cpp
index c5c94d7991..8b0e76332f 100644
--- a/engines/sci/graphics/screen.cpp
+++ b/engines/sci/graphics/screen.cpp
@@ -37,7 +37,15 @@ GfxScreen::GfxScreen(ResourceManager *resMan) : _resMan(resMan) {
// Scale the screen, if needed
_upscaledHires = GFX_SCREEN_UPSCALED_DISABLED;
-
+
+ // we default to scripts running at 320x200
+ _scriptWidth = 320;
+ _scriptHeight = 200;
+ _width = 0;
+ _height = 0;
+ _displayWidth = 0;
+ _displayHeight = 0;
+
// King's Quest 6 and Gabriel Knight 1 have hires content, gk1/cd was able
// to provide that under DOS as well, but as gk1/floppy does support
// upscaled hires scriptswise, but doesn't actually have the hires content
@@ -50,10 +58,33 @@ GfxScreen::GfxScreen(ResourceManager *resMan) : _resMan(resMan) {
_upscaledHires = GFX_SCREEN_UPSCALED_640x480;
#endif
}
+
+ // Japanese versions of games use hi-res font on upscaled version of the game.
+ if ((g_sci->getLanguage() == Common::JA_JPN) && (getSciVersion() <= SCI_VERSION_1_1))
+ _upscaledHires = GFX_SCREEN_UPSCALED_640x400;
+ // Macintosh SCI0 games used 480x300, while the scripts were running at 320x200
if (g_sci->getPlatform() == Common::kPlatformMacintosh) {
- if (getSciVersion() <= SCI_VERSION_01)
+ if (getSciVersion() <= SCI_VERSION_01) {
_upscaledHires = GFX_SCREEN_UPSCALED_480x300;
+ _width = 480;
+ _height = 300; // regular visual, priority and control map are 480x300 (this is different than other upscaled SCI games)
+ }
+
+ // Some Mac SCI1/1.1 games only take up 190 rows and do not
+ // have the menu bar.
+ // TODO: Verify that LSL1 and LSL5 use height 190
+ switch (g_sci->getGameId()) {
+ case GID_FREDDYPHARKAS:
+ case GID_KQ5:
+ case GID_KQ6:
+ case GID_LSL1:
+ case GID_LSL5:
+ case GID_SQ1:
+ _width = 190;
+ default:
+ break;
+ }
}
#ifdef ENABLE_SCI32
@@ -65,76 +96,77 @@ GfxScreen::GfxScreen(ResourceManager *resMan) : _resMan(resMan) {
#endif
if (_resMan->detectHires()) {
- _width = 640;
- _pitch = 640;
- _height = 480;
- } else {
- _width = 320;
- _pitch = 320;
- _height = getLowResScreenHeight();
+ _scriptWidth = 640;
+ _scriptHeight = 480;
}
#ifdef ENABLE_SCI32
- // Phantasmagoria 1 sets a window area of 630x450
+ // Phantasmagoria 1 effectively outputs 630x450
+ // Coordinate translation has to use this resolution as well
if (g_sci->getGameId() == GID_PHANTASMAGORIA) {
_width = 630;
_height = 450;
}
#endif
- // Japanese versions of games use hi-res font on upscaled version of the game.
- if ((g_sci->getLanguage() == Common::JA_JPN) && (getSciVersion() <= SCI_VERSION_1_1))
- _upscaledHires = GFX_SCREEN_UPSCALED_640x400;
+ // if not yet set, set those to script-width/height
+ if (!_width)
+ _width = _scriptWidth;
+ if (!_height)
+ _height = _scriptHeight;
- _pixels = _pitch * _height;
+ _pixels = _width * _height;
switch (_upscaledHires) {
case GFX_SCREEN_UPSCALED_480x300:
// Space Quest 3, Hoyle 1+2 on MAC use this one
- // TODO: Sierra's upscaling worked differently. We need to figure out the exact algo
_displayWidth = 480;
_displayHeight = 300;
- for (int i = 0; i <= _height; i++)
+ for (int i = 0; i <= _scriptHeight; i++)
_upscaledHeightMapping[i] = (i * 3) >> 1;
- for (int i = 0; i <= _width; i++)
+ for (int i = 0; i <= _scriptWidth; i++)
_upscaledWidthMapping[i] = (i * 3) >> 1;
break;
case GFX_SCREEN_UPSCALED_640x400:
// Police Quest 2 and Quest For Glory on PC9801 (Japanese)
_displayWidth = 640;
_displayHeight = 400;
- for (int i = 0; i <= _height; i++)
+ for (int i = 0; i <= _scriptHeight; i++)
_upscaledHeightMapping[i] = i * 2;
- for (int i = 0; i <= _width; i++)
+ for (int i = 0; i <= _scriptWidth; i++)
_upscaledWidthMapping[i] = i * 2;
break;
case GFX_SCREEN_UPSCALED_640x440:
// used by King's Quest 6 on Windows
_displayWidth = 640;
_displayHeight = 440;
- for (int i = 0; i <= _height; i++)
+ for (int i = 0; i <= _scriptHeight; i++)
_upscaledHeightMapping[i] = (i * 11) / 5;
- for (int i = 0; i <= _width; i++)
+ for (int i = 0; i <= _scriptWidth; i++)
_upscaledWidthMapping[i] = i * 2;
break;
case GFX_SCREEN_UPSCALED_640x480:
// Gabriel Knight 1 (VESA, Mac)
_displayWidth = 640;
_displayHeight = 480;
- for (int i = 0; i <= _height; i++)
+ for (int i = 0; i <= _scriptHeight; i++)
_upscaledHeightMapping[i] = (i * 12) / 5;
- for (int i = 0; i <= _width; i++)
+ for (int i = 0; i <= _scriptWidth; i++)
_upscaledWidthMapping[i] = i * 2;
break;
default:
- _displayWidth = _pitch;
- _displayHeight = _height;
+ if (!_displayWidth)
+ _displayWidth = _width;
+ if (!_displayHeight)
+ _displayHeight = _height;
memset(&_upscaledHeightMapping, 0, sizeof(_upscaledHeightMapping) );
memset(&_upscaledWidthMapping, 0, sizeof(_upscaledWidthMapping) );
break;
}
_displayPixels = _displayWidth * _displayHeight;
+
+ // Allocate visual, priority, control and display screen
_visualScreen = (byte *)calloc(_pixels, 1);
_priorityScreen = (byte *)calloc(_pixels, 1);
_controlScreen = (byte *)calloc(_pixels, 1);
@@ -179,6 +211,34 @@ GfxScreen::GfxScreen(ResourceManager *resMan) : _resMan(resMan) {
error("Unknown SCI1.1 Mac game");
} else
initGraphics(_displayWidth, _displayHeight, _displayWidth > 320);
+
+ // Initialize code pointers
+ _vectorAdjustCoordinatePtr = &GfxScreen::vectorAdjustCoordinateNOP;
+ _vectorAdjustLineCoordinatesPtr = &GfxScreen::vectorAdjustLineCoordinatesNOP;
+ _vectorIsFillMatchPtr = &GfxScreen::vectorIsFillMatchNormal;
+ _vectorPutPixelPtr = &GfxScreen::putPixelNormal;
+ _vectorPutLinePixelPtr = &GfxScreen::putPixel;
+ _vectorGetPixelPtr = &GfxScreen::getPixelNormal;
+ _putPixelPtr = &GfxScreen::putPixelNormal;
+ _getPixelPtr = &GfxScreen::getPixelNormal;
+
+ switch (_upscaledHires) {
+ case GFX_SCREEN_UPSCALED_480x300:
+ _vectorAdjustCoordinatePtr = &GfxScreen::vectorAdjustCoordinate480x300Mac;
+ _vectorAdjustLineCoordinatesPtr = &GfxScreen::vectorAdjustLineCoordinates480x300Mac;
+ // vectorPutPixel -> we already adjust coordinates for vector code, that's why we can set pixels directly
+ // vectorGetPixel -> see vectorPutPixel
+ _vectorPutLinePixelPtr = &GfxScreen::vectorPutLinePixel480x300Mac;
+ _putPixelPtr = &GfxScreen::putPixelAllUpscaled;
+ _getPixelPtr = &GfxScreen::getPixelUpscaled;
+ break;
+ case GFX_SCREEN_UPSCALED_640x400:
+ case GFX_SCREEN_UPSCALED_640x440:
+ case GFX_SCREEN_UPSCALED_640x480:
+ _vectorPutPixelPtr = &GfxScreen::putPixelDisplayUpscaled;
+ _putPixelPtr = &GfxScreen::putPixelDisplayUpscaled;
+ break;
+ }
}
GfxScreen::~GfxScreen() {
@@ -232,7 +292,7 @@ void GfxScreen::copyRectToScreen(const Common::Rect &rect, int16 x, int16 y) {
} else {
int rectHeight = _upscaledHeightMapping[rect.bottom] - _upscaledHeightMapping[rect.top];
int rectWidth = _upscaledWidthMapping[rect.right] - _upscaledWidthMapping[rect.left];
-
+
g_system->copyRectToScreen(_activeScreen + _upscaledHeightMapping[rect.top] * _displayWidth + _upscaledWidthMapping[rect.left], _displayWidth, _upscaledWidthMapping[x], _upscaledHeightMapping[y], rectWidth, rectHeight);
}
}
@@ -248,43 +308,162 @@ byte GfxScreen::getDrawingMask(byte color, byte prio, byte control) {
return flag;
}
-void GfxScreen::putPixel(int x, int y, byte drawMask, byte color, byte priority, byte control) {
- int offset = y * _pitch + x;
+void GfxScreen::vectorAdjustCoordinateNOP(int16 *x, int16 *y) {
+}
- if (drawMask & GFX_SCREEN_MASK_VISUAL) {
- _visualScreen[offset] = color;
- if (!_upscaledHires) {
- _displayScreen[offset] = color;
+void GfxScreen::vectorAdjustCoordinate480x300Mac(int16 *x, int16 *y) {
+ *x = _upscaledWidthMapping[*x];
+ *y = _upscaledHeightMapping[*y];
+}
+
+void GfxScreen::vectorAdjustLineCoordinatesNOP(int16 *left, int16 *top, int16 *right, int16 *bottom, byte drawMask, byte color, byte priority, byte control) {
+}
+
+void GfxScreen::vectorAdjustLineCoordinates480x300Mac(int16 *left, int16 *top, int16 *right, int16 *bottom, byte drawMask, byte color, byte priority, byte control) {
+ int16 displayLeft = _upscaledWidthMapping[*left];
+ int16 displayRight = _upscaledWidthMapping[*right];
+ int16 displayTop = _upscaledHeightMapping[*top];
+ int16 displayBottom = _upscaledHeightMapping[*bottom];
+
+ if (displayLeft < displayRight) {
+ // one more pixel to the left, one more pixel to the right
+ if (displayLeft > 0)
+ vectorPutLinePixel(displayLeft - 1, displayTop, drawMask, color, priority, control);
+ vectorPutLinePixel(displayRight + 1, displayBottom, drawMask, color, priority, control);
+ } else if (displayLeft > displayRight) {
+ if (displayRight > 0)
+ vectorPutLinePixel(displayRight - 1, displayBottom, drawMask, color, priority, control);
+ vectorPutLinePixel(displayLeft + 1, displayTop, drawMask, color, priority, control);
+ }
+ *left = displayLeft;
+ *top = displayTop;
+ *right = displayRight;
+ *bottom = displayBottom;
+}
+
+byte GfxScreen::vectorIsFillMatchNormal(int16 x, int16 y, byte screenMask, byte checkForColor, byte checkForPriority, byte checkForControl, bool isEGA) {
+ int offset = y * _width + x;
+ byte match = 0;
+
+ if (screenMask & GFX_SCREEN_MASK_VISUAL) {
+ if (!isEGA) {
+ if (*(_visualScreen + offset) == checkForColor)
+ match |= GFX_SCREEN_MASK_VISUAL;
} else {
- putScaledPixelOnDisplay(x, y, color);
+ // In EGA games a pixel in the framebuffer is only 4 bits. We store
+ // a full byte per pixel to allow undithering, but when comparing
+ // pixels for flood-fill purposes, we should only compare the
+ // visible color of a pixel.
+
+ byte EGAcolor = *(_visualScreen + offset);
+ if ((x ^ y) & 1)
+ EGAcolor = (EGAcolor ^ (EGAcolor >> 4)) & 0x0F;
+ else
+ EGAcolor = EGAcolor & 0x0F;
+ if (EGAcolor == checkForColor)
+ match |= GFX_SCREEN_MASK_VISUAL;
}
}
+ if ((screenMask & GFX_SCREEN_MASK_PRIORITY) && *(_priorityScreen + offset) == checkForPriority)
+ match |= GFX_SCREEN_MASK_PRIORITY;
+ if ((screenMask & GFX_SCREEN_MASK_CONTROL) && *(_controlScreen + offset) == checkForControl)
+ match |= GFX_SCREEN_MASK_CONTROL;
+ return match;
+}
+
+// Special 480x300 Mac putPixel for vector line drawing, also draws an additional pixel below the actual one
+void GfxScreen::vectorPutLinePixel480x300Mac(int16 x, int16 y, byte drawMask, byte color, byte priority, byte control) {
+ int offset = y * _width + x;
+
+ if (drawMask & GFX_SCREEN_MASK_VISUAL) {
+ _visualScreen[offset] = color;
+ _visualScreen[offset + _width] = color;
+ _displayScreen[offset] = color;
+ // also set pixel below actual pixel
+ _displayScreen[offset + _displayWidth] = color;
+ }
+ if (drawMask & GFX_SCREEN_MASK_PRIORITY) {
+ _priorityScreen[offset] = priority;
+ _priorityScreen[offset + _width] = priority;
+ }
+ if (drawMask & GFX_SCREEN_MASK_CONTROL) {
+ _controlScreen[offset] = control;
+ _controlScreen[offset + _width] = control;
+ }
+}
+
+// Directly sets a pixel on various screens, display is not upscaled
+void GfxScreen::putPixelNormal(int16 x, int16 y, byte drawMask, byte color, byte priority, byte control) {
+ int offset = y * _width + x;
+
+ if (drawMask & GFX_SCREEN_MASK_VISUAL) {
+ _visualScreen[offset] = color;
+ _displayScreen[offset] = color;
+ }
+ if (drawMask & GFX_SCREEN_MASK_PRIORITY)
+ _priorityScreen[offset] = priority;
+ if (drawMask & GFX_SCREEN_MASK_CONTROL)
+ _controlScreen[offset] = control;
+}
+
+// Directly sets a pixel on various screens, display IS upscaled
+void GfxScreen::putPixelDisplayUpscaled(int16 x, int16 y, byte drawMask, byte color, byte priority, byte control) {
+ int offset = y * _width + x;
+
+ if (drawMask & GFX_SCREEN_MASK_VISUAL) {
+ _visualScreen[offset] = color;
+ putScaledPixelOnScreen(_displayScreen, x, y, color);
+ }
if (drawMask & GFX_SCREEN_MASK_PRIORITY)
_priorityScreen[offset] = priority;
if (drawMask & GFX_SCREEN_MASK_CONTROL)
_controlScreen[offset] = control;
}
+// Directly sets a pixel on various screens, ALL screens ARE upscaled
+void GfxScreen::putPixelAllUpscaled(int16 x, int16 y, byte drawMask, byte color, byte priority, byte control) {
+ if (drawMask & GFX_SCREEN_MASK_VISUAL) {
+ putScaledPixelOnScreen(_visualScreen, x, y, color);
+ putScaledPixelOnScreen(_displayScreen, x, y, color);
+ }
+ if (drawMask & GFX_SCREEN_MASK_PRIORITY)
+ putScaledPixelOnScreen(_priorityScreen, x, y, priority);
+ if (drawMask & GFX_SCREEN_MASK_CONTROL)
+ putScaledPixelOnScreen(_controlScreen, x, y, control);
+}
+
/**
* This is used to put font pixels onto the screen - we adjust differently, so that we won't
* do triple pixel lines in any case on upscaled hires. That way the font will not get distorted
* Sierra SCI didn't do this
*/
-void GfxScreen::putFontPixel(int startingY, int x, int y, byte color) {
- int actualY = startingY + y;
+void GfxScreen::putFontPixel(int16 startingY, int16 x, int16 y, byte color) {
+ int16 actualY = startingY + y;
if (_fontIsUpscaled) {
// Do not scale ourselves, but put it on the display directly
putPixelOnDisplay(x, actualY, color);
} else {
- int offset = actualY * _pitch + x;
+ int offset = actualY * _width + x;
_visualScreen[offset] = color;
switch (_upscaledHires) {
case GFX_SCREEN_UPSCALED_DISABLED:
_displayScreen[offset] = color;
break;
+ case GFX_SCREEN_UPSCALED_640x400:
+ case GFX_SCREEN_UPSCALED_640x440:
+ case GFX_SCREEN_UPSCALED_640x480: {
+ // to 1-> 4 pixels upscaling for all of those, so that fonts won't look weird
+ int displayOffset = (_upscaledHeightMapping[startingY] + y * 2) * _displayWidth + x * 2;
+ _displayScreen[displayOffset] = color;
+ _displayScreen[displayOffset + 1] = color;
+ displayOffset += _displayWidth;
+ _displayScreen[displayOffset] = color;
+ _displayScreen[displayOffset + 1] = color;
+ break;
+ }
default:
- putScaledPixelOnDisplay(x, actualY, color);
+ putScaledPixelOnScreen(_displayScreen, x, actualY, color);
break;
}
}
@@ -295,12 +474,15 @@ void GfxScreen::putFontPixel(int startingY, int x, int y, byte color) {
* only used on upscaled-Hires games where hires content needs to get drawn ONTO
* the upscaled display screen (like japanese fonts, hires portraits, etc.).
*/
-void GfxScreen::putPixelOnDisplay(int x, int y, byte color) {
+void GfxScreen::putPixelOnDisplay(int16 x, int16 y, byte color) {
int offset = y * _displayWidth + x;
_displayScreen[offset] = color;
}
-void GfxScreen::putScaledPixelOnDisplay(int x, int y, byte color) {
+//void GfxScreen::putScaledPixelOnDisplay(int16 x, int16 y, byte color) {
+//}
+
+void GfxScreen::putScaledPixelOnScreen(byte *screen, int16 x, int16 y, byte data) {
int displayOffset = _upscaledHeightMapping[y] * _displayWidth + _upscaledWidthMapping[x];
int heightOffsetBreak = (_upscaledHeightMapping[y + 1] - _upscaledHeightMapping[y]) * _displayWidth;
int heightOffset = 0;
@@ -308,7 +490,7 @@ void GfxScreen::putScaledPixelOnDisplay(int x, int y, byte color) {
do {
int widthOffset = 0;
do {
- _displayScreen[displayOffset + heightOffset + widthOffset] = color;
+ screen[displayOffset + heightOffset + widthOffset] = data;
widthOffset++;
} while (widthOffset != widthOffsetBreak);
heightOffset += _displayWidth;
@@ -329,16 +511,18 @@ void GfxScreen::drawLine(Common::Point startPoint, Common::Point endPoint, byte
int16 top = CLIP<int16>(startPoint.y, 0, maxHeight);
int16 right = CLIP<int16>(endPoint.x, 0, maxWidth);
int16 bottom = CLIP<int16>(endPoint.y, 0, maxHeight);
-
+
//set_drawing_flag
byte drawMask = getDrawingMask(color, priority, control);
+ vectorAdjustLineCoordinates(&left, &top, &right, &bottom, drawMask, color, priority, control);
+
// horizontal line
if (top == bottom) {
if (right < left)
SWAP(right, left);
for (int i = left; i <= right; i++)
- putPixel(i, top, drawMask, color, priority, control);
+ vectorPutLinePixel(i, top, drawMask, color, priority, control);
return;
}
// vertical line
@@ -346,20 +530,20 @@ void GfxScreen::drawLine(Common::Point startPoint, Common::Point endPoint, byte
if (top > bottom)
SWAP(top, bottom);
for (int i = top; i <= bottom; i++)
- putPixel(left, i, drawMask, color, priority, control);
+ vectorPutLinePixel(left, i, drawMask, color, priority, control);
return;
}
// sloped line - draw with Bresenham algorithm
- int dy = bottom - top;
- int dx = right - left;
- int stepy = dy < 0 ? -1 : 1;
- int stepx = dx < 0 ? -1 : 1;
+ int16 dy = bottom - top;
+ int16 dx = right - left;
+ int16 stepy = dy < 0 ? -1 : 1;
+ int16 stepx = dx < 0 ? -1 : 1;
dy = ABS(dy) << 1;
dx = ABS(dx) << 1;
// setting the 1st and last pixel
- putPixel(left, top, drawMask, color, priority, control);
- putPixel(right, bottom, drawMask, color, priority, control);
+ vectorPutLinePixel(left, top, drawMask, color, priority, control);
+ vectorPutLinePixel(right, bottom, drawMask, color, priority, control);
// drawing the line
if (dx > dy) { // going horizontal
int fraction = dy - (dx >> 1);
@@ -370,7 +554,7 @@ void GfxScreen::drawLine(Common::Point startPoint, Common::Point endPoint, byte
}
left += stepx;
fraction += dy;
- putPixel(left, top, drawMask, color, priority, control);
+ vectorPutLinePixel(left, top, drawMask, color, priority, control);
}
} else { // going vertical
int fraction = dx - (dy >> 1);
@@ -381,7 +565,7 @@ void GfxScreen::drawLine(Common::Point startPoint, Common::Point endPoint, byte
}
top += stepy;
fraction += dx;
- putPixel(left, top, drawMask, color, priority, control);
+ vectorPutLinePixel(left, top, drawMask, color, priority, control);
}
}
}
@@ -394,46 +578,14 @@ void GfxScreen::putKanjiChar(Graphics::FontSJIS *commonFont, int16 x, int16 y, u
commonFont->drawChar(displayPtr, chr, _displayWidth, 1, color, 0, -1, -1);
}
-byte GfxScreen::getVisual(int x, int y) {
- return _visualScreen[y * _pitch + x];
-}
-
-byte GfxScreen::getPriority(int x, int y) {
- return _priorityScreen[y * _pitch + x];
-}
-
-byte GfxScreen::getControl(int x, int y) {
- return _controlScreen[y * _pitch + x];
+byte GfxScreen::getPixelNormal(byte *screen, int16 x, int16 y) {
+ return screen[y * _width + x];
}
-byte GfxScreen::isFillMatch(int16 x, int16 y, byte screenMask, byte t_color, byte t_pri, byte t_con, bool isEGA) {
- int offset = y * _pitch + x;
- byte match = 0;
-
- if (screenMask & GFX_SCREEN_MASK_VISUAL) {
- if (!isEGA) {
- if (*(_visualScreen + offset) == t_color)
- match |= GFX_SCREEN_MASK_VISUAL;
- } else {
- // In EGA games a pixel in the framebuffer is only 4 bits. We store
- // a full byte per pixel to allow undithering, but when comparing
- // pixels for flood-fill purposes, we should only compare the
- // visible color of a pixel.
-
- byte c = *(_visualScreen + offset);
- if ((x ^ y) & 1)
- c = (c ^ (c >> 4)) & 0x0F;
- else
- c = c & 0x0F;
- if (c == t_color)
- match |= GFX_SCREEN_MASK_VISUAL;
- }
- }
- if ((screenMask & GFX_SCREEN_MASK_PRIORITY) && *(_priorityScreen + offset) == t_pri)
- match |= GFX_SCREEN_MASK_PRIORITY;
- if ((screenMask & GFX_SCREEN_MASK_CONTROL) && *(_controlScreen + offset) == t_con)
- match |= GFX_SCREEN_MASK_CONTROL;
- return match;
+byte GfxScreen::getPixelUpscaled(byte *screen, int16 x, int16 y) {
+ int16 mappedX = _upscaledWidthMapping[x];
+ int16 mappedY = _upscaledHeightMapping[y];
+ return screen[mappedY * _width + mappedX];
}
int GfxScreen::bitsGetDataSize(Common::Rect rect, byte mask) {
@@ -469,14 +621,14 @@ void GfxScreen::bitsSave(Common::Rect rect, byte mask, byte *memoryPtr) {
memcpy(memoryPtr, (void *)&mask, sizeof(mask)); memoryPtr += sizeof(mask);
if (mask & GFX_SCREEN_MASK_VISUAL) {
- bitsSaveScreen(rect, _visualScreen, _pitch, memoryPtr);
+ bitsSaveScreen(rect, _visualScreen, _width, memoryPtr);
bitsSaveDisplayScreen(rect, memoryPtr);
}
if (mask & GFX_SCREEN_MASK_PRIORITY) {
- bitsSaveScreen(rect, _priorityScreen, _pitch, memoryPtr);
+ bitsSaveScreen(rect, _priorityScreen, _width, memoryPtr);
}
if (mask & GFX_SCREEN_MASK_CONTROL) {
- bitsSaveScreen(rect, _controlScreen, _pitch, memoryPtr);
+ bitsSaveScreen(rect, _controlScreen, _width, memoryPtr);
}
if (mask & GFX_SCREEN_MASK_DISPLAY) {
if (!_upscaledHires)
@@ -530,14 +682,14 @@ void GfxScreen::bitsRestore(byte *memoryPtr) {
memcpy((void *)&mask, memoryPtr, sizeof(mask)); memoryPtr += sizeof(mask);
if (mask & GFX_SCREEN_MASK_VISUAL) {
- bitsRestoreScreen(rect, memoryPtr, _visualScreen, _pitch);
+ bitsRestoreScreen(rect, memoryPtr, _visualScreen, _width);
bitsRestoreDisplayScreen(rect, memoryPtr);
}
if (mask & GFX_SCREEN_MASK_PRIORITY) {
- bitsRestoreScreen(rect, memoryPtr, _priorityScreen, _pitch);
+ bitsRestoreScreen(rect, memoryPtr, _priorityScreen, _width);
}
if (mask & GFX_SCREEN_MASK_CONTROL) {
- bitsRestoreScreen(rect, memoryPtr, _controlScreen, _pitch);
+ bitsRestoreScreen(rect, memoryPtr, _controlScreen, _width);
}
if (mask & GFX_SCREEN_MASK_DISPLAY) {
if (!_upscaledHires)
@@ -612,21 +764,22 @@ void GfxScreen::dither(bool addToFlag) {
byte color, ditheredColor;
byte *visualPtr = _visualScreen;
byte *displayPtr = _displayScreen;
-
+
if (!_unditheringEnabled) {
// Do dithering on visual and display-screen
for (y = 0; y < _height; y++) {
- for (x = 0; x < _pitch; x++) {
+ for (x = 0; x < _width; x++) {
color = *visualPtr;
if (color & 0xF0) {
color ^= color << 4;
color = ((x^y) & 1) ? color >> 4 : color & 0x0F;
switch (_upscaledHires) {
case GFX_SCREEN_UPSCALED_DISABLED:
+ case GFX_SCREEN_UPSCALED_480x300:
*displayPtr = color;
break;
default:
- putScaledPixelOnDisplay(x, y, color);
+ putScaledPixelOnScreen(_displayScreen, x, y, color);
break;
}
*visualPtr = color;
@@ -639,7 +792,7 @@ void GfxScreen::dither(bool addToFlag) {
memset(&_ditheredPicColors, 0, sizeof(_ditheredPicColors));
// Do dithering on visual screen and put decoded but undithered byte onto display-screen
for (y = 0; y < _height; y++) {
- for (x = 0; x < _pitch; x++) {
+ for (x = 0; x < _width; x++) {
color = *visualPtr;
if (color & 0xF0) {
color ^= color << 4;
@@ -654,10 +807,11 @@ void GfxScreen::dither(bool addToFlag) {
}
switch (_upscaledHires) {
case GFX_SCREEN_UPSCALED_DISABLED:
+ case GFX_SCREEN_UPSCALED_480x300:
*displayPtr = ditheredColor;
break;
default:
- putScaledPixelOnDisplay(x, y, ditheredColor);
+ putScaledPixelOnScreen(_displayScreen, x, y, ditheredColor);
break;
}
color = ((x^y) & 1) ? color >> 4 : color & 0x0F;
@@ -685,8 +839,8 @@ int16 *GfxScreen::unditherGetDitheredBgColors() {
}
void GfxScreen::debugShowMap(int mapNo) {
- // We cannot really support changing maps when in upscaledHires mode
- if (_upscaledHires)
+ // We cannot really support changing maps when display screen has a different resolution than visual screen
+ if ((_width != _displayWidth) || (_height != _displayHeight))
return;
switch (mapNo) {
@@ -779,8 +933,8 @@ void GfxScreen::adjustBackUpscaledCoordinates(int16 &y, int16 &x, Sci32ViewNativ
switch (_upscaledHires) {
case GFX_SCREEN_UPSCALED_480x300:
- x = (x << 1) / 3;
- y = (y << 1) / 3;
+ x = (x * 4) / 6;
+ y = (y * 4) / 6;
break;
case GFX_SCREEN_UPSCALED_640x400:
x /= 2;
@@ -816,26 +970,4 @@ int16 GfxScreen::kernelPicNotValid(int16 newPicNotValid) {
return oldPicNotValid;
}
-uint16 GfxScreen::getLowResScreenHeight() {
- // Some Mac SCI1/1.1 games only take up 190 rows and do not
- // have the menu bar.
- // TODO: Verify that LSL1 and LSL5 use height 190
- if (g_sci->getPlatform() == Common::kPlatformMacintosh) {
- switch (g_sci->getGameId()) {
- case GID_FREDDYPHARKAS:
- case GID_KQ5:
- case GID_KQ6:
- case GID_LSL1:
- case GID_LSL5:
- case GID_SQ1:
- return 190;
- default:
- break;
- }
- }
-
- // Everything else is 200
- return 200;
-}
-
} // End of namespace Sci
diff --git a/engines/sci/graphics/screen.h b/engines/sci/graphics/screen.h
index e266a4ed16..766e32614a 100644
--- a/engines/sci/graphics/screen.h
+++ b/engines/sci/graphics/screen.h
@@ -69,6 +69,8 @@ public:
uint16 getWidth() { return _width; }
uint16 getHeight() { return _height; }
+ uint16 getScriptWidth() { return _scriptWidth; }
+ uint16 getScriptHeight() { return _scriptHeight; }
uint16 getDisplayWidth() { return _displayWidth; }
uint16 getDisplayHeight() { return _displayHeight; }
byte getColorWhite() { return _colorWhite; }
@@ -81,11 +83,51 @@ public:
void copyDisplayRectToScreen(const Common::Rect &rect);
void copyRectToScreen(const Common::Rect &rect, int16 x, int16 y);
+ // calls to code pointers
+ void inline vectorAdjustCoordinate (int16 *x, int16 *y) {
+ (this->*_vectorAdjustCoordinatePtr)(x, y);
+ }
+ void inline vectorAdjustLineCoordinates (int16 *left, int16 *top, int16 *right, int16 *bottom, byte drawMask, byte color, byte priority, byte control) {
+ (this->*_vectorAdjustLineCoordinatesPtr)(left, top, right, bottom, drawMask, color, priority, control);
+ }
+ byte inline vectorIsFillMatch (int16 x, int16 y, byte screenMask, byte t_color, byte t_pri, byte t_con, bool isEGA) {
+ return (this->*_vectorIsFillMatchPtr)(x, y, screenMask, t_color, t_pri, t_con, isEGA);
+ }
+ void inline vectorPutPixel(int16 x, int16 y, byte drawMask, byte color, byte priority, byte control) {
+ (this->*_vectorPutPixelPtr)(x, y, drawMask, color, priority, control);
+ }
+ void inline vectorPutLinePixel(int16 x, int16 y, byte drawMask, byte color, byte priority, byte control) {
+ (this->*_vectorPutLinePixelPtr)(x, y, drawMask, color, priority, control);
+ }
+ byte inline vectorGetVisual(int16 x, int16 y) {
+ return (this->*_vectorGetPixelPtr)(_visualScreen, x, y);
+ }
+ byte inline vectorGetPriority(int16 x, int16 y) {
+ return (this->*_vectorGetPixelPtr)(_priorityScreen, x, y);
+ }
+ byte inline vectorGetControl(int16 x, int16 y) {
+ return (this->*_vectorGetPixelPtr)(_controlScreen, x, y);
+ }
+
+
+ void inline putPixel(int16 x, int16 y, byte drawMask, byte color, byte priority, byte control) {
+ (this->*_putPixelPtr)(x, y, drawMask, color, priority, control);
+ }
+
+ byte inline getVisual(int16 x, int16 y) {
+ return (this->*_getPixelPtr)(_visualScreen, x, y);
+ }
+ byte inline getPriority(int16 x, int16 y) {
+ return (this->*_getPixelPtr)(_priorityScreen, x, y);
+ }
+ byte inline getControl(int16 x, int16 y) {
+ return (this->*_getPixelPtr)(_controlScreen, x, y);
+ }
+
byte getDrawingMask(byte color, byte prio, byte control);
- void putPixel(int x, int y, byte drawMask, byte color, byte prio, byte control);
- void putFontPixel(int startingY, int x, int y, byte color);
- void putPixelOnDisplay(int x, int y, byte color);
- void putScaledPixelOnDisplay(int x, int y, byte color);
+ //void putPixel(int16 x, int16 y, byte drawMask, byte color, byte prio, byte control);
+ void putFontPixel(int16 startingY, int16 x, int16 y, byte color);
+ void putPixelOnDisplay(int16 x, int16 y, byte color);
void drawLine(Common::Point startPoint, Common::Point endPoint, byte color, byte prio, byte control);
void drawLine(int16 left, int16 top, int16 right, int16 bottom, byte color, byte prio, byte control) {
drawLine(Common::Point(left, top), Common::Point(right, bottom), color, prio, control);
@@ -101,10 +143,6 @@ public:
void enableUndithering(bool flag);
void putKanjiChar(Graphics::FontSJIS *commonFont, int16 x, int16 y, uint16 chr, byte color);
- byte getVisual(int x, int y);
- byte getPriority(int x, int y);
- byte getControl(int x, int y);
- byte isFillMatch(int16 x, int16 y, byte drawMask, byte t_color, byte t_pri, byte t_con, bool isEGA);
int bitsGetDataSize(Common::Rect rect, byte mask);
void bitsSave(Common::Rect rect, byte mask, byte *memoryPtr);
@@ -135,9 +173,10 @@ public:
private:
uint16 _width;
- uint16 _pitch;
uint16 _height;
uint _pixels;
+ uint16 _scriptWidth;
+ uint16 _scriptHeight;
uint16 _displayWidth;
uint16 _displayHeight;
uint _displayPixels;
@@ -190,8 +229,8 @@ private:
* This here holds a translation for vertical+horizontal coordinates between native
* (visual) and actual (display) screen.
*/
- int _upscaledHeightMapping[SCI_SCREEN_UPSCALEDMAXHEIGHT + 1];
- int _upscaledWidthMapping[SCI_SCREEN_UPSCALEDMAXWIDTH + 1];
+ int16 _upscaledHeightMapping[SCI_SCREEN_UPSCALEDMAXHEIGHT + 1];
+ int16 _upscaledWidthMapping[SCI_SCREEN_UPSCALEDMAXWIDTH + 1];
/**
* This defines whether or not the font we're drawing is already scaled
@@ -199,7 +238,38 @@ private:
*/
bool _fontIsUpscaled;
- uint16 getLowResScreenHeight();
+ // dynamic code
+ void (GfxScreen::*_vectorAdjustCoordinatePtr) (int16 *x, int16 *y);
+ void vectorAdjustCoordinateNOP (int16 *x, int16 *y);
+ void vectorAdjustCoordinate480x300Mac (int16 *x, int16 *y);
+
+ void (GfxScreen::*_vectorAdjustLineCoordinatesPtr) (int16 *left, int16 *top, int16 *right, int16 *bottom, byte drawMask, byte color, byte priority, byte control);
+ void vectorAdjustLineCoordinatesNOP (int16 *left, int16 *top, int16 *right, int16 *bottom, byte drawMask, byte color, byte priority, byte control);
+ void vectorAdjustLineCoordinates480x300Mac (int16 *left, int16 *top, int16 *right, int16 *bottom, byte drawMask, byte color, byte priority, byte control);
+
+ byte (GfxScreen::*_vectorIsFillMatchPtr) (int16 x, int16 y, byte screenMask, byte t_color, byte t_pri, byte t_con, bool isEGA);
+ byte vectorIsFillMatchNormal (int16 x, int16 y, byte screenMask, byte t_color, byte t_pri, byte t_con, bool isEGA);
+ byte vectorIsFillMatch480x300Mac (int16 x, int16 y, byte screenMask, byte t_color, byte t_pri, byte t_con, bool isEGA);
+
+ void (GfxScreen::*_vectorPutPixelPtr) (int16 x, int16 y, byte drawMask, byte color, byte priority, byte control);
+ void vectorPutPixel480x300Mac (int16 x, int16 y, byte drawMask, byte color, byte priority, byte control);
+
+ void (GfxScreen::*_vectorPutLinePixelPtr) (int16 x, int16 y, byte drawMask, byte color, byte priority, byte control);
+ void vectorPutLinePixel480x300Mac (int16 x, int16 y, byte drawMask, byte color, byte priority, byte control);
+
+ byte (GfxScreen::*_vectorGetPixelPtr) (byte *screen, int16 x, int16 y);
+
+ void (GfxScreen::*_putPixelPtr) (int16 x, int16 y, byte drawMask, byte color, byte priority, byte control);
+ void putPixelNormal (int16 x, int16 y, byte drawMask, byte color, byte priority, byte control);
+ void putPixelDisplayUpscaled (int16 x, int16 y, byte drawMask, byte color, byte priority, byte control);
+ void putPixelAllUpscaled (int16 x, int16 y, byte drawMask, byte color, byte priority, byte control);
+
+ byte (GfxScreen::*_getPixelPtr) (byte *screen, int16 x, int16 y);
+ byte getPixelNormal (byte *screen, int16 x, int16 y);
+ byte getPixelUpscaled (byte *screen, int16 x, int16 y);
+
+ // pixel helper
+ void putScaledPixelOnScreen(byte *screen, int16 x, int16 y, byte color);
};
} // End of namespace Sci
diff --git a/engines/sci/graphics/text16.cpp b/engines/sci/graphics/text16.cpp
index 245d6996cb..f463dff4b1 100644
--- a/engines/sci/graphics/text16.cpp
+++ b/engines/sci/graphics/text16.cpp
@@ -143,18 +143,30 @@ int16 GfxText16::CodeProcessing(const char *&text, GuiResourceId orgFontId, int1
return textCodeSize;
}
-static const uint16 text16_punctuationSjis[] = {
- 0x9F82, 0xA182, 0xA382, 0xA582, 0xA782, 0xC182, 0xA782, 0xC182, 0xE182, 0xE382, 0xE582, 0xEC82,
- 0x4083, 0x4283, 0x4483, 0x4683, 0x4883, 0x6283, 0x8383, 0x8583, 0x8783, 0x8E83, 0x9583, 0x9683,
- 0x5B81, 0x4181, 0x4281, 0x7681, 0x7881, 0x4981, 0x4881, 0
+// Has actually punctuation and characters in it, that may not be the first in a line
+static const uint16 text16_shiftJIS_punctuation[] = {
+ 0x9F82, 0xA182, 0xA382, 0xA582, 0xA782, 0xC182, 0xE182, 0xE382, 0xE582, 0xEC82, 0x4083, 0x4283,
+ 0x4483, 0x4683, 0x4883, 0x6283, 0x8383, 0x8583, 0x8783, 0x8E83, 0x9583, 0x9683, 0x5B81, 0x4181,
+ 0x4281, 0x7681, 0x7881, 0x4981, 0x4881, 0
};
// return max # of chars to fit maxwidth with full words, does not include
// breaking space
-int16 GfxText16::GetLongest(const char *text, int16 maxWidth, GuiResourceId orgFontId) {
+// Also adjusts text pointer to the new position for the caller
+//
+// Special cases in games:
+// Laura Bow 2 - Credits in the game menu - all the text lines start with spaces (bug #5159)
+// Act 6 Coroner questionaire - the text of all control buttons has trailing spaces
+// "Detective Ryan Hanrahan O'Riley" contains even more spaces (bug #5334)
+// Conquests of Camelot - talking with Cobb - one text box of the dialogue contains a longer word,
+// that will be broken into 2 lines (bug #5159)
+int16 GfxText16::GetLongest(const char *&textPtr, int16 maxWidth, GuiResourceId orgFontId) {
uint16 curChar = 0;
- int16 maxChars = 0, curCharCount = 0;
- uint16 width = 0;
+ const char *textStartPtr = textPtr;
+ const char *lastSpacePtr = NULL;
+ int16 lastSpaceCharCount = 0;
+ int16 curCharCount = 0, resultCharCount = 0;
+ uint16 curWidth = 0, tempWidth = 0;
GuiResourceId previousFontId = GetFontId();
int16 previousPenColor = _ports->_curPort->penClr;
@@ -162,35 +174,38 @@ int16 GfxText16::GetLongest(const char *text, int16 maxWidth, GuiResourceId orgF
if (!_font)
return 0;
- while (width <= maxWidth) {
- curChar = (*(const byte *)text++);
+ while (1) {
+ curChar = (*(const byte *)textPtr);
if (_font->isDoubleByte(curChar)) {
- curChar |= (*(const byte *)text++) << 8;
- curCharCount++;
+ curChar |= (*(const byte *)(textPtr + 1)) << 8;
}
switch (curChar) {
case 0x7C:
if (getSciVersion() >= SCI_VERSION_1_1) {
- curCharCount++;
- curCharCount += CodeProcessing(text, orgFontId, previousPenColor, false);
+ curCharCount++; textPtr++;
+ curCharCount += CodeProcessing(textPtr, orgFontId, previousPenColor, false);
continue;
}
break;
// We need to add 0xD, 0xA and 0xD 0xA to curCharCount and then exit
- // which means, we split text like
- // 'Mature, experienced software analyst available.' 0xD 0xA
- // 'Bug installation a proven speciality. "No version too clean."' (normal game text, this is from lsl2)
- // and 0xA '-------' 0xA (which is the official sierra subtitle separator)
+ // which means, we split text like for example
+ // - 'Mature, experienced software analyst available.' 0xD 0xA
+ // 'Bug installation a proven speciality. "No version too clean."' (normal game text, this is from lsl2)
+ // - 0xA '-------' 0xA (which is the official sierra subtitle separator) (found in multilingual versions)
// Sierra did it the same way.
case 0xD:
// Check, if 0xA is following, if so include it as well
- if ((*(const unsigned char *)text) == 0xA)
- curCharCount++;
+ if ((*(const byte *)(textPtr + 1)) == 0xA) {
+ curCharCount++; textPtr++;
+ }
// it's meant to pass through here
case 0xA:
case 0x9781: // this one is used by SQ4/japanese as line break as well
- curCharCount++;
+ curCharCount++; textPtr++;
+ if (curChar > 0xFF) {
+ curCharCount++; textPtr++;
+ }
// and it's also meant to pass through here
case 0:
SetFont(previousFontId);
@@ -198,55 +213,86 @@ int16 GfxText16::GetLongest(const char *text, int16 maxWidth, GuiResourceId orgF
return curCharCount;
case ' ':
- maxChars = curCharCount; // return count up to (but not including) breaking space
+ lastSpaceCharCount = curCharCount; // return count up to (but not including) breaking space
+ lastSpacePtr = textPtr + 1; // remember position right after the current space
break;
}
- // Sometimes this can go off the screen, like for example bug #3040161.
- // However, we only perform this for non-Japanese games, as these require
- // special handling, done after this loop.
- if (width + _font->getCharWidth(curChar) > maxWidth && g_sci->getLanguage() != Common::JA_JPN)
+ tempWidth += _font->getCharWidth(curChar);
+
+ // Width is too large? -> break out
+ if (tempWidth > maxWidth)
break;
- width += _font->getCharWidth(curChar);
- curCharCount++;
+
+ // still fits, remember width
+ curWidth = tempWidth;
+
+ // go to next character
+ curCharCount++; textPtr++;
+ if (curChar > 0xFF) {
+ // Double-Byte
+ curCharCount++; textPtr++;
+ }
}
- // Text without spaces, probably Kanji/Japanese
- if (maxChars == 0) {
- maxChars = curCharCount;
+ if (lastSpaceCharCount) {
+ // Break and at least one space was found before that
+ resultCharCount = lastSpaceCharCount;
- uint16 nextChar;
+ // additionally skip over all spaces, that are following that space, but don't count them for displaying purposes
+ textPtr = lastSpacePtr;
+ while (*textPtr == ' ')
+ textPtr++;
- // We remove the last char only, if maxWidth was actually equal width
- // before adding the last char. Otherwise we won't get the same cutting
- // as in sierra pc98 sci.
- if (maxWidth == (width - _font->getCharWidth(curChar))) {
- maxChars--;
- if (curChar > 0xFF)
- maxChars--;
- nextChar = curChar;
- } else {
- nextChar = (*(const byte *)text++);
- if (_font->isDoubleByte(nextChar))
- nextChar |= (*(const byte *)text++) << 8;
- }
- // sierra checked the following character against a punctuation kanji table
- if (nextChar > 0xFF) {
- // if the character is punctuation, we go back one character
- uint nonBreakingNr = 0;
- while (text16_punctuationSjis[nonBreakingNr]) {
- if (text16_punctuationSjis[nonBreakingNr] == nextChar) {
- maxChars--;
- if (curChar > 0xFF)
- maxChars--; // go back 2 chars, when last char was double byte
+ } else {
+ // Break without spaces found, we split the very first word - may also be Kanji/Japanese
+ if (curChar > 0xFF) {
+ // current charracter is Japanese
+
+ // PC-9801 SCI actually added the last character, which shouldn't fit anymore, still onto the
+ // screen in case maxWidth wasn't fully reached with the last character
+ if (( maxWidth - 1 ) > curWidth) {
+ curCharCount += 2; textPtr += 2;
+
+ curChar = (*(const byte *)textPtr);
+ if (_font->isDoubleByte(curChar)) {
+ curChar |= (*(const byte *)(textPtr + 1)) << 8;
+ }
+ }
+
+ // But it also checked, if the current character is not inside a punctuation table and it even
+ // went backwards in case it found multiple ones inside that table.
+ uint nonBreakingPos = 0;
+
+ while (1) {
+ // Look up if character shouldn't be the first on a new line
+ nonBreakingPos = 0;
+ while (text16_shiftJIS_punctuation[nonBreakingPos]) {
+ if (text16_shiftJIS_punctuation[nonBreakingPos] == curChar)
+ break;
+ nonBreakingPos++;
+ }
+ if (!text16_shiftJIS_punctuation[nonBreakingPos]) {
+ // character is fine
break;
}
- nonBreakingNr++;
+ // Character is not acceptable, seek backward in the text
+ curCharCount -= 2; textPtr -= 2;
+ if (textPtr < textStartPtr)
+ error("Seeking back went too far, data corruption?");
+
+ curChar = (*(const byte *)textPtr);
+ if (!_font->isDoubleByte(curChar))
+ error("Non double byte while seeking back");
+ curChar |= (*(const byte *)(textPtr + 1)) << 8;
}
}
+
+ // We split the word in that case
+ resultCharCount = curCharCount;
}
SetFont(previousFontId);
_ports->penColor(previousPenColor);
- return maxChars;
+ return resultCharCount;
}
void GfxText16::Width(const char *text, int16 from, int16 len, GuiResourceId orgFontId, int16 &textWidth, int16 &textHeight, bool restoreFont) {
@@ -303,7 +349,7 @@ void GfxText16::DrawString(const char *str, GuiResourceId orgFontId, int16 orgPe
Draw(str, 0, (int16)strlen(str), orgFontId, orgPenColor);
}
-int16 GfxText16::Size(Common::Rect &rect, const char *text, GuiResourceId fontId, int16 maxWidth) {
+int16 GfxText16::Size(Common::Rect &rect, const char *text, uint16 languageSplitter, GuiResourceId fontId, int16 maxWidth) {
GuiResourceId previousFontId = GetFontId();
int16 previousPenColor = _ports->_curPort->penClr;
int16 charCount;
@@ -315,12 +361,12 @@ int16 GfxText16::Size(Common::Rect &rect, const char *text, GuiResourceId fontId
else
fontId = previousFontId;
- if (g_sci->getLanguage() == Common::JA_JPN)
- SwitchToFont900OnSjis(text);
-
rect.top = rect.left = 0;
if (maxWidth < 0) { // force output as single line
+ if (g_sci->getLanguage() == Common::JA_JPN)
+ SwitchToFont900OnSjis(text, languageSplitter);
+
StringWidth(text, fontId, textWidth, textHeight);
rect.bottom = textHeight;
rect.right = textWidth;
@@ -328,17 +374,20 @@ int16 GfxText16::Size(Common::Rect &rect, const char *text, GuiResourceId fontId
// rect.right=found widest line with RTextWidth and GetLongest
// rect.bottom=num. lines * GetPointSize
rect.right = (maxWidth ? maxWidth : 192);
- const char *curPos = text;
- while (*curPos) {
- charCount = GetLongest(curPos, rect.right, fontId);
+ const char *curTextPos = text; // in work position for GetLongest()
+ const char *curTextLine = text; // starting point of current line
+ while (*curTextPos) {
+ // We need to check for Shift-JIS every line
+ if (g_sci->getLanguage() == Common::JA_JPN)
+ SwitchToFont900OnSjis(curTextPos, languageSplitter);
+
+ charCount = GetLongest(curTextPos, rect.right, fontId);
if (charCount == 0)
break;
- Width(curPos, 0, charCount, fontId, textWidth, textHeight, false);
+ Width(curTextLine, 0, charCount, fontId, textWidth, textHeight, false);
maxTextWidth = MAX(textWidth, maxTextWidth);
totalHeight += textHeight;
- curPos += charCount;
- while (*curPos == ' ')
- curPos++; // skip over breaking spaces
+ curTextLine = curTextPos;
}
rect.bottom = totalHeight;
rect.right = maxWidth ? maxWidth : MIN(rect.right, maxTextWidth);
@@ -405,34 +454,38 @@ void GfxText16::Show(const char *text, int16 from, int16 len, GuiResourceId orgF
}
// Draws a text in rect.
-void GfxText16::Box(const char *text, bool show, const Common::Rect &rect, TextAlignment alignment, GuiResourceId fontId) {
+void GfxText16::Box(const char *text, uint16 languageSplitter, bool show, const Common::Rect &rect, TextAlignment alignment, GuiResourceId fontId) {
int16 textWidth, maxTextWidth, textHeight, charCount;
int16 offset = 0;
int16 hline = 0;
GuiResourceId previousFontId = GetFontId();
int16 previousPenColor = _ports->_curPort->penClr;
bool doubleByteMode = false;
+ const char *curTextPos = text;
+ const char *curTextLine = text;
if (fontId != -1)
SetFont(fontId);
else
fontId = previousFontId;
- if (g_sci->getLanguage() == Common::JA_JPN) {
- if (SwitchToFont900OnSjis(text))
- doubleByteMode = true;
- }
-
// Reset reference code rects
_codeRefRects.clear();
_codeRefTempRect.left = _codeRefTempRect.top = -1;
maxTextWidth = 0;
- while (*text) {
- charCount = GetLongest(text, rect.width(), fontId);
+ while (*curTextPos) {
+ // We need to check for Shift-JIS every line
+ // Police Quest 2 PC-9801 often draws English + Japanese text during the same call
+ if (g_sci->getLanguage() == Common::JA_JPN) {
+ if (SwitchToFont900OnSjis(curTextPos, languageSplitter))
+ doubleByteMode = true;
+ }
+
+ charCount = GetLongest(curTextPos, rect.width(), fontId);
if (charCount == 0)
break;
- Width(text, 0, charCount, fontId, textWidth, textHeight, true);
+ Width(curTextLine, 0, charCount, fontId, textWidth, textHeight, true);
maxTextWidth = MAX<int16>(maxTextWidth, textWidth);
switch (alignment) {
case SCI_TEXT16_ALIGNMENT_RIGHT:
@@ -451,15 +504,13 @@ void GfxText16::Box(const char *text, bool show, const Common::Rect &rect, TextA
_ports->moveTo(rect.left + offset, rect.top + hline);
if (show) {
- Show(text, 0, charCount, fontId, previousPenColor);
+ Show(curTextLine, 0, charCount, fontId, previousPenColor);
} else {
- Draw(text, 0, charCount, fontId, previousPenColor);
+ Draw(curTextLine, 0, charCount, fontId, previousPenColor);
}
hline += textHeight;
- text += charCount;
- while (*text == ' ')
- text++; // skip over breaking spaces
+ curTextLine = curTextPos;
}
SetFont(previousFontId);
_ports->penColor(previousPenColor);
@@ -521,11 +572,13 @@ void GfxText16::DrawStatus(const char *text) {
// Sierra did this in their PC98 interpreter only, they identify a text as being
// sjis and then switch to font 900
-bool GfxText16::SwitchToFont900OnSjis(const char *text) {
+bool GfxText16::SwitchToFont900OnSjis(const char *text, uint16 languageSplitter) {
byte firstChar = (*(const byte *)text++);
- if (((firstChar >= 0x81) && (firstChar <= 0x9F)) || ((firstChar >= 0xE0) && (firstChar <= 0xEF))) {
- SetFont(900);
- return true;
+ if (languageSplitter != 0x6a23) { // #j prefix as language splitter
+ if (((firstChar >= 0x81) && (firstChar <= 0x9F)) || ((firstChar >= 0xE0) && (firstChar <= 0xEF))) {
+ SetFont(900);
+ return true;
+ }
}
return false;
}
@@ -554,9 +607,9 @@ reg_t GfxText16::allocAndFillReferenceRectArray() {
return NULL_REG;
}
-void GfxText16::kernelTextSize(const char *text, int16 font, int16 maxWidth, int16 *textWidth, int16 *textHeight) {
+void GfxText16::kernelTextSize(const char *text, uint16 languageSplitter, int16 font, int16 maxWidth, int16 *textWidth, int16 *textHeight) {
Common::Rect rect(0, 0, 0, 0);
- Size(rect, text, font, maxWidth);
+ Size(rect, text, languageSplitter, font, maxWidth);
*textWidth = rect.width();
*textHeight = rect.height();
}
diff --git a/engines/sci/graphics/text16.h b/engines/sci/graphics/text16.h
index ab0cb13a64..2724d97347 100644
--- a/engines/sci/graphics/text16.h
+++ b/engines/sci/graphics/text16.h
@@ -51,15 +51,20 @@ public:
void ClearChar(int16 chr);
- int16 GetLongest(const char *text, int16 maxWidth, GuiResourceId orgFontId);
+ int16 GetLongest(const char *&text, int16 maxWidth, GuiResourceId orgFontId);
void Width(const char *text, int16 from, int16 len, GuiResourceId orgFontId, int16 &textWidth, int16 &textHeight, bool restoreFont);
void StringWidth(const char *str, GuiResourceId orgFontId, int16 &textWidth, int16 &textHeight);
void ShowString(const char *str, GuiResourceId orgFontId, int16 orgPenColor);
void DrawString(const char *str, GuiResourceId orgFontId, int16 orgPenColor);
- int16 Size(Common::Rect &rect, const char *text, GuiResourceId fontId, int16 maxWidth);
+ int16 Size(Common::Rect &rect, const char *text, uint16 textLanguage, GuiResourceId fontId, int16 maxWidth);
void Draw(const char *text, int16 from, int16 len, GuiResourceId orgFontId, int16 orgPenColor);
void Show(const char *text, int16 from, int16 len, GuiResourceId orgFontId, int16 orgPenColor);
- void Box(const char *text, bool show, const Common::Rect &rect, TextAlignment alignment, GuiResourceId fontId);
+ void Box(const char *text, uint16 languageSplitter, bool show, const Common::Rect &rect, TextAlignment alignment, GuiResourceId fontId);
+
+ void Box(const char *text, bool show, const Common::Rect &rect, TextAlignment alignment, GuiResourceId fontId) {
+ Box(text, 0, show, rect, alignment, fontId);
+ }
+
void DrawString(const char *text);
void DrawStatus(const char *text);
@@ -67,13 +72,13 @@ public:
reg_t allocAndFillReferenceRectArray();
- void kernelTextSize(const char *text, int16 font, int16 maxWidth, int16 *textWidth, int16 *textHeight);
+ void kernelTextSize(const char *text, uint16 textLanguage, int16 font, int16 maxWidth, int16 *textWidth, int16 *textHeight);
void kernelTextFonts(int argc, reg_t *argv);
void kernelTextColors(int argc, reg_t *argv);
private:
void init();
- bool SwitchToFont900OnSjis(const char *text);
+ bool SwitchToFont900OnSjis(const char *text, uint16 languageSplitter);
GfxCache *_cache;
GfxPorts *_ports;
diff --git a/engines/sci/graphics/transitions.cpp b/engines/sci/graphics/transitions.cpp
index 5e7dbc6c15..ccc7a4389a 100644
--- a/engines/sci/graphics/transitions.cpp
+++ b/engines/sci/graphics/transitions.cpp
@@ -339,10 +339,10 @@ void GfxTransitions::pixelation(bool blackoutFlag) {
do {
mask = (mask & 1) ? (mask >> 1) ^ 0xB400 : mask >> 1;
- if (mask >= _screen->getWidth() * _screen->getHeight())
+ if (mask >= _screen->getScriptWidth() * _screen->getScriptHeight())
continue;
- pixelRect.left = mask % _screen->getWidth(); pixelRect.right = pixelRect.left + 1;
- pixelRect.top = mask / _screen->getWidth(); pixelRect.bottom = pixelRect.top + 1;
+ pixelRect.left = mask % _screen->getScriptWidth(); pixelRect.right = pixelRect.left + 1;
+ pixelRect.top = mask / _screen->getScriptWidth(); pixelRect.bottom = pixelRect.top + 1;
pixelRect.clip(_picRect);
if (!pixelRect.isEmpty())
copyRectToScreen(pixelRect, blackoutFlag);
diff --git a/engines/sci/graphics/view.cpp b/engines/sci/graphics/view.cpp
index f3f352e5b8..da61ecf4c3 100644
--- a/engines/sci/graphics/view.cpp
+++ b/engines/sci/graphics/view.cpp
@@ -283,6 +283,7 @@ void GfxView::initData(GuiResourceId resourceId) {
_isScaleable = false;
break;
case 0x40:
+ case 0x4F: // LSL6 Polish, seems to be garbage - bug #6718
case 0:
break; // don't do anything, we already have _isScaleable set
default:
@@ -366,7 +367,7 @@ void GfxView::initData(GuiResourceId resourceId) {
default:
error("ViewType was not detected, can't continue");
}
-
+
// Inject our own views
// Currently only used for Dual mode (speech + text) for games, that do not have a "dual" icon already
// Which is Laura Bow 2 + King's Quest 6
diff --git a/engines/sci/module.mk b/engines/sci/module.mk
index 6b6058c819..33392e3b42 100644
--- a/engines/sci/module.mk
+++ b/engines/sci/module.mk
@@ -76,8 +76,8 @@ MODULE_OBJS := \
sound/drivers/midi.o \
sound/drivers/pcjr.o \
video/seq_decoder.o
-
-
+
+
ifdef ENABLE_SCI32
MODULE_OBJS += \
engine/kgraphics32.o \
diff --git a/engines/sci/parser/said.cpp b/engines/sci/parser/said.cpp
index 693bbec744..27ebc58704 100644
--- a/engines/sci/parser/said.cpp
+++ b/engines/sci/parser/said.cpp
@@ -186,8 +186,7 @@ static bool parseList(ParseTreeNode* parentNode);
static bool parseListEntry(ParseTreeNode* parentNode);
static bool parseWord(ParseTreeNode* parentNode);
-static bool parseWord(ParseTreeNode* parentNode)
-{
+static bool parseWord(ParseTreeNode* parentNode) {
int token = said_tokens[said_token];
if (token & 0x8000)
return false;
@@ -201,8 +200,7 @@ static bool parseWord(ParseTreeNode* parentNode)
return true;
}
-static bool parsePart2(ParseTreeNode* parentNode, bool& nonempty)
-{
+static bool parsePart2(ParseTreeNode* parentNode, bool& nonempty) {
// Store current state for rolling back if we fail
int curToken = said_token;
int curTreePos = said_tree_pos;
@@ -259,8 +257,7 @@ static bool parsePart2(ParseTreeNode* parentNode, bool& nonempty)
return false;
}
-static bool parsePart3(ParseTreeNode* parentNode, bool& nonempty)
-{
+static bool parsePart3(ParseTreeNode* parentNode, bool& nonempty) {
// Store current state for rolling back if we fail
int curToken = said_token;
int curTreePos = said_tree_pos;
@@ -318,8 +315,7 @@ static bool parsePart3(ParseTreeNode* parentNode, bool& nonempty)
}
-static bool parseSlash(ParseTreeNode* parentNode)
-{
+static bool parseSlash(ParseTreeNode* parentNode) {
// Store current state for rolling back if we fail
int curToken = said_token;
int curTreePos = said_tree_pos;
@@ -343,8 +339,7 @@ static bool parseSlash(ParseTreeNode* parentNode)
}
-static bool parseRef(ParseTreeNode* parentNode)
-{
+static bool parseRef(ParseTreeNode* parentNode) {
// Store current state for rolling back if we fail
int curToken = said_token;
int curTreePos = said_tree_pos;
@@ -411,8 +406,7 @@ static bool parseRef(ParseTreeNode* parentNode)
return false;
}
-static bool parseComma(ParseTreeNode* parentNode)
-{
+static bool parseComma(ParseTreeNode* parentNode) {
// Store current state for rolling back if we fail
int curToken = said_token;
int curTreePos = said_tree_pos;
@@ -435,8 +429,7 @@ static bool parseComma(ParseTreeNode* parentNode)
return false;
}
-static bool parseListEntry(ParseTreeNode* parentNode)
-{
+static bool parseListEntry(ParseTreeNode* parentNode) {
// Store current state for rolling back if we fail
int curToken = said_token;
int curTreePos = said_tree_pos;
@@ -494,8 +487,7 @@ static bool parseListEntry(ParseTreeNode* parentNode)
return false;
}
-static bool parseList(ParseTreeNode* parentNode)
-{
+static bool parseList(ParseTreeNode* parentNode) {
// Store current state for rolling back if we fail
int curToken = said_token;
int curTreePos = said_tree_pos;
@@ -524,8 +516,7 @@ static bool parseList(ParseTreeNode* parentNode)
return false;
}
-static bool parseExpr(ParseTreeNode* parentNode)
-{
+static bool parseExpr(ParseTreeNode* parentNode) {
// Store current state for rolling back if we fail
int curToken = said_token;
int curTreePos = said_tree_pos;
@@ -546,7 +537,6 @@ static bool parseExpr(ParseTreeNode* parentNode)
said_attach_subtree(newParent, 0x141, 0x14F, newNode);
newParent = newParent->right;
-
}
found = parseRef(newParent);
@@ -561,8 +551,7 @@ static bool parseExpr(ParseTreeNode* parentNode)
return false;
}
-static bool parseSpec(ParseTreeNode* parentNode)
-{
+static bool parseSpec(ParseTreeNode* parentNode) {
// Store current state for rolling back if we fail
int curToken = said_token;
int curTreePos = said_tree_pos;
@@ -748,9 +737,7 @@ static void node_print_desc(ParseTreeNode *) { }
-
-static int matchTrees(ParseTreeNode* parseT, ParseTreeNode* saidT)
-{
+static int matchTrees(ParseTreeNode* parseT, ParseTreeNode* saidT) {
outputDepth++;
scidprintf("%*smatchTrees on ", outputDepth, "");
node_print_desc(parseT);
diff --git a/engines/sci/parser/vocabulary.cpp b/engines/sci/parser/vocabulary.cpp
index b4a223dcff..000b037b44 100644
--- a/engines/sci/parser/vocabulary.cpp
+++ b/engines/sci/parser/vocabulary.cpp
@@ -530,18 +530,16 @@ bool Vocabulary::tokenizeString(ResultWordListList &retval, const char *sentence
*error = NULL;
do {
-
c = sentence[pos_in_sentence++];
+
if (Common::isAlnum(c) || (c == '-' && wordLen) || (c >= 0x80)) {
currentWord[wordLen] = lowerCaseMap[c];
++wordLen;
- }
- // Continue on this word */
- // Words may contain a '-', but may not
- // start with one.
- else {
- if (wordLen) { // Finished a word?
+ } else if (c == ' ' || c == '\0') {
+ // Continue on this word. Words may contain a '-', but may not start with
+ // one.
+ if (wordLen) { // Finished a word?
ResultWordList lookup_result;
// Look it up
diff --git a/engines/sci/resource.cpp b/engines/sci/resource.cpp
index 17195c14b8..10740a8b7b 100644
--- a/engines/sci/resource.cpp
+++ b/engines/sci/resource.cpp
@@ -55,6 +55,11 @@ SciVersion getSciVersion() {
return s_sciVersion;
}
+SciVersion getSciVersionForDetection() {
+ assert(!g_sci);
+ return s_sciVersion;
+}
+
const char *getSciVersionDesc(SciVersion version) {
switch (version) {
case SCI_VERSION_NONE:
@@ -88,9 +93,6 @@ const char *getSciVersionDesc(SciVersion version) {
//////////////////////////////////////////////////////////////////////
-
-#undef SCI_REQUIRE_RESOURCE_FILES
-
//#define SCI_VERBOSE_RESMAN 1
static const char *const s_errorDescriptions[] = {
@@ -639,7 +641,7 @@ int ResourceManager::addAppropriateSources() {
return 1;
}
-int ResourceManager::addAppropriateSources(const Common::FSList &fslist) {
+int ResourceManager::addAppropriateSourcesForDetection(const Common::FSList &fslist) {
ResourceSource *map = 0;
Common::Array<ResourceSource *> sci21Maps;
@@ -858,7 +860,7 @@ void ResourceManager::freeResourceSources() {
ResourceManager::ResourceManager() {
}
-void ResourceManager::init(bool initFromFallbackDetector) {
+void ResourceManager::init() {
_memoryLocked = 0;
_memoryLRU = 0;
_LRU.clear();
@@ -890,25 +892,24 @@ void ResourceManager::init(bool initFromFallbackDetector) {
debugC(1, kDebugLevelResMan, "resMan: Detected volume version %d: %s", _volVersion, versionDescription(_volVersion));
if ((_mapVersion == kResVersionUnknown) && (_volVersion == kResVersionUnknown)) {
- warning("Volume and map version not detected, assuming that this is not a sci game");
+ warning("Volume and map version not detected, assuming that this is not a SCI game");
_viewType = kViewUnknown;
return;
}
scanNewSources();
- if (!initFromFallbackDetector) {
- if (!addAudioSources()) {
- // FIXME: This error message is not always correct.
- // OTOH, it is nice to be able to detect missing files/sources
- // So we should definitely fix addAudioSources so this error
- // only pops up when necessary. Disabling for now.
- //error("Somehow I can't seem to find the sound files I need (RESOURCE.AUD/RESOURCE.SFX), aborting");
- }
- addScriptChunkSources();
- scanNewSources();
+ if (!addAudioSources()) {
+ // FIXME: This error message is not always correct.
+ // OTOH, it is nice to be able to detect missing files/sources
+ // So we should definitely fix addAudioSources so this error
+ // only pops up when necessary. Disabling for now.
+ //error("Somehow I can't seem to find the sound files I need (RESOURCE.AUD/RESOURCE.SFX), aborting");
}
+ addScriptChunkSources();
+ scanNewSources();
+
detectSciVersion();
debugC(1, kDebugLevelResMan, "resMan: Detected %s", getSciVersionDesc(getSciVersion()));
@@ -943,6 +944,22 @@ void ResourceManager::init(bool initFromFallbackDetector) {
}
}
+void ResourceManager::initForDetection() {
+ assert(!g_sci);
+
+ _memoryLocked = 0;
+ _memoryLRU = 0;
+ _LRU.clear();
+ _resMap.clear();
+ _audioMapSCI1 = NULL;
+
+ _mapVersion = detectMapVersion();
+ _volVersion = detectVolVersion();
+
+ scanNewSources();
+ detectSciVersion();
+}
+
ResourceManager::~ResourceManager() {
// freeing resources
ResourceMap::iterator itr = _resMap.begin();
@@ -1645,6 +1662,9 @@ int ResourceManager::readResourceMapSCI1(ResourceSource *map) {
do {
type = fileStream->readByte() & 0x1F;
resMap[type].wOffset = fileStream->readUint16LE();
+ if (fileStream->eos())
+ return SCI_ERROR_RESMAP_NOT_FOUND;
+
resMap[prevtype].wSize = (resMap[type].wOffset
- resMap[prevtype].wOffset) / nEntrySize;
prevtype = type;
@@ -2330,6 +2350,9 @@ bool ResourceManager::detectPaletteMergingSci11() {
// Old palette format used in palette resource? -> it's merging
if ((data[0] == 0 && data[1] == 1) || (data[0] == 0 && data[1] == 0 && READ_LE_UINT16(data + 29) == 0))
return true;
+ // Hardcoded: Laura Bow 2 floppy uses new palette resource, but still palette merging + 16 bit color matching
+ if ((g_sci->getGameId() == GID_LAURABOW2) && (!g_sci->isCD()) && (!g_sci->isDemo()))
+ return true;
return false;
}
return false;
diff --git a/engines/sci/resource.h b/engines/sci/resource.h
index e90f52a3ce..62f3c584ac 100644
--- a/engines/sci/resource.h
+++ b/engines/sci/resource.h
@@ -312,10 +312,22 @@ public:
/**
* Initializes the resource manager.
*/
- void init(bool initFromFallbackDetector = false);
+ void init();
+ /**
+ * Similar to the function above, only called from the fallback detector
+ */
+ void initForDetection();
+
+ /**
+ * Adds all of the resource files for a game
+ */
int addAppropriateSources();
- int addAppropriateSources(const Common::FSList &fslist); // TODO: Switch from FSList to Common::Archive?
+
+ /**
+ * Similar to the function above, only called from the fallback detector
+ */
+ int addAppropriateSourcesForDetection(const Common::FSList &fslist); // TODO: Switch from FSList to Common::Archive?
/**
* Looks up a resource's data.
diff --git a/engines/sci/resource_audio.cpp b/engines/sci/resource_audio.cpp
index 4c7cd9b84a..c775f502c5 100644
--- a/engines/sci/resource_audio.cpp
+++ b/engines/sci/resource_audio.cpp
@@ -110,7 +110,7 @@ bool Resource::loadFromAudioVolumeSCI11(Common::SeekableReadStream *file) {
unalloc();
return false;
}
-
+
_headerSize = file->readByte();
if (type == kResourceTypeAudio) {
@@ -710,7 +710,6 @@ SoundResource::SoundResource(uint32 resourceNr, ResourceManager *resMan, SciVers
// 0x20 is set on rhythm channels to prevent remapping
// CHECKME: Which SCI versions need that set manually?
- channel->flags = (*channel->data) >> 4;
if (channel->number == 9)
channel->flags |= 2;
// Note: flag 1: channel start offset is 0 instead of 10
diff --git a/engines/sci/sci.cpp b/engines/sci/sci.cpp
index fc723f18cf..60a1271b89 100644
--- a/engines/sci/sci.cpp
+++ b/engines/sci/sci.cpp
@@ -219,7 +219,7 @@ Common::Error SciEngine::run() {
// Add the after market GM patches for the specified game, if they exist
_resMan->addNewGMPatch(_gameId);
_gameObjectAddress = _resMan->findGameObject();
-
+
_scriptPatcher = new ScriptPatcher();
SegManager *segMan = new SegManager(_resMan, _scriptPatcher);
@@ -896,7 +896,7 @@ void SciEngine::syncSoundSettings() {
bool SciEngine::speechAndSubtitlesEnabled() {
bool subtitlesOn = ConfMan.getBool("subtitles");
bool speechOn = !ConfMan.getBool("speech_mute");
-
+
if (isCD() && subtitlesOn && speechOn)
return true;
return false;
@@ -936,7 +936,7 @@ void SciEngine::updateScummVMAudioOptions() {
// depending on the in-game settings
if (isCD() && getSciVersion() == SCI_VERSION_1_1) {
uint16 ingameSetting = _gamestate->variables[VAR_GLOBAL][90].getOffset();
-
+
switch (ingameSetting) {
case 1:
// subtitles
diff --git a/engines/sci/sci.h b/engines/sci/sci.h
index 48bc4819d2..4928fd1b4e 100644
--- a/engines/sci/sci.h
+++ b/engines/sci/sci.h
@@ -314,13 +314,16 @@ public:
* if NULL is passed no subtitle will be added to the returned string
* @return processed string
*/
- Common::String strSplit(const char *str, const char *sep = "\r----------\r");
+ Common::String strSplitLanguage(const char *str, uint16 *splitLanguage, const char *sep = "\r----------\r");
+ Common::String strSplit(const char *str, const char *sep = "\r----------\r") {
+ return strSplitLanguage(str, NULL, sep);
+ }
kLanguage getSciLanguage();
void setSciLanguage(kLanguage lang);
void setSciLanguage();
- Common::String getSciLanguageString(const Common::String &str, kLanguage lang, kLanguage *lang2 = NULL) const;
+ Common::String getSciLanguageString(const Common::String &str, kLanguage lang, kLanguage *lang2 = NULL, uint16 *languageSplitter = NULL) const;
// Check if vocabulary needs to get switched (in multilingual parser games)
void checkVocabularySwitch();
@@ -429,6 +432,12 @@ extern SciEngine *g_sci;
SciVersion getSciVersion();
/**
+ * Same as above, but this version doesn't assert on unknown SCI versions.
+ * Only used by the fallback detector
+ */
+SciVersion getSciVersionForDetection();
+
+/**
* Convenience function converting an SCI version into a human-readable string.
*/
const char *getSciVersionDesc(SciVersion version);
diff --git a/engines/sci/sound/drivers/midi.cpp b/engines/sci/sound/drivers/midi.cpp
index 8f535aeddc..baf85de74c 100644
--- a/engines/sci/sound/drivers/midi.cpp
+++ b/engines/sci/sound/drivers/midi.cpp
@@ -399,24 +399,42 @@ void MidiPlayer_Midi::playSwitch(bool play) {
}
bool MidiPlayer_Midi::isMt32GmPatch(const byte *data, int size) {
- if (size < 1155)
+ // WORKAROUND: Some Mac games (e.g. LSL5) may have an extra byte at the
+ // end, so compensate for that here - bug #6725.
+ if (size == 16890)
+ size--;
+
+ // Need at least 1153 + 2 bytes for a GM patch. Check readMt32GmPatch()
+ // below for more info.
+ if (size < 1153 + 2)
return false;
+ // The maximum number of bytes for an MT-32 patch is 16889. The maximum
+ // number of timbres is 64, which leads us to:
+ // 491 + 1 + 64 * 246 + 653 = 16889
if (size > 16889)
return true;
bool isMt32 = false;
bool isMt32Gm = false;
+ // First, check for a GM patch. The presence of MIDI data after the
+ // initial 1153 + 2 bytes indicates a GM patch
if (READ_LE_UINT16(data + 1153) + 1155 == size)
isMt32Gm = true;
- int pos = 492 + 246 * data[491];
+ // Now check for a regular MT-32 patch. Check readMt32Patch() below for
+ // more info.
+ // 491 = 20 + 20 + 20 + 2 + 1 + 11 + 3 * 11 + 256 + 128
+ byte timbresNr = data[491];
+ int pos = 492 + 246 * timbresNr;
+ // Patches 49-96
if ((size >= (pos + 386)) && (READ_BE_UINT16(data + pos) == 0xabcd))
- pos += 386;
+ pos += 386; // 256 + 128 + 2
+ // Rhythm key map + partial reserve
if ((size >= (pos + 267)) && (READ_BE_UINT16(data + pos) == 0xdcba))
- pos += 267;
+ pos += 267; // 256 + 9 + 2
if (size == pos)
isMt32 = true;
@@ -460,10 +478,28 @@ void MidiPlayer_Midi::sendMt32SysEx(const uint32 addr, const byte *buf, int len,
}
void MidiPlayer_Midi::readMt32Patch(const byte *data, int size) {
+ // MT-32 patch contents:
+ // - 20 bytes unkown
+ // - 20 bytes before-SysEx message
+ // - 20 bytes goodbye SysEx message
+ // - 2 bytes volume
+ // - 1 byte reverb
+ // - 11 bytes reverb Sysex message
+ // - 3 * 11 reverb data
+ // - 256 + 128 bytes patches 1-48
+ // --> total: 491 bytes
+ // - 1 byte number of timbres (64 max)
+ // - 246 * timbres timbre data
+ // - 2 bytes flag (0xabcd)
+ // - 256 + 128 bytes patches 49-96
+ // - 2 bytes flag (0xdcba)
+ // - 256 bytes rhythm key map
+ // - 9 bytes partial reserve
+
Common::MemoryReadStream *str = new Common::MemoryReadStream(data, size);
// Send before-SysEx text
- str->seek(0x14);
+ str->seek(20);
sendMt32SysEx(0x200000, str, 20);
// Save goodbye message
@@ -527,15 +563,25 @@ void MidiPlayer_Midi::readMt32Patch(const byte *data, int size) {
}
void MidiPlayer_Midi::readMt32GmPatch(const byte *data, int size) {
- memcpy(_patchMap, data, 0x80);
- memcpy(_keyShift, data + 0x80, 0x80);
- memcpy(_volAdjust, data + 0x100, 0x80);
- memcpy(_percussionMap, data + 0x180, 0x80);
- _channels[MIDI_RHYTHM_CHANNEL].volAdjust = data[0x200];
- memcpy(_velocityMapIdx, data + 0x201, 0x80);
- memcpy(_velocityMap, data + 0x281, 0x200);
-
- uint16 midiSize = READ_LE_UINT16(data + 0x481);
+ // GM patch contents:
+ // - 128 bytes patch map
+ // - 128 bytes key shift
+ // - 128 bytes volume adjustment
+ // - 128 bytes percussion map
+ // - 1 byte volume adjust for the rhythm channel
+ // - 128 bytes velocity map IDs
+ // - 512 bytes velocity map
+ // --> total: 1153 bytes
+
+ memcpy(_patchMap, data, 128);
+ memcpy(_keyShift, data + 128, 128);
+ memcpy(_volAdjust, data + 256, 128);
+ memcpy(_percussionMap, data + 384, 128);
+ _channels[MIDI_RHYTHM_CHANNEL].volAdjust = data[512];
+ memcpy(_velocityMapIdx, data + 513, 128);
+ memcpy(_velocityMap, data + 641, 512);
+
+ uint16 midiSize = READ_LE_UINT16(data + 1153);
if (midiSize > 0) {
if (size < midiSize + 1155)
@@ -956,7 +1002,7 @@ int MidiPlayer_Midi::open(ResourceManager *resMan) {
if (getSciVersion() >= SCI_VERSION_1_EGA_ONLY)
warning("The automatic mapping for General MIDI hasn't been worked on for "
"SCI1 games. Music might sound wrong or broken. Please choose another "
- "music driver for this game (e.g. Adlib or MT-32) if you are "
+ "music driver for this game (e.g. AdLib or MT-32) if you are "
"experiencing issues with music");
// Modify velocity map to make low velocity notes a little louder
diff --git a/engines/sci/sound/music.cpp b/engines/sci/sound/music.cpp
index 362cca699d..7a6eaf62b4 100644
--- a/engines/sci/sound/music.cpp
+++ b/engines/sci/sound/music.cpp
@@ -142,7 +142,7 @@ void SciMusic::init() {
_driverLastChannel = _pMidiDrv->getLastChannel();
if (getSciVersion() <= SCI_VERSION_0_LATE)
_globalReverb = _pMidiDrv->getReverb(); // Init global reverb for SCI0
-
+
_currentlyPlayingSample = NULL;
}
diff --git a/engines/sci/sound/music.h b/engines/sci/sound/music.h
index 6149bb799e..4e44074630 100644
--- a/engines/sci/sound/music.h
+++ b/engines/sci/sound/music.h
@@ -264,7 +264,7 @@ private:
int _driverFirstChannel;
int _driverLastChannel;
-
+
MusicEntry *_currentlyPlayingSample;
};
diff --git a/engines/scumm/POTFILES b/engines/scumm/POTFILES
index 6034320259..6d10537d3c 100644
--- a/engines/scumm/POTFILES
+++ b/engines/scumm/POTFILES
@@ -1,3 +1,6 @@
engines/scumm/dialogs.cpp
engines/scumm/help.cpp
engines/scumm/scumm.cpp
+engines/scumm/players/player_v3m.cpp
+engines/scumm/players/player_v5m.cpp
+
diff --git a/engines/scumm/cdda.cpp b/engines/scumm/cdda.cpp
index adb414ecce..d797712a31 100644
--- a/engines/scumm/cdda.cpp
+++ b/engines/scumm/cdda.cpp
@@ -46,7 +46,7 @@ private:
public:
CDDAStream(Common::SeekableReadStream *stream, DisposeAfterUse::Flag disposeAfterUse);
virtual ~CDDAStream();
-
+
int readBuffer(int16 *buffer, const int numSamples);
bool isStereo() const { return true; }
int getRate() const { return 44100; }
diff --git a/engines/scumm/charset.cpp b/engines/scumm/charset.cpp
index 185ebbce6e..e546c805b5 100644
--- a/engines/scumm/charset.cpp
+++ b/engines/scumm/charset.cpp
@@ -253,7 +253,7 @@ CharsetRenderer::~CharsetRenderer() {
CharsetRendererCommon::CharsetRendererCommon(ScummEngine *vm)
: CharsetRenderer(vm), _bytesPerPixel(0), _fontHeight(0), _numChars(0) {
- _shadowMode = false;
+ _enableShadow = false;
_shadowColor = 0;
}
@@ -392,6 +392,10 @@ int CharsetRenderer::getStringWidth(int arg, const byte *text) {
} else if (chr & 0x80) {
pos++;
width += _vm->_2byteWidth;
+ // Original keeps glyph width and character dimensions separately
+ if (_vm->_language == Common::KO_KOR || _vm->_language == Common::ZH_TWN) {
+ width++;
+ }
continue;
}
}
@@ -478,6 +482,12 @@ void CharsetRenderer::addLinebreaks(int a, byte *str, int pos, int maxwidth) {
} else if (chr & 0x80) {
pos++;
curw += _vm->_2byteWidth;
+ // Original keeps glyph width and character dimensions separately
+ if (_vm->_language == Common::KO_KOR || _vm->_language == Common::ZH_TWN) {
+ curw++;
+ }
+ } else {
+ curw += getCharWidth(chr);
}
} else {
curw += getCharWidth(chr);
@@ -507,12 +517,17 @@ int CharsetRendererV3::getCharWidth(uint16 chr) {
return spacing;
}
-void CharsetRendererV3::enableShadow(bool enable) {
+void CharsetRendererPC::enableShadow(bool enable) {
_shadowColor = 0;
- _shadowMode = enable;
+ _enableShadow = enable;
+
+ if (_vm->_game.version >= 7 && _vm->_language == Common::KO_KOR)
+ _shadowType = kHorizontalShadowType;
+ else
+ _shadowType = kNormalShadowType;
}
-void CharsetRendererV3::drawBits1(Graphics::Surface &dest, int x, int y, const byte *src, int drawTop, int width, int height) {
+void CharsetRendererPC::drawBits1(Graphics::Surface &dest, int x, int y, const byte *src, int drawTop, int width, int height) {
byte *dst = (byte *)dest.getBasePtr(x, y);
byte bits = 0;
@@ -525,8 +540,12 @@ void CharsetRendererV3::drawBits1(Graphics::Surface &dest, int x, int y, const b
if ((x % 8) == 0)
bits = *src++;
if ((bits & revBitMask(x % 8)) && y + drawTop >= 0) {
- if (_shadowMode)
- dst[1] = dst2[0] = dst2[1] = _shadowColor;
+ if (_enableShadow) {
+ if (_shadowType == kNormalShadowType)
+ dst[1] = dst2[0] = dst2[1] = _shadowColor;
+ else if (_shadowType == kHorizontalShadowType)
+ dst[1] = _shadowColor;
+ }
dst[0] = col;
}
dst += dest.format.bytesPerPixel;
@@ -615,7 +634,7 @@ void CharsetRendererV3::printChar(int chr, bool ignoreCharsetMask) {
if (_left + origWidth > _right + 1)
return;
- if (_shadowMode) {
+ if (_enableShadow) {
width++;
height++;
}
@@ -658,7 +677,7 @@ void CharsetRendererV3::printChar(int chr, bool ignoreCharsetMask) {
if (_str.right < _left) {
_str.right = _left;
- if (_shadowMode)
+ if (_enableShadow)
_str.right++;
}
@@ -776,11 +795,15 @@ void CharsetRendererClassic::printChar(int chr, bool ignoreCharsetMask) {
printCharIntern(is2byte, _charPtr, _origWidth, _origHeight, _width, _height, vs, ignoreCharsetMask);
+ // Original keeps glyph width and character dimensions separately
+ if ((_vm->_language == Common::ZH_TWN || _vm->_language == Common::KO_KOR) && is2byte)
+ _origWidth++;
+
_left += _origWidth;
if (_str.right < _left) {
_str.right = _left;
- if (_vm->_game.platform != Common::kPlatformFMTowns && _shadowMode)
+ if (_vm->_game.platform != Common::kPlatformFMTowns && _enableShadow)
_str.right++;
}
@@ -844,7 +867,10 @@ void CharsetRendererClassic::printCharIntern(bool is2byte, const byte *charPtr,
drawTop = _top - _vm->_screenTop;
}
- drawBitsN(dstSurface, dstPtr, charPtr, *_fontPtr, drawTop, origWidth, origHeight);
+ if (is2byte && _vm->_game.platform != Common::kPlatformFMTowns)
+ drawBits1(dstSurface, _left, drawTop, charPtr, drawTop, origWidth, origHeight);
+ else
+ drawBitsN(dstSurface, dstPtr, charPtr, *_fontPtr, drawTop, origWidth, origHeight);
if (_blitAlso && vs->hasTwoBuffers) {
// FIXME: Revisiting this code, I think the _blitAlso mode is likely broken
@@ -884,6 +910,24 @@ void CharsetRendererClassic::printCharIntern(bool is2byte, const byte *charPtr,
}
bool CharsetRendererClassic::prepareDraw(uint16 chr) {
+ bool is2byte = (chr >= 256 && _vm->_useCJKMode);
+ if (is2byte) {
+ if (_vm->_language == Common::KO_KOR)
+ enableShadow(true);
+
+ _charPtr = _vm->get2byteCharPtr(chr);
+ _width = _origWidth = _vm->_2byteWidth;
+ _height = _origHeight = _vm->_2byteHeight;
+ _offsX = _offsY = 0;
+
+ if (_enableShadow) {
+ _width++;
+ _height++;
+ }
+
+ return true;
+ }
+
uint32 charOffs = READ_LE_UINT32(_fontPtr + chr * 4 + 4);
assert(charOffs < 0x14000);
if (!charOffs)
@@ -908,8 +952,14 @@ bool CharsetRendererClassic::prepareDraw(uint16 chr) {
void CharsetRendererClassic::drawChar(int chr, Graphics::Surface &s, int x, int y) {
if (!prepareDraw(chr))
return;
+
byte *dst = (byte *)s.getBasePtr(x, y);
- drawBitsN(s, dst, _charPtr, *_fontPtr, y, _width, _height);
+
+ bool is2byte = (_vm->_useCJKMode && chr >= 256);
+ if (is2byte)
+ drawBits1(s, x, y, _charPtr, y, _width, _height);
+ else
+ drawBitsN(s, dst, _charPtr, *_fontPtr, y, _width, _height);
}
void CharsetRendererClassic::drawBitsN(const Graphics::Surface &s, byte *dst, const byte *src, byte bpp, int drawTop, int width, int height) {
@@ -982,7 +1032,7 @@ int CharsetRendererTownsV3::getFontHeight() {
void CharsetRendererTownsV3::enableShadow(bool enable) {
_shadowColor = 8;
- _shadowMode = enable;
+ _enableShadow = enable;
#ifndef DISABLE_TOWNS_DUAL_LAYER_MODE
_shadowColor = 0x88;
@@ -1027,13 +1077,13 @@ void CharsetRendererTownsV3::drawBits1(Graphics::Surface &dest, int x, int y, co
bits = *src++;
if ((bits & revBitMask(x % 8)) && y + drawTop >= 0) {
if (dest.format.bytesPerPixel == 2) {
- if (_shadowMode) {
+ if (_enableShadow) {
WRITE_UINT16(dst + 2, _vm->_16BitPalette[_shadowColor]);
WRITE_UINT16(dst + dest.pitch, _vm->_16BitPalette[_shadowColor]);
}
WRITE_UINT16(dst, _vm->_16BitPalette[_color]);
} else {
- if (_shadowMode) {
+ if (_enableShadow) {
#ifndef DISABLE_TOWNS_DUAL_LAYER_MODE
if (scale2x) {
dst[2] = dst[3] = dst2[2] = dst2[3] = _shadowColor;
@@ -1124,11 +1174,11 @@ void CharsetRendererPCE::drawBits1(Graphics::Surface &dest, int x, int y, const
bits = *src++;
if ((bits & revBitMask(bitCount % 8)) && y + drawTop >= 0) {
if (dest.format.bytesPerPixel == 2) {
- if (_shadowMode)
+ if (_enableShadow)
WRITE_UINT16(dst + dest.pitch + 2, _vm->_16BitPalette[_shadowColor]);
WRITE_UINT16(dst, _vm->_16BitPalette[_color]);
} else {
- if (_shadowMode)
+ if (_enableShadow)
*(dst + dest.pitch + 1) = _shadowColor;
*dst = _color;
}
@@ -1227,7 +1277,8 @@ void CharsetRendererNut::printChar(int chr, bool ignoreCharsetMask) {
int width = _current->getCharWidth(chr);
int height = _current->getCharHeight(chr);
- if (chr >= 256 && _vm->_useCJKMode)
+ bool is2byte = chr >= 256 && _vm->_useCJKMode;
+ if (is2byte)
width = _vm->_2byteWidth;
shadow.right = _left + width;
@@ -1259,8 +1310,8 @@ void CharsetRendererNut::printChar(int chr, bool ignoreCharsetMask) {
_str.left = _left;
// Original keeps glyph width and character dimensions separately
- if (_vm->_language == Common::ZH_TWN && width == 16)
- width = 17;
+ if ((_vm->_language == Common::ZH_TWN || _vm->_language == Common::KO_KOR) && is2byte)
+ width++;
_left += width;
@@ -1327,7 +1378,7 @@ void CharsetRendererNES::printChar(int chr, bool ignoreCharsetMask) {
if (_str.right < _left) {
_str.right = _left;
- if (_shadowMode)
+ if (_enableShadow)
_str.right++;
}
@@ -1483,7 +1534,7 @@ bool CharsetRendererTownsClassic::prepareDraw(uint16 chr) {
_origHeight = _height = _vm->_2byteHeight;
_charPtr = _vm->get2byteCharPtr(chr);
_offsX = _offsY = 0;
- if (_shadowMode) {
+ if (_enableShadow) {
_width++;
_height++;
}
@@ -1495,7 +1546,7 @@ bool CharsetRendererTownsClassic::prepareDraw(uint16 chr) {
}
void CharsetRendererTownsClassic::setupShadowMode() {
- _shadowMode = true;
+ _enableShadow = true;
_shadowColor = _vm->_townsCharsetColorMap[0];
assert(_vm->_cjkFont);
diff --git a/engines/scumm/charset.h b/engines/scumm/charset.h
index 5a9977b7d6..b4b3d88ccd 100644
--- a/engines/scumm/charset.h
+++ b/engines/scumm/charset.h
@@ -100,7 +100,7 @@ protected:
int _numChars;
byte _shadowColor;
- bool _shadowMode;
+ bool _enableShadow;
public:
CharsetRendererCommon(ScummEngine *vm);
@@ -110,7 +110,24 @@ public:
virtual int getFontHeight();
};
-class CharsetRendererClassic : public CharsetRendererCommon {
+class CharsetRendererPC : public CharsetRendererCommon {
+ enum ShadowType {
+ kNoShadowType,
+ kNormalShadowType,
+ kHorizontalShadowType
+ };
+
+ ShadowType _shadowType;
+
+protected:
+ virtual void enableShadow(bool enable);
+ virtual void drawBits1(Graphics::Surface &dest, int x, int y, const byte *src, int drawTop, int width, int height);
+
+public:
+ CharsetRendererPC(ScummEngine *vm) : CharsetRendererCommon(vm), _shadowType(kNoShadowType) { }
+};
+
+class CharsetRendererClassic : public CharsetRendererPC {
protected:
virtual void drawBitsN(const Graphics::Surface &s, byte *dst, const byte *src, byte bpp, int drawTop, int width, int height);
void printCharIntern(bool is2byte, const byte *charPtr, int origWidth, int origHeight, int width, int height, VirtScreen *vs, bool ignoreCharsetMask);
@@ -124,7 +141,7 @@ protected:
VirtScreenNumber _drawScreen;
public:
- CharsetRendererClassic(ScummEngine *vm) : CharsetRendererCommon(vm) {}
+ CharsetRendererClassic(ScummEngine *vm) : CharsetRendererPC(vm) {}
void printChar(int chr, bool ignoreCharsetMask);
void drawChar(int chr, Graphics::Surface &s, int x, int y);
@@ -170,10 +187,8 @@ public:
int getCharWidth(uint16 chr) { return 8; }
};
-class CharsetRendererV3 : public CharsetRendererCommon {
+class CharsetRendererV3 : public CharsetRendererPC {
protected:
- virtual void enableShadow(bool enable);
- virtual void drawBits1(Graphics::Surface &dest, int x, int y, const byte *src, int drawTop, int width, int height);
virtual int getDrawWidthIntern(uint16 chr);
virtual int getDrawHeightIntern(uint16 chr);
virtual void setDrawCharIntern(uint16 chr) {}
@@ -181,7 +196,7 @@ protected:
const byte *_widthTable;
public:
- CharsetRendererV3(ScummEngine *vm) : CharsetRendererCommon(vm) {}
+ CharsetRendererV3(ScummEngine *vm) : CharsetRendererPC(vm) {}
void printChar(int chr, bool ignoreCharsetMask);
void drawChar(int chr, Graphics::Surface &s, int x, int y);
diff --git a/engines/scumm/detection.cpp b/engines/scumm/detection.cpp
index 7cd50e1f4c..c0db0d6d37 100644
--- a/engines/scumm/detection.cpp
+++ b/engines/scumm/detection.cpp
@@ -244,7 +244,7 @@ static Common::String generateFilenameForDetection(const char *pattern, Filename
case kGenRoomNum:
result = Common::String::format(pattern, 0);
break;
-
+
case kGenDiskNumSteam:
case kGenRoomNumSteam: {
const SteamIndexFile *indexFile = lookUpSteamIndexFile(pattern, platform);
@@ -502,12 +502,7 @@ static void computeGameSettingsFromMD5(const Common::FSList &fslist, const GameF
// (since they have identical MD5):
if (dr.game.id == GID_MANIAC && !strcmp(gfp->pattern, "%02d.MAN")) {
dr.extra = "V1 Demo";
- }
-
- // HACK: If 'Demo' occurs in the extra string, set the GF_DEMO flag,
- // required by some game demos (e.g. Dig, FT and COMI).
- if (dr.extra && strstr(dr.extra, "Demo")) {
- dr.game.features |= GF_DEMO;
+ dr.game.features = GF_DEMO;
}
// HACK: Try to detect languages for translated games
diff --git a/engines/scumm/detection_tables.h b/engines/scumm/detection_tables.h
index ae334c201c..3f08f17aff 100644
--- a/engines/scumm/detection_tables.h
+++ b/engines/scumm/detection_tables.h
@@ -260,13 +260,16 @@ static const GameSettings gameVariantsTable[] = {
{"samnmax", "Floppy", 0, GID_SAMNMAX, 6, 0, MDT_ADLIB | MDT_MIDI | MDT_PREFER_GM, GF_USE_KEY, UNK, GUIO1(GUIO_NOSPEECH)},
#ifdef ENABLE_SCUMM_7_8
- {"ft", 0, 0, GID_FT, 7, 0, MDT_NONE, 0, UNK, GUIO1(GUIO_NOMIDI)},
+ {"ft", "", 0, GID_FT, 7, 0, MDT_NONE, 0, UNK, GUIO1(GUIO_NOMIDI)},
+ {"ft", "Demo", 0, GID_FT, 7, 0, MDT_NONE, GF_DEMO, UNK, GUIO1(GUIO_NOMIDI)},
- {"dig", "", 0, GID_DIG, 7, 0, MDT_NONE, 0, UNK, GUIO1(GUIO_NOMIDI)},
+ {"dig", "", 0, GID_DIG, 7, 0, MDT_NONE, 0, UNK, GUIO1(GUIO_NOMIDI)},
+ {"dig", "Demo", 0, GID_DIG, 7, 0, MDT_NONE, GF_DEMO, UNK, GUIO1(GUIO_NOMIDI)},
{"dig", "Steam", "steam", GID_DIG, 7, 0, MDT_NONE, 0, UNK, GUIO1(GUIO_NOMIDI)},
- {"comi", 0, 0, GID_CMI, 8, 0, MDT_NONE, 0, Common::kPlatformWindows, GUIO2(GUIO_NOMIDI, GUIO_NOASPECT)},
-#endif
+ {"comi", "", 0, GID_CMI, 8, 0, MDT_NONE, 0, Common::kPlatformWindows, GUIO2(GUIO_NOMIDI, GUIO_NOASPECT)},
+ {"comi", "Demo", 0, GID_CMI, 8, 0, MDT_NONE, GF_DEMO, Common::kPlatformWindows, GUIO2(GUIO_NOMIDI, GUIO_NOASPECT)},
+ #endif
// Humongous Entertainment Scumm Version 6
{"activity", "", 0, GID_HEGAME, 6, 62, MDT_ADLIB | MDT_MIDI, GF_USE_KEY, UNK, GUIO1(GUIO_NOLAUNCHLOAD)},
@@ -677,12 +680,13 @@ static const GameFilenamePattern gameFilenamesTable[] = {
{ "freddi", "Freddi Demo", kGenHEMac, UNK_LANG, Common::kPlatformMacintosh, 0 },
{ "freddi", "Freddi Fish", kGenHEMac, UNK_LANG, Common::kPlatformMacintosh, 0 },
{ "freddi", "FreddiD", kGenHEPC, Common::NL_NLD, UNK, 0 },
+ { "freddi", "FreddiE", kGenHEPC, UNK_LANG, UNK, 0 },
{ "freddi", "Freddi Fisk", kGenHEMac, Common::SE_SWE, Common::kPlatformMacintosh, 0 },
{ "freddi", "FRITZI", kGenHEPC, Common::DE_DEU, UNK, 0 },
{ "freddi", "Marine Malice", kGenHEMac, Common::FR_FRA, Common::kPlatformMacintosh, 0 },
{ "freddi", "MM-DEMO", kGenHEPC, UNK_LANG, UNK, 0 },
- { "freddi2", "freddi2", kGenHEPC, UNK_LANG, UNK, 0 },
+ { "freddi2", "freddi2", kGenHEPC, UNK_LANG, Common::kPlatformWindows, 0 },
{ "freddi2", "FF2-demo", kGenHEMac, UNK_LANG, Common::kPlatformMacintosh, 0 },
{ "freddi2", "ff2-demo", kGenHEPC, UNK_LANG, Common::kPlatformWindows, 0 },
{ "freddi2", "FFHSDemo", kGenHEMac, UNK_LANG, Common::kPlatformMacintosh, 0 },
@@ -744,7 +748,7 @@ static const GameFilenamePattern gameFilenamesTable[] = {
{ "lost", "lost", kGenHEPC, UNK_LANG, UNK, 0 },
{ "lost", "Lost and Found", kGenHEMac, UNK_LANG, Common::kPlatformMacintosh, 0 },
{ "lost", "smaller", kGenHEPC, UNK_LANG, UNK, 0 },
- { "lost", "verloren", kGenHEPC, Common::NL_NLD, UNK, 0 },
+ { "lost", "verloren", kGenHEPC, Common::NL_NLD, Common::kPlatformWindows, 0 },
{ "lost", "Verloren", kGenHEMac, Common::NL_NLD, Common::kPlatformMacintosh, 0 },
{ "maze", "maze", kGenHEPC, UNK_LANG, UNK, 0 },
@@ -789,7 +793,7 @@ static const GameFilenamePattern gameFilenamesTable[] = {
{ "pajama2", "PJ2 Demo", kGenHEMac, Common::NL_NLD, Common::kPlatformMacintosh, 0 },
{ "pajama2", "PS2DEMO", kGenHEPC, Common::HE_ISR, UNK, 0 },
- { "pajama3", "pajama3", kGenHEPC, UNK_LANG, UNK, 0 },
+ { "pajama3", "pajama3", kGenHEPC, UNK_LANG, Common::kPlatformWindows, 0 },
{ "pajama3", "FPJ3Demo", kGenHEPC, Common::FR_FRA, UNK, 0 },
{ "pajama3", "GPJ3Demo", kGenHEPC, Common::DE_DEU, UNK, 0 },
{ "pajama3", "PajamaHTF", kGenHEMac, UNK_LANG, Common::kPlatformMacintosh, 0 },
@@ -888,7 +892,7 @@ static const GameFilenamePattern gameFilenamesTable[] = {
{ "socks", "socks", kGenHEPC, UNK_LANG, UNK, 0 },
{ "socks", "SockWorks", kGenHEMac, UNK_LANG, Common::kPlatformMacintosh, 0 },
- { "socks", "SokkenSoep", kGenHEPC, Common::NL_NLD, UNK, 0 },
+ { "socks", "SokkenSoep", kGenHEPC, Common::NL_NLD, Common::kPlatformWindows, 0 },
{ "socks", "SokkenSoep", kGenHEMac, Common::NL_NLD, Common::kPlatformMacintosh, 0 },
{ "spyfox", "spyfox", kGenHEPC, UNK_LANG, Common::kPlatformWindows, 0 },
diff --git a/engines/scumm/dialogs.cpp b/engines/scumm/dialogs.cpp
index 8321daa583..c22525b6f2 100644
--- a/engines/scumm/dialogs.cpp
+++ b/engines/scumm/dialogs.cpp
@@ -180,9 +180,9 @@ static const ResString string_map_table_v345[] = {
// I18N: You may specify 'Yes' symbol at the end of the line, like this:
// "Moechten Sie wirklich neu starten? (J/N)J"
// Will react to J as 'Yes'
- {5, _s("Are you sure you want to restart? (Y/N)")},
+ {5, _s("Are you sure you want to restart? (Y/N)Y")},
// I18N: you may specify 'Yes' symbol at the end of the line. See previous comment
- {6, _s("Are you sure you want to quit? (Y/N)")},
+ {6, _s("Are you sure you want to quit? (Y/N)Y")},
// Added in SCUMM4
{7, _s("Save")},
@@ -428,7 +428,9 @@ const Common::String InfoDialog::queryResString(int stringno) {
if (stringno == 0)
return String();
- if (_vm->_game.version == 8)
+ if (_vm->_game.heversion >= 80)
+ return _(string_map_table_v6[stringno - 1].string);
+ else if (_vm->_game.version == 8)
result = (const byte *)string_map_table_v8[stringno - 1].string;
else if (_vm->_game.version == 7)
result = _vm->getStringAddressVar(string_map_table_v7[stringno - 1].num);
@@ -458,7 +460,7 @@ const Common::String InfoDialog::queryResString(int stringno) {
tmp += chr;
}
}
- return tmp;
+ return _(tmp);
}
#pragma mark -
diff --git a/engines/scumm/nut_renderer.cpp b/engines/scumm/nut_renderer.cpp
index 1d5761ef48..d8672c473c 100644
--- a/engines/scumm/nut_renderer.cpp
+++ b/engines/scumm/nut_renderer.cpp
@@ -395,10 +395,6 @@ void NutRenderer::drawChar(const Graphics::Surface &s, byte c, int x, int y, byt
}
void NutRenderer::draw2byte(const Graphics::Surface &s, int c, int x, int y, byte color) {
- // FIXME: This gets passed a const destination Surface. Intuitively this
- // should never get written to. But sadly it does... For now we simply
- // cast the const qualifier away.
- byte *dst = (byte *)const_cast<void *>(s.getBasePtr(x, y));
const int width = _vm->_2byteWidth;
const int height = MIN(_vm->_2byteHeight, s.h - y);
const byte *src = _vm->get2byteCharPtr(c);
@@ -408,17 +404,50 @@ void NutRenderer::draw2byte(const Graphics::Surface &s, int c, int x, int y, byt
return;
}
- for (int ty = 0; ty < height; ty++) {
- for (int tx = 0; tx < width; tx++) {
- if ((tx & 7) == 0)
- bits = *src++;
- if (x + tx < 0 || x + tx >= s.w || y + ty < 0)
- continue;
- if (bits & revBitMask(tx % 8)) {
- dst[tx] = color;
+ enum ShadowMode {
+ kNone,
+ kKoreanV8ShadowMode
+ };
+
+ ShadowMode shadowMode = kNone;
+
+ if (_vm->_language == Common::KO_KOR && _vm->_game.version == 8) {
+ shadowMode = kKoreanV8ShadowMode;
+ }
+
+ int shadowOffsetXTable[4] = {-1, 0, 1, 0};
+ int shadowOffsetYTable[4] = {0, 1, 0, 0};
+ int shadowOffsetColorTable[4] = {0, 0, 0, color};
+
+ int shadowIdx = 3;
+ if (shadowMode == kKoreanV8ShadowMode)
+ shadowIdx = 0;
+
+ const byte *origSrc = src;
+
+ for (; shadowIdx < 4; shadowIdx++) {
+ int offX = x + shadowOffsetXTable[shadowIdx];
+ int offY = y + shadowOffsetYTable[shadowIdx];
+ byte drawColor = shadowOffsetColorTable[shadowIdx];
+
+ // FIXME: This gets passed a const destination Surface. Intuitively this
+ // should never get written to. But sadly it does... For now we simply
+ // cast the const qualifier away.
+ byte *dst = (byte *)const_cast<void *>(s.getBasePtr(offX, offY));
+ src = origSrc;
+
+ for (int ty = 0; ty < height; ty++) {
+ for (int tx = 0; tx < width; tx++) {
+ if ((tx & 7) == 0)
+ bits = *src++;
+ if (offX + tx < 0 || offX + tx >= s.w || offY + ty < 0)
+ continue;
+ if (bits & revBitMask(tx % 8)) {
+ dst[tx] = drawColor;
+ }
}
+ dst += s.pitch;
}
- dst += s.pitch;
}
}
diff --git a/engines/scumm/object.cpp b/engines/scumm/object.cpp
index 7919075d0b..db836467ef 100644
--- a/engines/scumm/object.cpp
+++ b/engines/scumm/object.cpp
@@ -1013,7 +1013,6 @@ void ScummEngine::resetRoomObject(ObjectData *od, const byte *room, const byte *
od->actordir = (byte)READ_LE_UINT16(&imhd->v7.actordir);
} else if (_game.version == 6) {
- assert(imhd);
od->obj_nr = READ_LE_UINT16(&(cdhd->v6.obj_id));
od->width = READ_LE_UINT16(&cdhd->v6.w);
diff --git a/engines/scumm/players/player_mac.cpp b/engines/scumm/players/player_mac.cpp
index fe15698494..634fd2de2b 100644
--- a/engines/scumm/players/player_mac.cpp
+++ b/engines/scumm/players/player_mac.cpp
@@ -21,7 +21,6 @@
*/
#include "common/macresman.h"
-#include "common/translation.h"
#include "engines/engine.h"
#include "gui/message.h"
#include "scumm/players/player_mac.h"
diff --git a/engines/scumm/saveload.cpp b/engines/scumm/saveload.cpp
index 7eadb042fb..0c0f6be73b 100644
--- a/engines/scumm/saveload.cpp
+++ b/engines/scumm/saveload.cpp
@@ -109,7 +109,12 @@ Common::Error ScummEngine::saveGameState(int slot, const Common::String &desc) {
}
bool ScummEngine::canSaveGameStateCurrently() {
- // FIXME: For now always allow loading in V0-V3 games
+ // Disallow saving in v0-v3 games when a 'prequel' to a cutscene is shown.
+ // This is a blank screen with text, and while this is shown, saving should
+ // be disabled, as no room is set.
+ if (_game.version <= 3 && _currentScript == 0xFF && _roomResource == 0 && _currentRoom == 0)
+ return false;
+
// TODO: Should we disallow saving in some more places,
// e.g. when a SAN movie is playing? Not sure whether the
// original EXE allowed this.
diff --git a/engines/scumm/script.cpp b/engines/scumm/script.cpp
index 2c672ccc89..2fe5333bfc 100644
--- a/engines/scumm/script.cpp
+++ b/engines/scumm/script.cpp
@@ -972,6 +972,18 @@ void ScummEngine::runEntryScript() {
runScript(VAR(VAR_ENTRY_SCRIPT2), 0, 0, 0);
}
+void ScummEngine::runQuitScript() {
+ if (VAR_QUIT_SCRIPT != 0xFF && VAR(VAR_QUIT_SCRIPT)) {
+ int args[NUM_SCRIPT_LOCAL];
+
+ memset(args, 0, sizeof(args));
+ args[0] = 2;
+ args[1] = 1003;
+
+ runScript(VAR(VAR_QUIT_SCRIPT), 0, 0, args);
+ }
+}
+
void ScummEngine::killScriptsAndResources() {
ScriptSlot *ss;
int i;
diff --git a/engines/scumm/script_v0.cpp b/engines/scumm/script_v0.cpp
index a7999a2695..af39fdaad8 100644
--- a/engines/scumm/script_v0.cpp
+++ b/engines/scumm/script_v0.cpp
@@ -589,9 +589,9 @@ void ScummEngine_v0::o_loadRoomWithEgo() {
return;
}
- // The original interpreter seems to set the actors new room X/Y to the last rooms X/Y
- // This fixes a problem with MM: script 158 in room 12, the 'Oompf!' script
- // This scripts runs before the actor position is set to the correct location
+ // The original interpreter sets the actors new room X/Y to the last rooms X/Y
+ // This fixes a problem with MM: script 158 in room 12, the 'Oomph!' script
+ // This scripts runs before the actor position is set to the correct room entry location
a->putActor(a->getPos().x, a->getPos().y, room);
_egoPositioned = false;
diff --git a/engines/scumm/script_v2.cpp b/engines/scumm/script_v2.cpp
index 74d0aa2483..a7ec2e644f 100644
--- a/engines/scumm/script_v2.cpp
+++ b/engines/scumm/script_v2.cpp
@@ -1390,7 +1390,14 @@ void ScummEngine_v2::o2_loadRoomWithEgo() {
a = derefActor(VAR(VAR_EGO), "o2_loadRoomWithEgo");
- a->putActor(0, 0, room);
+ // The original interpreter sets the actors new room X/Y to the last rooms X/Y
+ // This fixes a problem with MM: script 161 in room 12, the 'Oomph!' script
+ // This scripts runs before the actor position is set to the correct room entry location
+ if ((_game.id == GID_MANIAC) && (_game.platform != Common::kPlatformNES)) {
+ a->putActor(a->getPos().x, a->getPos().y, room);
+ } else {
+ a->putActor(0, 0, room);
+ }
_egoPositioned = false;
x = (int8)fetchScriptByte();
diff --git a/engines/scumm/scumm-md5.h b/engines/scumm/scumm-md5.h
index 0eeff57ff7..878b2eeef3 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 Wed Jun 25 10:34:07 2014
+ This file was generated by the md5table tool on Sat Nov 01 11:52:16 2014
DO NOT EDIT MANUALLY!
*/
@@ -28,7 +28,7 @@ static const MD5Table md5table[] = {
{ "055ffe4f47753e47594ac67823220c54", "puttrace", "HE 99", "", -1, Common::DE_DEU, Common::kPlatformUnknown },
{ "057c9b456dedcc4d71b991a3072a20b3", "monkey", "SEGA", "", 9465, Common::JA_JPN, Common::kPlatformSegaCD },
{ "06b187468113f9ae5a400b148a847fac", "atlantis", "Floppy", "Floppy", 12075, Common::EN_ANY, Common::kPlatformMacintosh },
- { "06c3cf4f31daad8b1cd93153491db9e6", "pajama3", "", "", -1, Common::NL_NLD, Common::kPlatformMacintosh },
+ { "06c3cf4f31daad8b1cd93153491db9e6", "pajama3", "", "", 79382, Common::NL_NLD, Common::kPlatformUnknown },
{ "07433205acdca3bc553d0e731588b35f", "airport", "", "", -1, Common::EN_ANY, Common::kPlatformWindows },
{ "07a1eefd8ca95d77310311446c0f53d0", "brstorm", "", "", 5433, Common::EN_ANY, Common::kPlatformUnknown },
{ "07b810e37be7489263f7bc7627d4765d", "freddi4", "unenc", "Unencrypted", -1, Common::RU_RUS, Common::kPlatformWindows },
@@ -112,7 +112,7 @@ static const MD5Table md5table[] = {
{ "2108d83dcf09f8adb4bc524669c8cf51", "PuttTime", "HE 99", "Updated", -1, Common::EN_USA, Common::kPlatformUnknown },
{ "21a6592322f92550f144f68a8a4e685e", "dig", "", "", -1, Common::FR_FRA, Common::kPlatformMacintosh },
{ "21abe302e1b1e2b66d6f5c12e241ebfd", "freddicove", "unenc", "Unencrypted", -1, Common::RU_RUS, Common::kPlatformWindows },
- { "2232b0b9411575b1f9961713ebc9de61", "balloon", "HE 80", "", -1, Common::UNK_LANG, Common::kPlatformWindows },
+ { "2232b0b9411575b1f9961713ebc9de61", "balloon", "HE 80", "", -1, Common::NL_NLD, Common::kPlatformWindows },
{ "225e18566e810c634bf7de63e7568e3e", "mustard", "", "", -1, Common::EN_USA, Common::kPlatformUnknown },
{ "22c9eb04455440131ffc157aeb8d40a8", "fbear", "HE 70", "Demo", -1, Common::EN_ANY, Common::kPlatformWindows },
{ "22de86b2f7ec6e5db745ed1123310b44", "spyfox2", "", "Demo", 15832, Common::FR_FRA, Common::kPlatformWindows },
@@ -310,6 +310,7 @@ static const MD5Table md5table[] = {
{ "6bca7a1a96d16e52b8f3c42b50dbdca3", "fbear", "HE 62", "", -1, Common::JA_JPN, Common::kPlatform3DO },
{ "6bf70eee5de3d24d2403e0dd3d267e8a", "spyfox", "", "", 49221, Common::UNK_LANG, Common::kPlatformWindows },
{ "6c2bff0e327f2962e809c2e1a82d7309", "monkey", "VGA", "VGA", -1, Common::EN_ANY, Common::kPlatformAmiga },
+ { "6c375c2236d99f56e6c2cf540e74e474", "farm", "", "Demo", 34333, Common::NL_NLD, Common::kPlatformWindows },
{ "6d1baa1065ac5f7b210be8ebe4235e49", "freddi", "HE 73", "", -1, Common::NL_NLD, Common::kPlatformMacintosh },
{ "6dead580b0ff14d5f7b33b4219f04159", "samnmax", "", "Demo", 16556335, Common::EN_ANY, Common::kPlatformMacintosh },
{ "6df20c50c1ab19799de9be7ae7716881", "fbear", "HE 62", "Demo", -1, Common::EN_ANY, Common::kPlatformMacintosh },
@@ -393,9 +394,10 @@ static const MD5Table md5table[] = {
{ "8e3241ddd6c8dadf64305e8740d45e13", "balloon", "HE 100", "Updated", -1, Common::EN_ANY, Common::kPlatformUnknown },
{ "8e4ee4db46954bfe2912e259a16fad82", "monkey2", "", "", -1, Common::FR_FRA, Common::kPlatformDOS },
{ "8e9417564f33790815445b2136efa667", "atlantis", "", "CD", 11915, Common::JA_JPN, Common::kPlatformMacintosh },
- { "8e9830a6f2702be5b22c8fa0a6aaf977", "freddi2", "HE 80", "", -1, Common::NL_NLD, Common::kPlatformMacintosh },
+ { "8e9830a6f2702be5b22c8fa0a6aaf977", "freddi2", "HE 80", "", 65305, Common::NL_NLD, Common::kPlatformUnknown },
{ "8eb84cee9b429314c7f0bdcf560723eb", "monkey", "FM-TOWNS", "", 9925, Common::EN_ANY, Common::kPlatformFMTowns },
{ "8ee63cafb1fe9d62aa0d5a23117e70e7", "freddi2", "HE 100", "Updated", -1, Common::EN_USA, Common::kPlatformUnknown },
+ { "8f345db2f3f5a25ed6305001957e6f72", "freddicove", "HE 100", "", 41182, Common::NL_NLD, Common::kPlatformUnknown },
{ "8f3758ff98c9c5d78e5d635222cad026", "atlantis", "Floppy", "Floppy", -1, Common::IT_ITA, Common::kPlatformDOS },
{ "8fec68383202d38c0d25e9e3b757c5df", "comi", "Demo", "Demo", 18041, Common::UNK_LANG, Common::kPlatformWindows },
{ "8ffd618a776a4c0d8922bb28b09f8ce8", "airport", "", "Demo", -1, Common::EN_ANY, Common::kPlatformWindows },
diff --git a/engines/scumm/scumm.cpp b/engines/scumm/scumm.cpp
index 73776bad5a..475b146a7b 100644
--- a/engines/scumm/scumm.cpp
+++ b/engines/scumm/scumm.cpp
@@ -467,6 +467,8 @@ ScummEngine::ScummEngine(OSystem *syst, const DetectorResult &dr)
VAR_NUM_SCRIPT_CYCLES = 0xFF;
VAR_SCRIPT_CYCLE = 0xFF;
+ VAR_QUIT_SCRIPT = 0xFF;
+
VAR_NUM_GLOBAL_OBJS = 0xFF;
// Use g_scumm from error() ONLY
@@ -2073,6 +2075,7 @@ Common::Error ScummEngine::go() {
if (shouldQuit()) {
// TODO: Maybe perform an autosave on exit?
+ runQuitScript();
}
}
diff --git a/engines/scumm/scumm.h b/engines/scumm/scumm.h
index 36d05077c6..967909e505 100644
--- a/engines/scumm/scumm.h
+++ b/engines/scumm/scumm.h
@@ -642,7 +642,7 @@ protected:
byte _opcode;
byte _currentScript;
int _scummStackPos;
- int _vmStack[150];
+ int _vmStack[256];
OpcodeEntry _opcodes[256];
@@ -671,6 +671,7 @@ protected:
virtual void checkAndRunSentenceScript();
void runExitScript();
void runEntryScript();
+ void runQuitScript();
void runAllScripts();
void freezeScripts(int scr);
void unfreezeScripts();
@@ -1362,6 +1363,8 @@ public:
byte VAR_SCRIPT_CYCLE; // Used in runScript()/runObjectScript()
byte VAR_NUM_SCRIPT_CYCLES; // Used in runAllScripts()
+ byte VAR_QUIT_SCRIPT; // Used in confirmExitDialog()
+
// Exists both in V7 and in V72HE:
byte VAR_NUM_GLOBAL_OBJS;
diff --git a/engines/scumm/smush/smush_font.cpp b/engines/scumm/smush/smush_font.cpp
index 4c04901b42..e2f75a6862 100644
--- a/engines/scumm/smush/smush_font.cpp
+++ b/engines/scumm/smush/smush_font.cpp
@@ -115,9 +115,7 @@ int SmushFont::drawChar(byte *buffer, int dst_width, int x, int y, byte chr) {
int SmushFont::draw2byte(byte *buffer, int dst_width, int x, int y, int idx) {
int w = _vm->_2byteWidth;
int h = _vm->_2byteHeight;
-
- byte *src = _vm->get2byteCharPtr(idx);
- byte *dst = buffer + dst_width * (y + (_vm->_game.id == GID_CMI ? 7 : (_vm->_game.id == GID_DIG ? 2 : 0))) + x;
+ const byte *src = _vm->get2byteCharPtr(idx);
byte bits = 0;
char color = (_color != -1) ? _color : 1;
@@ -128,18 +126,60 @@ int SmushFont::draw2byte(byte *buffer, int dst_width, int x, int y, int idx) {
if (_vm->_game.id == GID_FT)
color = 1;
- for (int j = 0; j < h; j++) {
- for (int i = 0; i < w; i++) {
- if ((i % 8) == 0)
- bits = *src++;
- if (bits & revBitMask(i % 8)) {
- dst[i + 1] = 0;
- dst[dst_width + i] = 0;
- dst[dst_width + i + 1] = 0;
- dst[i] = color;
+ enum ShadowMode {
+ kNone,
+ kNormalShadowMode,
+ kKoreanV7ShadowMode,
+ kKoreanV8ShadowMode
+ };
+
+ ShadowMode shadowMode = kNone;
+
+ if (_vm->_language == Common::KO_KOR) {
+ if (_vm->_game.version == 8)
+ shadowMode = kKoreanV8ShadowMode;
+ else
+ shadowMode = kKoreanV7ShadowMode;
+ }
+
+ int shadowOffsetXTable[4] = {-1, 0, 1, 0};
+ int shadowOffsetYTable[4] = {0, 1, 0, 0};
+ int shadowOffsetColorTable[4] = {0, 0, 0, color};
+
+ int shadowIdx = 3;
+ if (shadowMode == kKoreanV8ShadowMode)
+ shadowIdx = 0;
+ else if (shadowMode == kKoreanV7ShadowMode)
+ shadowIdx = 2;
+
+ const byte *origSrc = src;
+
+ for (; shadowIdx < 4; shadowIdx++) {
+ int offX = x + shadowOffsetXTable[shadowIdx];
+ int offY = y + shadowOffsetYTable[shadowIdx];
+ byte drawColor = shadowOffsetColorTable[shadowIdx];
+
+ src = origSrc;
+
+ byte *dst = buffer + dst_width * (offY + (_vm->_game.id == GID_CMI ? 7 : (_vm->_game.id == GID_DIG ? 2 : 0))) + offX;
+
+ for (int j = 0; j < h; j++) {
+ for (int i = 0; i < w; i++) {
+ if (offX + i < 0)
+ continue;
+ if ((i % 8) == 0)
+ bits = *src++;
+ if (bits & revBitMask(i % 8)) {
+ if (shadowMode == kNormalShadowMode) {
+ dst[i + 1] = 0;
+ dst[dst_width + i] = 0;
+ dst[dst_width + i + 1] = 0;
+ }
+ dst[i] = drawColor;
+ }
}
+ dst += dst_width;
}
- dst += dst_width;
}
return w + 1;
}
diff --git a/engines/scumm/sound.cpp b/engines/scumm/sound.cpp
index cb428d1c15..84d2b37f96 100644
--- a/engines/scumm/sound.cpp
+++ b/engines/scumm/sound.cpp
@@ -1066,9 +1066,9 @@ void Sound::playCDTrackInternal(int track, int numLoops, int startFrame, int dur
Common::File *cddaFile = new Common::File();
if (cddaFile->open("CDDA.SOU")) {
Audio::Timestamp start = Audio::Timestamp(0, startFrame, 75);
- Audio::Timestamp end = Audio::Timestamp(0, startFrame + duration, 75);
+ Audio::Timestamp end = Audio::Timestamp(0, startFrame + duration, 75);
Audio::SeekableAudioStream *stream = makeCDDAStream(cddaFile, DisposeAfterUse::YES);
-
+
_mixer->playStream(Audio::Mixer::kMusicSoundType, &_loomSteamCDAudioHandle,
Audio::makeLoopingAudioStream(stream, start, end, (numLoops < 1) ? numLoops + 1 : numLoops));
} else {
diff --git a/engines/scumm/vars.cpp b/engines/scumm/vars.cpp
index 79d7ed03da..a6be5c3f3a 100644
--- a/engines/scumm/vars.cpp
+++ b/engines/scumm/vars.cpp
@@ -320,6 +320,7 @@ void ScummEngine_v90he::setupScummVars() {
ScummEngine_v80he::setupScummVars();
VAR_TIMER = 97;
+ VAR_QUIT_SCRIPT = 102;
VAR_SCRIPT_CYCLE = 103;
VAR_NUM_SCRIPT_CYCLES = 104;
@@ -714,7 +715,7 @@ void ScummEngine_v99he::resetScummVars() {
VAR(140) = 0;
#endif
}
-
+
if (_game.id == GID_PUTTZOO && _game.heversion == 100 && _game.platform == Common::kPlatformWindows) {
// Specific to Nimbus Games version.
VAR(156) = 1;
diff --git a/engines/sword1/POTFILES b/engines/sword1/POTFILES
index 849bef9060..b60d55ff22 100644
--- a/engines/sword1/POTFILES
+++ b/engines/sword1/POTFILES
@@ -1,4 +1,4 @@
engines/sword1/animation.cpp
engines/sword1/control.cpp
engines/sword1/logic.cpp
-engines/sword1/sword1.cpp
+
diff --git a/engines/sword1/animation.cpp b/engines/sword1/animation.cpp
index b42b833304..ac358e774b 100644
--- a/engines/sword1/animation.cpp
+++ b/engines/sword1/animation.cpp
@@ -542,7 +542,7 @@ MoviePlayer *makeMoviePlayer(uint32 id, SwordEngine *vm, Text *textMan, ResMan *
Video::VideoDecoder *dxaDecoder = new Video::DXADecoder();
return new MoviePlayer(vm, textMan, resMan, system, dxaDecoder, kVideoDecoderDXA);
#else
- GUI::MessageDialog dialog(_("DXA cutscenes found but ScummVM has been built without zlib support"), _("OK"));
+ GUI::MessageDialog dialog(_("DXA cutscenes found but ScummVM has been built without zlib"), _("OK"));
dialog.runModal();
return 0;
#endif
diff --git a/engines/sword1/console.cpp b/engines/sword1/console.cpp
index 3eb3b93a19..3a4b51965b 100644
--- a/engines/sword1/console.cpp
+++ b/engines/sword1/console.cpp
@@ -22,14 +22,37 @@
#include "sword1/console.h"
#include "sword1/sword1.h"
+#include "sword1/sound.h"
+#include "common/config-manager.h"
+#include "common/str.h"
namespace Sword1 {
SwordConsole::SwordConsole(SwordEngine *vm) : GUI::Debugger(), _vm(vm) {
assert(_vm);
+ if (scumm_stricmp(ConfMan.get("gameid").c_str(), "sword1mac") == 0 || scumm_stricmp(ConfMan.get("gameid").c_str(), "sword1macdemo") == 0)
+ registerCmd("speechEndianness", WRAP_METHOD(SwordConsole, Cmd_SpeechEndianness));
}
SwordConsole::~SwordConsole() {
}
+bool SwordConsole::Cmd_SpeechEndianness(int argc, const char **argv) {
+ if (argc == 1) {
+ debugPrintf("Using %s speech\n", _vm->_sound->_bigEndianSpeech ? "be" : "le");
+ return true;
+ }
+ if (argc == 2) {
+ if (scumm_stricmp(argv[1], "le") == 0) {
+ _vm->_sound->_bigEndianSpeech = false;
+ return false;
+ } else if (scumm_stricmp(argv[1], "be") == 0) {
+ _vm->_sound->_bigEndianSpeech = true;
+ return false;
+ }
+ }
+ debugPrintf("Usage: %s [le | be]\n", argv[0]);
+ return true;
+}
+
} // End of namespace Sword
diff --git a/engines/sword1/console.h b/engines/sword1/console.h
index a2bb51f9a4..88ee756151 100644
--- a/engines/sword1/console.h
+++ b/engines/sword1/console.h
@@ -36,6 +36,7 @@ public:
private:
SwordEngine *_vm;
+ bool Cmd_SpeechEndianness(int argc, const char **argv);
};
} // End of namespace Sword1
diff --git a/engines/sword1/sound.cpp b/engines/sword1/sound.cpp
index 0b4d3829d6..4deaf06edc 100644
--- a/engines/sword1/sound.cpp
+++ b/engines/sword1/sound.cpp
@@ -116,7 +116,7 @@ void Sound::checkSpeechFileEndianness() {
return;
// I picked the sample to use randomly (I just made sure it is long enough so that there is
- // a fair change of the heuristic to have a stable result and work for every language).
+ // a fair chance of the heuristic to have a stable result and work for every language).
int roomNo = _currentCowFile == 1 ? 1 : 129;
int localNo = _currentCowFile == 1 ? 2 : 933;
// Get the speech data and apply the heuristic
@@ -125,32 +125,45 @@ void Sound::checkSpeechFileEndianness() {
uint32 index = _cowHeader[locIndex + (localNo * 2) - 1];
if (sampleSize) {
uint32 size;
- double be_diff_sum = 0., le_diff_sum = 0.;
+ // Compute average of difference between two consecutive samples for both BE and LE
_bigEndianSpeech = false;
int16 *data = uncompressSpeech(index + _cowHeaderSize, sampleSize, &size);
- // Compute average of difference between two consecutive samples for both BE and LE
- if (data) {
- if (size > 4000)
- size = 2000;
- else
- size /= 2;
- int16 prev_be_value = (int16)SWAP_BYTES_16(*((uint16 *)(data)));
- for (uint32 i = 1; i < size; ++i) {
- le_diff_sum += fabs((double)(data[i] - data[i - 1]));
- int16 be_value = (int16)SWAP_BYTES_16(*((uint16 *)(data + i)));
- be_diff_sum += fabs((double)(be_value - prev_be_value));
- prev_be_value = be_value;
- }
- delete[] data;
- }
+ uint32 maxSamples = size > 2000 ? 2000 : size;
+ double le_diff = endiannessHeuristicValue(data, size, maxSamples);
+ delete[] data;
+ _bigEndianSpeech = true;
+ data = uncompressSpeech(index + _cowHeaderSize, sampleSize, &size);
+ double be_diff = endiannessHeuristicValue(data, size, maxSamples);
+ delete [] data;
// Set the big endian flag
- _bigEndianSpeech = (be_diff_sum < le_diff_sum);
+ _bigEndianSpeech = (be_diff < le_diff);
if (_bigEndianSpeech)
debug(6, "Mac version: using big endian speech file");
else
debug(6, "Mac version: using little endian speech file");
- debug(8, "Speech endianness heuristic: average = %f for BE and %f for LE, computed on %d samples)", be_diff_sum / (size - 1), le_diff_sum / (size - 1), size);
+ debug(8, "Speech endianness heuristic: average = %f for BE and %f for LE (%d samples)", be_diff, le_diff, maxSamples);
+ }
+}
+
+double Sound::endiannessHeuristicValue(int16* data, uint32 dataSize, uint32 &maxSamples) {
+ if (!data)
+ return 50000.; // the heuristic value for the wrong endianess is about 21000 (1/3rd of the 16 bits range)
+
+ double diff_sum = 0.;
+ uint32 cpt = 0;
+ int16 prev_value = (int16)FROM_LE_16(*((uint16 *)(data)));
+ for (uint32 i = 1; i < dataSize && cpt < maxSamples; ++i) {
+ int16 value = (int16)FROM_LE_16(*((uint16 *)(data + i)));
+ if (value != prev_value) {
+ diff_sum += fabs((double)(value - prev_value));
+ ++cpt;
+ prev_value = value;
+ }
}
+ if (cpt == 0)
+ return 50000.;
+ maxSamples = cpt;
+ return diff_sum / cpt;
}
diff --git a/engines/sword1/sound.h b/engines/sword1/sound.h
index 666598dba0..e65e797934 100644
--- a/engines/sword1/sound.h
+++ b/engines/sword1/sound.h
@@ -79,6 +79,7 @@ enum CowMode {
};
class Sound {
+ friend class SwordConsole;
public:
Sound(Audio::Mixer *mixer, ResMan *pResMan);
~Sound();
@@ -101,6 +102,7 @@ public:
void engine();
void checkSpeechFileEndianness();
+ double endiannessHeuristicValue(int16* data, uint32 dataSize, uint32 &maxSamples);
private:
uint8 _sfxVolL, _sfxVolR, _speechVolL, _speechVolR;
diff --git a/engines/sword1/sword1.cpp b/engines/sword1/sword1.cpp
index 08ea02f32d..1e9b7f70f4 100644
--- a/engines/sword1/sword1.cpp
+++ b/engines/sword1/sword1.cpp
@@ -774,6 +774,8 @@ void SwordEngine::reinitRes() {
_logic->newScreen(Logic::_scriptVars[NEW_SCREEN]);
_sound->newScreen(Logic::_scriptVars[NEW_SCREEN]);
Logic::_scriptVars[SCREEN] = Logic::_scriptVars[NEW_SCREEN];
+ _logic->engine();
+ _logic->updateScreenParams();
_screen->fullRefresh();
_screen->draw();
}
diff --git a/engines/sword1/sword1.h b/engines/sword1/sword1.h
index c58e97e353..eb24ef70fa 100644
--- a/engines/sword1/sword1.h
+++ b/engines/sword1/sword1.h
@@ -79,6 +79,7 @@ struct SystemVars {
};
class SwordEngine : public Engine {
+ friend class SwordConsole;
public:
SwordEngine(OSystem *syst);
virtual ~SwordEngine();
diff --git a/engines/sword2/animation.cpp b/engines/sword2/animation.cpp
index 92fa9d0e44..e93f27f76c 100644
--- a/engines/sword2/animation.cpp
+++ b/engines/sword2/animation.cpp
@@ -442,7 +442,7 @@ MoviePlayer *makeMoviePlayer(const char *name, Sword2Engine *vm, OSystem *system
Video::DXADecoder *dxaDecoder = new Video::DXADecoder();
return new MoviePlayer(vm, system, dxaDecoder, kVideoDecoderDXA);
#else
- GUI::MessageDialog dialog(_("DXA cutscenes found but ScummVM has been built without zlib support"), _("OK"));
+ GUI::MessageDialog dialog(_("DXA cutscenes found but ScummVM has been built without zlib"), _("OK"));
dialog.runModal();
return NULL;
#endif
diff --git a/engines/sword25/gfx/renderobjectmanager.cpp b/engines/sword25/gfx/renderobjectmanager.cpp
index 4927b4c58e..8aeecad6b1 100644
--- a/engines/sword25/gfx/renderobjectmanager.cpp
+++ b/engines/sword25/gfx/renderobjectmanager.cpp
@@ -107,7 +107,7 @@ bool RenderObjectManager::render() {
if (!_currQueue->exists(*it))
_uta->addRect((*it)._bbox);
}
-
+
// Add rectangles of objects which are different from the previous frame
for (RenderObjectQueue::iterator it = _currQueue->begin(); it != _currQueue->end(); ++it) {
if (!_prevQueue->exists(*it))
diff --git a/engines/sword25/kernel/persistenceservice.cpp b/engines/sword25/kernel/persistenceservice.cpp
index fb83b7f941..7d68081593 100644
--- a/engines/sword25/kernel/persistenceservice.cpp
+++ b/engines/sword25/kernel/persistenceservice.cpp
@@ -52,7 +52,7 @@ static const uint SLOT_COUNT = 18;
static const uint FILE_COPY_BUFFER_SIZE = 1024 * 10;
static const char *VERSIONIDOLD = "SCUMMVM1";
static const char *VERSIONID = "SCUMMVM2";
-static const int VERSIONNUM = 2;
+static const int VERSIONNUM = 3;
#define MAX_SAVEGAME_SIZE 100
diff --git a/engines/sword25/util/pluto/pluto.cpp b/engines/sword25/util/pluto/pluto.cpp
index fb477c1687..cbe16b0d5b 100644
--- a/engines/sword25/util/pluto/pluto.cpp
+++ b/engines/sword25/util/pluto/pluto.cpp
@@ -325,7 +325,7 @@ static void persisttable(PersistInfo *pi)
#ifdef TOTEXT
printf("persisttable\n");
#endif
-
+
/* perms reftbl ... tbl */
lua_checkstack(pi->L, 3);
if(persistspecialobject(pi, 1)) {
@@ -835,7 +835,15 @@ static void persistthread(PersistInfo *pi)
#endif
write_size(pi, &stackbase);
write_size(pi, &stacktop);
+
+ // ptrdiff_t changes sizes based on 32/64 bit
+ // Hard cast to 64 bit size if SIZE64 is defined
+#ifdef SIZES64
+ uint64 ptrIndex = static_cast<uint64>(L2->errfunc);
+ pi_write(pi, &ptrIndex, sizeof(uint64), pi->ud);
+#else
pi_write(pi, &L2->errfunc, sizeof(ptrdiff_t), pi->ud);
+#endif
//write_size(pi, (size_t *)&L2->errfunc);
}
@@ -944,12 +952,6 @@ static void persist(PersistInfo *pi)
if(!lua_isnil(pi->L, -1)) {
/* perms reftbl ... obj ref */
int zero = 0;
- // FIXME: Casting a pointer to an integer data type is a bad idea we
- // should really get rid of this by fixing the design of this code.
- // For now casting to size_t should silence most (all?) compilers,
- // since size_t is supposedly the same size as a pointer on most
- // (modern) architectures.
- int ref = (int)(size_t)lua_touserdata(pi->L, -1);
pi_write(pi, &zero, sizeof(int), pi->ud);
if (humanReadable) {
snprintf(hrBuf, hrBufSize, "persist_seenobject\n");
@@ -958,7 +960,8 @@ static void persist(PersistInfo *pi)
#ifdef TOTEXT
printf("persist_seenobject\n");
#endif
- pi_write(pi, &ref, sizeof(int), pi->ud);
+ int *ref = (int *)lua_touserdata(pi->L, -1);
+ pi_write(pi, ref, sizeof(int), pi->ud);
if (humanReadable) {
snprintf(hrBuf, hrBufSize, "persist_touserdata_ref %d\n", ref);
hrOut(pi);
@@ -1011,7 +1014,8 @@ static void persist(PersistInfo *pi)
}
lua_pushvalue(pi->L, -1);
/* perms reftbl ... obj obj */
- lua_pushlightuserdata(pi->L, (void *)(++(pi->counter)));
+ int *ref = (int *)lua_newuserdata(pi->L, sizeof(int));
+ *ref = ++(pi->counter);
/* perms reftbl ... obj obj ref */
lua_rawset(pi->L, 2);
/* perms reftbl ... obj */
@@ -1188,7 +1192,7 @@ int persist_l(lua_State *L)
wi.buf = NULL;
wi.buflen = 0;
-
+
lua_settop(L, 2);
/* perms? rootobj? */
luaL_checktype(L, 1, LUA_TTABLE);
@@ -1737,7 +1741,16 @@ static void unpersistthread(int ref, UnpersistInfo *upi)
verify(LIF(Z,read)(&upi->zio, &L2->status, sizeof(lu_byte)) == 0);
read_size(&upi->zio, &stackbase);
read_size(&upi->zio, &stacktop);
+
+#ifdef SIZES64
+ uint64 value;
+ verify(LIF(Z,read)(&upi->zio, &value, sizeof(uint64)) == 0);
+
+ L2->errfunc = static_cast<ptrdiff_t>(value);
+#else
verify(LIF(Z,read)(&upi->zio, &L2->errfunc, sizeof(ptrdiff_t)) == 0);
+#endif
+
//read_size(&upi->zio, (size_t *)&L2->errfunc);
L2->base = L2->stack + stackbase;
L2->top = L2->stack + stacktop;
@@ -2032,7 +2045,7 @@ int unpersist_l(lua_State *L)
int version_l(lua_State *L)
{
const char *version = VERSION;
-
+
lua_settop(L, 0);
/* (empty) */
lua_pushlstring(L, version, strlen(version));
diff --git a/engines/tinsel/tinsel.cpp b/engines/tinsel/tinsel.cpp
index 31610a8467..57d8432f0e 100644
--- a/engines/tinsel/tinsel.cpp
+++ b/engines/tinsel/tinsel.cpp
@@ -821,7 +821,8 @@ const char *const TinselEngine::_textFiles[][3] = {
TinselEngine::TinselEngine(OSystem *syst, const TinselGameDescription *gameDesc) :
- Engine(syst), _gameDescription(gameDesc), _random("tinsel") {
+ Engine(syst), _gameDescription(gameDesc), _random("tinsel"),
+ _sound(0), _midiMusic(0), _pcmMusic(0), _bmv(0) {
_vm = this;
_config = new Config(this);
@@ -846,13 +847,6 @@ TinselEngine::TinselEngine(OSystem *syst, const TinselGameDescription *gameDesc)
if (cd_num >= 0)
_system->getAudioCDManager()->openCD(cd_num);
- _midiMusic = new MidiMusicPlayer();
- _pcmMusic = new PCMMusicPlayer();
-
- _sound = new SoundManager(this);
-
- _bmv = new BMVPlayer();
-
_mousePos.x = 0;
_mousePos.y = 0;
_keyHandler = NULL;
@@ -896,6 +890,11 @@ void TinselEngine::initializePath(const Common::FSNode &gamePath) {
}
Common::Error TinselEngine::run() {
+ _midiMusic = new MidiMusicPlayer();
+ _pcmMusic = new PCMMusicPlayer();
+ _sound = new SoundManager(this);
+ _bmv = new BMVPlayer();
+
// Initialize backend
if (getGameID() == GID_DW2) {
#ifndef DW2_EXACT_SIZE
diff --git a/engines/tony/game.cpp b/engines/tony/game.cpp
index c102242dfd..0a2c62330b 100644
--- a/engines/tony/game.cpp
+++ b/engines/tony/game.cpp
@@ -1557,14 +1557,14 @@ void RMPointer::updateCursor() {
for (int i = 0; i < 64; i++) {
uint16 *lineP = src;
for (int j = 0; j < 64; j++) {
- lineP[j] = RMGfxTargetBuffer::_precalcTable[lineP[j] & 0x7FFF];
+ lineP[j] = RMGfxTargetBuffer::_precalcTable[lineP[j]];
}
src += 64;
}
}
// Get the raw pixel data and set the cursor to it
- Graphics::PixelFormat pixelFormat(2, 5, 5, 5, 0, 10, 5, 0, 0);
+ Graphics::PixelFormat pixelFormat(2, 5, 6, 5, 0, 11, 5, 0, 0);
CursorMan.replaceCursor(cursorData, 64, 64, _cursorHotspot._x, _cursorHotspot._y, 0, 1, &pixelFormat);
}
diff --git a/engines/tony/gfxcore.cpp b/engines/tony/gfxcore.cpp
index 9254d59df6..2a32926c53 100644
--- a/engines/tony/gfxcore.cpp
+++ b/engines/tony/gfxcore.cpp
@@ -422,11 +422,11 @@ uint16 *RMGfxTargetBuffer::_precalcTable = NULL;
* called if the user selects the black & white option.
*/
void RMGfxTargetBuffer::createBWPrecalcTable() {
- _precalcTable = new uint16[0x8000];
+ _precalcTable = new uint16[0x10000];
- for (int i = 0; i < 0x8000; i++) {
- int r = (i >> 10) & 0x1F;
- int g = (i >> 5) & 0x1F;
+ for (int i = 0; i < 0x10000; i++) {
+ int r = (i >> 11) & 0x1F;
+ int g = (i >> 6) & 0x1F;
int b = i & 0x1F;
int min = MIN(r, MIN(g, b));
@@ -434,11 +434,11 @@ void RMGfxTargetBuffer::createBWPrecalcTable() {
min = (min + max) / 2;
- r = CLIP(min + 8 - 8, 0, 31);
- g = CLIP(min + 5 - 8, 0, 31);
- b = CLIP(min + 0 - 8, 0, 31);
+ r = CLIP(min + 8 - 8, 0, 0x1f);
+ g = CLIP(min + 5 - 8, 0, 0x1f);
+ b = CLIP(min + 0 - 8, 0, 0x1f);
- _precalcTable[i] = (r << 10) | (g << 5) | b;
+ _precalcTable[i] = (r << 11) | (g << 6) | b;
}
}
@@ -512,8 +512,9 @@ int RMGfxSourceBufferPal::loadPalette(const byte *buf) {
void RMGfxSourceBufferPal::preparePalette() {
for (int i = 0; i < 256; i++) {
- _palFinal[i] = (((int)_pal[i * 3 + 0] >> 3) << 10) |
- (((int)_pal[i * 3 + 1] >> 3) << 5) |
+ // we convert 555 to 565 here.
+ _palFinal[i] = (((int)_pal[i * 3 + 0] >> 3) << 11) |
+ (((int)_pal[i * 3 + 1] >> 3) << 6) |
(((int)_pal[i * 3 + 2] >> 3) << 0);
}
}
@@ -665,8 +666,8 @@ void RMGfxSourceBuffer8::create(int dimx, int dimy) {
RMGfxBuffer::create(dimx, dimy, 8);
}
-#define GETRED(x) (((x) >> 10) & 0x1F)
-#define GETGREEN(x) (((x) >> 5) & 0x1F)
+#define GETRED(x) (((x) >> 11) & 0x1F)
+#define GETGREEN(x) (((x) >> 5) & 0x3F)
#define GETBLUE(x) ((x) & 0x1F)
/****************************************************************************\
@@ -684,13 +685,13 @@ int RMGfxSourceBuffer8AB::calcTrasp(int fore, int back) {
if (r > 0x1F)
r = 0x1F;
- if (g > 0x1F)
- g = 0x1F;
+ if (g > 0x3F)
+ g = 0x3F;
if (b > 0x1F)
b = 0x1F;
- return (r << 10) | (g << 5) | b;
+ return (r << 11) | (g << 5) | b;
}
void RMGfxSourceBuffer8AB::draw(CORO_PARAM, RMGfxTargetBuffer &bigBuf, RMGfxPrimitive *prim) {
@@ -802,8 +803,8 @@ void RMGfxSourceBuffer8RLE::preparePalette() {
// Handle RGB alpha blending
if (_alphaBlendColor != -1) {
- _alphaR = (_palFinal[_alphaBlendColor] >> 10) & 0x1F;
- _alphaG = (_palFinal[_alphaBlendColor] >> 5) & 0x1F;
+ _alphaR = (_palFinal[_alphaBlendColor] >> 11) & 0x1F;
+ _alphaG = (_palFinal[_alphaBlendColor] >> 5) & 0x3F;
_alphaB = (_palFinal[_alphaBlendColor]) & 0x1F;
}
}
@@ -1054,15 +1055,15 @@ RLEByteDoAlpha2:
if (n > nLength)
n = nLength;
for (int i = 0; i < n; i++) {
- int r = (*dst >> 10) & 0x1F;
- int g = (*dst >> 5) & 0x1F;
+ int r = (*dst >> 11) & 0x1F;
+ int g = (*dst >> 5) & 0x3F;
int b = *dst & 0x1F;
r = (r >> 2) + (_alphaR >> 1);
g = (g >> 2) + (_alphaG >> 1);
b = (b >> 2) + (_alphaB >> 1);
- *dst ++ = (r << 10) | (g << 5) | b;
+ *dst ++ = (r << 11) | (g << 5) | b;
}
nLength -= n;
@@ -1158,15 +1159,15 @@ RLEByteFlippedDoAlpha2:
if (n > nLength)
n = nLength;
for (int i = 0; i < n; i++) {
- int r = (*dst >> 10) & 0x1F;
- int g = (*dst >> 5) & 0x1F;
+ int r = (*dst >> 11) & 0x1F;
+ int g = (*dst >> 5) & 0x3F;
int b = *dst & 0x1F;
r = (r >> 2) + (_alphaR >> 1);
g = (g >> 2) + (_alphaG >> 1);
b = (b >> 2) + (_alphaB >> 1);
- *dst-- = (r << 10) | (g << 5) | b;
+ *dst-- = (r << 11) | (g << 5) | b;
}
nLength -= n;
@@ -1302,15 +1303,15 @@ RLEWordDoAlpha2:
n = nLength;
for (int i = 0; i < n; i++) {
- int r = (*dst >> 10) & 0x1F;
- int g = (*dst >> 5) & 0x1F;
+ int r = (*dst >> 11) & 0x1F;
+ int g = (*dst >> 5) & 0x3F;
int b = *dst & 0x1F;
r = (r >> 2) + (_alphaR >> 1);
g = (g >> 2) + (_alphaG >> 1);
b = (b >> 2) + (_alphaB >> 1);
- *dst++ = (r << 10) | (g << 5) | b;
+ *dst++ = (r << 11) | (g << 5) | b;
}
nLength -= n;
@@ -1416,15 +1417,15 @@ RLEWordFlippedDoAlpha2:
n = nLength;
for (int i = 0; i < n; i++) {
- int r = (*dst >> 10) & 0x1F;
- int g = (*dst >> 5) & 0x1F;
+ int r = (*dst >> 11) & 0x1F;
+ int g = (*dst >> 5) & 0x3F;
int b = *dst & 0x1F;
r = (r >> 2) + (_alphaR >> 1);
g = (g >> 2) + (_alphaG >> 1);
b = (b >> 2) + (_alphaB >> 1);
- *dst-- = (r << 10) | (g << 5) | b;
+ *dst-- = (r << 11) | (g << 5) | b;
}
nLength -= n;
@@ -1543,15 +1544,15 @@ RLEWordDoAlpha2:
// @@@ SHOULD NOT BE THERE !!!!!
for (int i = 0; i < n; i++) {
- int r = (*dst >> 10) & 0x1F;
- int g = (*dst >> 5) & 0x1F;
+ int r = (*dst >> 11) & 0x1F;
+ int g = (*dst >> 5) & 0x3F;
int b = *dst & 0x1F;
r = (r >> 2) + (_alphaR >> 1);
g = (g >> 2) + (_alphaG >> 1);
b = (b >> 2) + (_alphaB >> 1);
- *dst++ = (r << 10) | (g << 5) | b;
+ *dst++ = (r << 11) | (g << 5) | b;
}
nLength -= n;
@@ -1570,19 +1571,19 @@ RLEWordDoCopy2:
n = nLength;
for (int i = 0; i < n; i++) {
- int r = (*dst >> 10) & 0x1F;
- int g = (*dst >> 5) & 0x1F;
+ int r = (*dst >> 11) & 0x1F;
+ int g = (*dst >> 5) & 0x3F;
int b = *dst & 0x1F;
- int r2 = (_palFinal[*src] >> 10) & 0x1F;
- int g2 = (_palFinal[*src] >> 5) & 0x1F;
+ int r2 = (_palFinal[*src] >> 11) & 0x1F;
+ int g2 = (_palFinal[*src] >> 5) & 0x3F;
int b2 = _palFinal[*src] & 0x1F;
r = (r >> 1) + (r2 >> 1);
g = (g >> 1) + (g2 >> 1);
b = (b >> 1) + (b2 >> 1);
- *dst ++ = (r << 10) | (g << 5) | b;
+ *dst ++ = (r << 11) | (g << 5) | b;
src++;
}
@@ -1732,14 +1733,14 @@ void RMGfxSourceBuffer8AA::drawAA(RMGfxTargetBuffer &bigBuf, RMGfxPrimitive *pri
g /= 5;
b /= 5;
- if (r > 31)
- r = 31;
- if (g > 31)
- g = 31;
- if (b > 31)
- b = 31;
+ if (r > 0x1f)
+ r = 0x1f;
+ if (g > 0x3f)
+ g = 0x3f;
+ if (b > 0x1f)
+ b = 0x1f;
- mybuf[0] = (r << 10) | (g << 5) | b;
+ mybuf[0] = (r << 11) | (g << 5) | b;
}
}
@@ -1773,14 +1774,14 @@ void RMGfxSourceBuffer8AA::drawAA(RMGfxTargetBuffer &bigBuf, RMGfxPrimitive *pri
g /= 6;
b /= 6;
- if (r > 31)
- r = 31;
- if (g > 31)
- g = 31;
- if (b > 31)
- b = 31;
+ if (r > 0x1f)
+ r = 0x1f;
+ if (g > 0x3f)
+ g = 0x3f;
+ if (b > 0x1f)
+ b = 0x1f;
- mybuf[0] = (r << 10) | (g << 5) | b;
+ mybuf[0] = (r << 11) | (g << 5) | b;
}
}
@@ -1948,8 +1949,17 @@ void RMGfxSourceBuffer16::prepareImage() {
// Color space conversion if necessary!
uint16 *buf = (uint16 *)_buf;
- for (int i = 0; i < _dimx * _dimy; i++)
- buf[i] = FROM_LE_16(buf[i]) & 0x7FFF;
+ // convert 555 to 565
+ for (int i = 0; i < _dimx * _dimy; i++) {
+ uint16 pixel = FROM_LE_16(buf[i]);
+ int r = (pixel >> 10) & 0x1F;
+ int g = (pixel >> 5) & 0x1F;
+ int b = pixel & 0x1F;
+
+ pixel = (r << 11) | (g << 6) | b;
+
+ buf[i] = pixel;
+ }
}
RMGfxSourceBuffer16::RMGfxSourceBuffer16(int dimx, int dimy)
@@ -1983,7 +1993,8 @@ void RMGfxBox::setColor(byte r, byte g, byte b) {
r >>= 3;
g >>= 3;
b >>= 3;
- _wFillColor = (r << 10) | (g << 5) | b;
+ // These are hard-coded colors, so we convert 555 to 565.
+ _wFillColor = (r << 11) | (g << 6) | b;
}
void RMGfxBox::draw(CORO_PARAM, RMGfxTargetBuffer &bigBuf, RMGfxPrimitive *prim) {
diff --git a/engines/tony/mpal/lzo.cpp b/engines/tony/mpal/lzo.cpp
index 314d6f3ed5..6cc2333315 100644
--- a/engines/tony/mpal/lzo.cpp
+++ b/engines/tony/mpal/lzo.cpp
@@ -116,7 +116,7 @@ int lzo1x_decompress(const byte *in, uint32 in_len, byte *out, uint32 *out_len)
*op++ = *ip++;
*op++ = *ip++;
*op++ = *ip++;
- do
+ do
*op++ = *ip++;
while (--t > 0);
diff --git a/engines/tony/window.cpp b/engines/tony/window.cpp
index 5c50a50a57..3b3687419b 100644
--- a/engines/tony/window.cpp
+++ b/engines/tony/window.cpp
@@ -53,9 +53,9 @@ RMWindow::~RMWindow() {
* Initializes the graphics window
*/
void RMWindow::init() {
- Graphics::PixelFormat pixelFormat(2, 5, 5, 5, 0, 10, 5, 0, 0);
+ Graphics::PixelFormat pixelFormat(2, 5, 6, 5, 0, 11, 5, 0, 0);
initGraphics(RM_SX, RM_SY, true, &pixelFormat);
-
+
reset();
}
@@ -83,7 +83,7 @@ void RMWindow::copyRectToScreen(const byte *buf, int pitch, int x, int y, int w,
for (int i = 0; i < h; i++) {
uint16 *dst = (uint16 *)screen->getBasePtr(x, y + i);
for (int j = 0; j < w; j++) {
- dst[j] = RMGfxTargetBuffer::_precalcTable[src[j] & 0x7FFF];
+ dst[j] = RMGfxTargetBuffer::_precalcTable[src[j]];
}
src += (pitch / 2);
}
@@ -291,8 +291,8 @@ void RMSnapshot::grabScreenshot(byte *lpBuf, int dezoom, uint16 *lpDestBuf) {
cursrc = &src[RM_SKIPX + x];
*curOut++ = ((*cursrc) & 0x1F) << 3;
- *curOut++ = (((*cursrc) >> 5) & 0x1F) << 3;
- *curOut++ = (((*cursrc) >> 10) & 0x1F) << 3;
+ *curOut++ = (((*cursrc) >> 5) & 0x3F) << 3;
+ *curOut++ = (((*cursrc) >> 11) & 0x1F) << 3;
if (lpDestBuf)
*lpDestBuf++ = *cursrc;
@@ -319,8 +319,8 @@ void RMSnapshot::grabScreenshot(byte *lpBuf, int dezoom, uint16 *lpDestBuf) {
curv = v;
sommab += cursrc[curv * RM_BBX + u] & 0x1F;
- sommag += (cursrc[curv * RM_BBX + u] >> 5) & 0x1F;
- sommar += (cursrc[curv * RM_BBX + u] >> 10) & 0x1F;
+ sommag += (cursrc[curv * RM_BBX + u] >> 6) & 0x1F;
+ sommar += (cursrc[curv * RM_BBX + u] >> 11) & 0x1F;
}
}
_rgb[k + 0] = (byte)(sommab * 8 / (dezoom * dezoom));
diff --git a/engines/toon/character.cpp b/engines/toon/character.cpp
index 51e8dee19f..686fe99beb 100644
--- a/engines/toon/character.cpp
+++ b/engines/toon/character.cpp
@@ -1059,7 +1059,7 @@ void Character::playAnim(int32 animId, int32 unused, int32 flags) {
_specialAnim->loadAnimation(animName);
_animSpecialId = animId;
-
+
if (_animationInstance) {
_animationInstance->setAnimation(_specialAnim);
_animationInstance->setAnimationRange(0, _specialAnim->_numFrames - 1);
diff --git a/engines/toon/state.cpp b/engines/toon/state.cpp
index 6ac5808219..000f94d659 100644
--- a/engines/toon/state.cpp
+++ b/engines/toon/state.cpp
@@ -115,7 +115,7 @@ State::State(void) {
#endif
memset(_conversationState, 0, sizeof(Conversation) * 60);
-
+
_conversationData = nullptr;
_currentConversationId = -1;
_exitConversation = true;
diff --git a/engines/toon/toon.cpp b/engines/toon/toon.cpp
index 14e7d104d2..2f5051c157 100644
--- a/engines/toon/toon.cpp
+++ b/engines/toon/toon.cpp
@@ -2037,23 +2037,19 @@ int32 ToonEngine::characterTalk(int32 dialogid, bool blocking) {
}
}
- int32 myId = 0;
char *myLine;
- if (dialogid < 1000) {
+ if (dialogid < 1000)
myLine = _roomTexts->getText(dialogid);
- myId = dialogid;
- } else {
+ else
myLine = _genericTexts->getText(dialogid - 1000);
- myId = dialogid - 1000;
- }
if (!myLine)
return 0;
bool oldMouseHidden = _gameState->_mouseHidden;
- if (blocking) {
+ if (blocking)
_gameState->_mouseHidden = true;
- }
+
// get what is before the string
int a = READ_LE_UINT16(myLine - 2);
@@ -2090,10 +2086,8 @@ int32 ToonEngine::characterTalk(int32 dialogid, bool blocking) {
while ((waitChar->getAnimFlag() & 0x10) == 0x10 && !_shouldQuit)
doFrame();
}
- } else {
- if (_audioManager->voiceStillPlaying())
- _audioManager->stopCurrentVoice();
- }
+ } else if (_audioManager->voiceStillPlaying())
+ _audioManager->stopCurrentVoice();
for (int32 i = 0; i < numParticipants - 1; i++) {
// listener
@@ -2133,10 +2127,10 @@ int32 ToonEngine::characterTalk(int32 dialogid, bool blocking) {
getTextPosition(talkerId, &_currentTextLineX, &_currentTextLineY);
if (dialogid < 1000) {
- myId = _roomTexts->getId(dialogid);
+ int myId = _roomTexts->getId(dialogid);
_audioManager->playVoice(myId, false);
} else {
- myId = _genericTexts->getId(dialogid - 1000);
+ int myId = _genericTexts->getId(dialogid - 1000);
_audioManager->playVoice(myId, true);
}
diff --git a/engines/touche/detection.cpp b/engines/touche/detection.cpp
index 97a14e5bc1..1d0e136d69 100644
--- a/engines/touche/detection.cpp
+++ b/engines/touche/detection.cpp
@@ -24,7 +24,6 @@
#include "engines/advancedDetector.h"
#include "common/savefile.h"
#include "common/system.h"
-#include "common/translation.h"
#include "base/plugins.h"
diff --git a/engines/tsage/POTFILES b/engines/tsage/POTFILES
new file mode 100644
index 0000000000..de18cbd072
--- /dev/null
+++ b/engines/tsage/POTFILES
@@ -0,0 +1,3 @@
+engines/tsage/dialogs.cpp
+engines/tsage/scenes.cpp
+
diff --git a/engines/tsage/blue_force/blueforce_dialogs.cpp b/engines/tsage/blue_force/blueforce_dialogs.cpp
index 2f337ac549..5be27c9ae7 100644
--- a/engines/tsage/blue_force/blueforce_dialogs.cpp
+++ b/engines/tsage/blue_force/blueforce_dialogs.cpp
@@ -20,8 +20,6 @@
*
*/
-#include "common/translation.h"
-
#include "gui/dialog.h"
#include "gui/widget.h"
diff --git a/engines/tsage/debugger.cpp b/engines/tsage/debugger.cpp
index b647807f8a..a38796717a 100644
--- a/engines/tsage/debugger.cpp
+++ b/engines/tsage/debugger.cpp
@@ -42,7 +42,7 @@ Debugger::Debugger() : GUI::Debugger() {
registerCmd("moveobject", WRAP_METHOD(Debugger, Cmd_MoveObject));
registerCmd("hotspots", WRAP_METHOD(Debugger, Cmd_Hotspots));
registerCmd("sound", WRAP_METHOD(Debugger, Cmd_Sound));
- registerCmd("setdebug", WRAP_METHOD(Debugger, Cmd_SetDebug));
+ registerCmd("setdebug", WRAP_METHOD(Debugger, Cmd_SetOutpostAlphaDebug));
}
static int strToInt(const char *s) {
@@ -344,7 +344,7 @@ bool Debugger::Cmd_Sound(int argc, const char **argv) {
/**
* Activate internal debugger, when available
*/
-bool Debugger::Cmd_SetDebug(int argc, const char **argv) {
+bool Debugger::Cmd_SetOutpostAlphaDebug(int argc, const char **argv) {
debugPrintf("Not available in this game\n");
return true;
}
@@ -720,7 +720,7 @@ bool Ringworld2Debugger::Cmd_MoveObject(int argc, const char **argv) {
/**
* Activate internal debugger, when available
*/
-bool Ringworld2Debugger::Cmd_SetDebug(int argc, const char **argv) {
+bool Ringworld2Debugger::Cmd_SetOutpostAlphaDebug(int argc, const char **argv) {
if (argc != 1) {
debugPrintf("Usage: %s\n", argv[0]);
return true;
diff --git a/engines/tsage/debugger.h b/engines/tsage/debugger.h
index 610f45de64..b0f4c665dd 100644
--- a/engines/tsage/debugger.h
+++ b/engines/tsage/debugger.h
@@ -45,7 +45,7 @@ protected:
bool Cmd_Sound(int argc, const char **argv);
virtual bool Cmd_ListObjects(int argc, const char **argv) = 0;
virtual bool Cmd_MoveObject(int argc, const char **argv) = 0;
- virtual bool Cmd_SetDebug(int argc, const char **argv);
+ virtual bool Cmd_SetOutpostAlphaDebug(int argc, const char **argv);
};
class DemoDebugger : public Debugger {
@@ -70,7 +70,7 @@ class Ringworld2Debugger : public Debugger {
protected:
virtual bool Cmd_ListObjects(int argc, const char **argv);
virtual bool Cmd_MoveObject(int argc, const char **argv);
- virtual bool Cmd_SetDebug(int argc, const char **argv);
+ virtual bool Cmd_SetOutpostAlphaDebug(int argc, const char **argv);
};
} // End of namespace TsAGE
diff --git a/engines/tsage/module.mk b/engines/tsage/module.mk
index 53c03e2e57..d62f398c20 100644
--- a/engines/tsage/module.mk
+++ b/engines/tsage/module.mk
@@ -35,13 +35,16 @@ MODULE_OBJS := \
ringworld/ringworld_scenes8.o \
ringworld/ringworld_scenes10.o \
ringworld/ringworld_speakers.o \
+ ringworld2/ringworld2_airduct.o \
ringworld2/ringworld2_dialogs.o \
ringworld2/ringworld2_logic.o \
+ ringworld2/ringworld2_outpost.o \
ringworld2/ringworld2_scenes0.o \
ringworld2/ringworld2_scenes1.o \
ringworld2/ringworld2_scenes2.o \
ringworld2/ringworld2_scenes3.o \
ringworld2/ringworld2_speakers.o \
+ ringworld2/ringworld2_vampire.o \
saveload.o \
scenes.o \
sound.o \
diff --git a/engines/tsage/ringworld/ringworld_dialogs.cpp b/engines/tsage/ringworld/ringworld_dialogs.cpp
index 226a943f08..1dd3bc158b 100644
--- a/engines/tsage/ringworld/ringworld_dialogs.cpp
+++ b/engines/tsage/ringworld/ringworld_dialogs.cpp
@@ -20,8 +20,6 @@
*
*/
-#include "common/translation.h"
-
#include "gui/dialog.h"
#include "gui/widget.h"
diff --git a/engines/tsage/ringworld2/ringworld2_airduct.cpp b/engines/tsage/ringworld2/ringworld2_airduct.cpp
new file mode 100644
index 0000000000..136e8d5d1b
--- /dev/null
+++ b/engines/tsage/ringworld2/ringworld2_airduct.cpp
@@ -0,0 +1,909 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public 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 "tsage/ringworld2/ringworld2_airduct.h"
+
+namespace TsAGE {
+
+namespace Ringworld2 {
+
+/*--------------------------------------------------------------------------
+ * Scene 1200 - Air Ducts Maze
+ *
+ *--------------------------------------------------------------------------*/
+
+Scene1200::Scene1200() {
+ _nextCrawlDirection = 0;
+ _field414 = 0;
+ _field416 = 0;
+ _field418 = 0;
+ _field41A = 0;
+ _fixupMaze = false;
+}
+
+void Scene1200::synchronize(Serializer &s) {
+ SceneExt::synchronize(s);
+
+ s.syncAsSint16LE(_nextCrawlDirection);
+ s.syncAsSint16LE(_field414);
+ s.syncAsSint16LE(_field416);
+ s.syncAsSint16LE(_field418);
+ s.syncAsSint16LE(_field41A);
+ s.syncAsSint16LE(_fixupMaze);
+}
+
+Scene1200::LaserPanel::LaserPanel() {
+}
+
+void Scene1200::LaserPanel::Jumper::init(int state) {
+ _state = state;
+
+ SceneActor::postInit();
+ setup(1003, 1, 1);
+ fixPriority(255);
+
+ switch (_state) {
+ case 1:
+ switch (R2_GLOBALS._ductMazePanel1State) {
+ case 1:
+ setFrame2(2);
+ setPosition(Common::Point(129, 101));
+ break;
+ case 2:
+ setFrame2(3);
+ setPosition(Common::Point(135, 95));
+ break;
+ default:
+ break;
+ }
+ break;
+ case 2:
+ switch (R2_GLOBALS._ductMazePanel2State) {
+ case 1:
+ setFrame2(2);
+ setPosition(Common::Point(152, 101));
+ break;
+ case 2:
+ setFrame2(3);
+ setPosition(Common::Point(158, 122));
+ break;
+ case 3:
+ setFrame2(3);
+ setPosition(Common::Point(135, 122));
+ break;
+ default:
+ break;
+ }
+ break;
+ case 3:
+ switch (R2_GLOBALS._ductMazePanel3State) {
+ case 1:
+ setFrame2(3);
+ setPosition(Common::Point(158, 95));
+ break;
+ case 2:
+ setFrame2(2);
+ setPosition(Common::Point(175, 101));
+ break;
+ default:
+ break;
+ }
+ break;
+ default:
+ break;
+ }
+
+ setDetails(1200, 12, -1, -1, 2, (SceneItem *) NULL);
+}
+
+bool Scene1200::LaserPanel::Jumper::startAction(CursorType action, Event &event) {
+ if (action != CURSOR_USE)
+ return SceneActor::startAction(action, event);
+
+ R2_GLOBALS._sound2.play(260);
+ switch (_state) {
+ case 1:
+ if (R2_GLOBALS._ductMazePanel1State == 1) {
+ R2_GLOBALS._ductMazePanel1State = 2;
+ setFrame2(3);
+ setPosition(Common::Point(135, 95));
+ } else {
+ R2_GLOBALS._ductMazePanel1State = 1;
+ setFrame2(2);
+ setPosition(Common::Point(129, 101));
+ }
+ break;
+ case 2:
+ ++R2_GLOBALS._ductMazePanel2State;
+ if (R2_GLOBALS._ductMazePanel2State == 4)
+ R2_GLOBALS._ductMazePanel2State = 1;
+
+ switch (R2_GLOBALS._ductMazePanel2State) {
+ case 1:
+ setFrame2(2);
+ setPosition(Common::Point(152, 101));
+ break;
+ case 2:
+ setFrame2(3);
+ setPosition(Common::Point(158, 122));
+ break;
+ case 3:
+ setFrame2(3);
+ setPosition(Common::Point(135, 122));
+ break;
+ default:
+ break;
+ }
+ break;
+ case 3:
+ if (R2_GLOBALS._ductMazePanel3State == 1) {
+ R2_GLOBALS._ductMazePanel3State = 2;
+ setFrame2(2);
+ setPosition(Common::Point(175, 101));
+ } else {
+ R2_GLOBALS._ductMazePanel3State = 1;
+ setFrame2(3);
+ setPosition(Common::Point(158, 95));
+ }
+ break;
+ default:
+ break;
+ }
+
+ Scene1200 *scene = (Scene1200 *)R2_GLOBALS._sceneManager._scene;
+ scene->_field418 = 0;
+
+ if ((R2_GLOBALS._ductMazePanel1State == 1) && (R2_GLOBALS._ductMazePanel2State == 1) && (R2_GLOBALS._ductMazePanel3State == 1))
+ scene->_field418 = 1;
+ else if ((R2_GLOBALS._ductMazePanel1State == 2) && (R2_GLOBALS._ductMazePanel2State == 1) && (R2_GLOBALS._ductMazePanel3State == 1))
+ scene->_field418 = 2;
+ else if ((R2_GLOBALS._ductMazePanel1State == 2) && (R2_GLOBALS._ductMazePanel2State == 1) && (R2_GLOBALS._ductMazePanel3State == 2))
+ scene->_field418 = 3;
+ else if ((R2_GLOBALS._ductMazePanel1State == 2) && (R2_GLOBALS._ductMazePanel2State == 3) && (R2_GLOBALS._ductMazePanel3State == 1))
+ scene->_field418 = 4;
+
+ return true;
+}
+
+void Scene1200::LaserPanel::postInit(SceneObjectList *OwnerList) {
+ Scene1200 *scene = (Scene1200 *)R2_GLOBALS._sceneManager._scene;
+
+ scene->_field41A = 1;
+ R2_GLOBALS._events.setCursor(CURSOR_USE);
+ setup2(1003, 1, 1, 100, 40);
+ setup3(1200, 11, -1, -1);
+ R2_GLOBALS._sound2.play(259);
+ _jumper1.init(1);
+ _jumper2.init(2);
+ _jumper3.init(3);
+
+ R2_GLOBALS._player._canWalk = false;
+}
+
+void Scene1200::LaserPanel::remove() {
+ Scene1200 *scene = (Scene1200 *)R2_GLOBALS._sceneManager._scene;
+
+ scene->_field41A = 0;
+ scene->_sceneAreas.remove(&_jumper1);
+ scene->_sceneAreas.remove(&_jumper2);
+ scene->_sceneAreas.remove(&_jumper3);
+ _jumper1.remove();
+ _jumper2.remove();
+ _jumper3.remove();
+
+ ModalWindow::remove();
+ R2_GLOBALS._player._canWalk = true;
+}
+
+void Scene1200::postInit(SceneObjectList *OwnerList) {
+ loadScene(1200);
+ SceneExt::postInit();
+
+ if (R2_GLOBALS._sceneManager._previousScene < 3200)
+ R2_GLOBALS._sound1.play(257);
+
+ _nextCrawlDirection = CRAWL_EAST;
+ _field414 = 0;
+ _field416 = 0;
+ _field418 = 0;
+ _field41A = 0;
+
+ if ((R2_GLOBALS._ductMazePanel1State == 1) && (R2_GLOBALS._ductMazePanel2State == 1) && (R2_GLOBALS._ductMazePanel3State == 1))
+ _field418 = 1;
+ else if ((R2_GLOBALS._ductMazePanel1State == 2) && (R2_GLOBALS._ductMazePanel2State == 1) && (R2_GLOBALS._ductMazePanel3State == 1))
+ _field418 = 2;
+ else if ((R2_GLOBALS._ductMazePanel1State == 2) && (R2_GLOBALS._ductMazePanel2State == 1) && (R2_GLOBALS._ductMazePanel3State == 2))
+ _field418 = 3;
+ else if ((R2_GLOBALS._ductMazePanel1State == 2) && (R2_GLOBALS._ductMazePanel2State == 3) && (R2_GLOBALS._ductMazePanel3State == 1))
+ _field418 = 4;
+
+ R2_GLOBALS._player.postInit();
+ R2_GLOBALS._player.disableControl();
+ R2_GLOBALS._player.setup(3156, 1, 6);
+ R2_GLOBALS._player.setPosition(Common::Point(160, 70));
+ R2_GLOBALS._player._numFrames = 10;
+ R2_GLOBALS._player._oldCharacterScene[R2_MIRANDA] = 1200;
+
+ _actor1.postInit();
+ _actor1.hide();
+
+ _mazeUI.setDisplayBounds(Rect(110, 20, 210, 120));
+
+ _mazeUI.postInit();
+ _mazeUI.load(1);
+ _mazeUI.setMazePosition(R2_GLOBALS._ventCellPos);
+
+ R2_GLOBALS._player.enableControl();
+ _item1.setDetails(Rect(0, 0, 320, 200), 1200, 0, 1, 2, 1, NULL);
+}
+
+void Scene1200::signal() {
+ switch (_sceneMode++) {
+ case 1:
+ // No break on purpose
+ case 1200:
+ // No break on purpose
+ case 1201:
+ // No break on purpose
+ case 1202:
+ // No break on purpose
+ case 1203:
+ R2_GLOBALS._player.enableControl();
+ // CHECKME: The original is calling _eventManager.waitEvent();
+ _sceneMode = 2;
+ break;
+ case 10:
+ _field416 = 1;
+ _field414 = 6;
+ R2_GLOBALS._player._numFrames = 5;
+ R2_GLOBALS._player.setStrip(1);
+ R2_GLOBALS._player.setFrame(5);
+ R2_GLOBALS._player.animate(ANIM_MODE_6, this);
+ break;
+ case 11:
+ // No break on purpose
+ case 21:
+ // No break on purpose
+ case 31:
+ // No break on purpose
+ case 41:
+ _field416 = 0;
+ break;
+ case 12:
+ _field414 = 14;
+ R2_GLOBALS._player._numFrames = 10;
+ R2_GLOBALS._player.setup(3155, 1, 4);
+ R2_GLOBALS._player.setPosition(Common::Point(160, 70));
+ R2_GLOBALS._player.animate(ANIM_MODE_2, NULL);
+ break;
+ case 13:
+ // No break on purpose
+ case 16:
+ // No break on purpose
+ case 23:
+ // No break on purpose
+ case 26:
+ // No break on purpose
+ case 33:
+ // No break on purpose
+ case 36:
+ // No break on purpose
+ case 43:
+ // No break on purpose
+ case 46:
+ R2_GLOBALS._player.setFrame(4);
+ _sceneMode = 1;
+ setAction(&_sequenceManager, this, 1, &R2_GLOBALS._player, NULL);
+ break;
+ case 15:
+ // No break on purpose
+ case 25:
+ // No break on purpose
+ case 35:
+ // No break on purpose
+ case 45:
+ _field414 = 20;
+ R2_GLOBALS._player.animate(ANIM_MODE_2, NULL);
+ break;
+ case 20:
+ _field416 = 1;
+ _field414 = 6;
+ R2_GLOBALS._player._numFrames = 5;
+ R2_GLOBALS._player.setStrip(2);
+ R2_GLOBALS._player.setFrame(5);
+ R2_GLOBALS._player.animate(ANIM_MODE_6, this);
+ break;
+ case 22:
+ _field414 = 14;
+ R2_GLOBALS._player._numFrames = 10;
+ R2_GLOBALS._player.setup(3155, 2, 4);
+ R2_GLOBALS._player.setPosition(Common::Point(160, 70));
+ R2_GLOBALS._player.animate(ANIM_MODE_2, NULL);
+ break;
+ case 30:
+ _field416 = 1;
+ _field414 = 6;
+ R2_GLOBALS._player._numFrames = 5;
+ R2_GLOBALS._player.setStrip(3);
+ R2_GLOBALS._player.setFrame(5);
+ R2_GLOBALS._player.animate(ANIM_MODE_6, this);
+ break;
+ case 32:
+ _field414 = 14;
+ R2_GLOBALS._player._numFrames = 10;
+ R2_GLOBALS._player.setup(3155, 3, 4);
+ R2_GLOBALS._player.setPosition(Common::Point(160, 70));
+ R2_GLOBALS._player.animate(ANIM_MODE_2, NULL);
+ break;
+ case 40:
+ _field416 = 1;
+ _field414 = 6;
+ R2_GLOBALS._player._numFrames = 5;
+ R2_GLOBALS._player.setStrip(4);
+ R2_GLOBALS._player.setFrame(5);
+ R2_GLOBALS._player.animate(ANIM_MODE_6, this);
+ break;
+ case 42:
+ _field414 = 14;
+ R2_GLOBALS._player._numFrames = 10;
+ R2_GLOBALS._player.setup(3155, 4, 4);
+ R2_GLOBALS._player.setPosition(Common::Point(160, 70));
+ R2_GLOBALS._player.animate(ANIM_MODE_2, NULL);
+ break;
+ case 50:
+ // No break on purpose
+ case 55:
+ // No break on purpose
+ case 60:
+ R2_GLOBALS._player.setup(3156, 5, 1);
+ R2_GLOBALS._player._numFrames = 5;
+ R2_GLOBALS._player.animate(ANIM_MODE_5, this);
+ break;
+ case 51:
+ // No break on purpose
+ case 56:
+ // No break on purpose
+ case 117:
+ R2_GLOBALS._player.setup(3157, 1, 1);
+ R2_GLOBALS._player.animate(ANIM_MODE_5, this);
+ break;
+ case 52:
+ // No break on purpose
+ case 82:
+ // No break on purpose
+ case 118:
+ R2_GLOBALS._player.setup(3156, 3, 6);
+ _sceneMode = 1;
+ setAction(&_sequenceManager, this, 1, &R2_GLOBALS._player, NULL);
+ break;
+ case 57:
+ // No break on purpose
+ case 91:
+ // No break on purpose
+ case 96:
+ R2_GLOBALS._player.setup(3157, 2, 1);
+ R2_GLOBALS._player.animate(ANIM_MODE_5, this);
+ break;
+ case 58:
+ // No break on purpose
+ case 92:
+ // No break on purpose
+ case 122:
+ R2_GLOBALS._player.setup(3156, 2, 6);
+ _sceneMode = 1;
+ setAction(&_sequenceManager, this, 1, &R2_GLOBALS._player, NULL);
+ break;
+ case 61:
+ R2_GLOBALS._player.setup(3157, 4, 5);
+ R2_GLOBALS._player.animate(ANIM_MODE_6, this);
+ break;
+ case 62:
+ // No break on purpose
+ case 72:
+ // No break on purpose
+ case 98:
+ R2_GLOBALS._player.setup(3156, 4, 6);
+ _sceneMode = 1;
+ setAction(&_sequenceManager, this, 1, &R2_GLOBALS._player, NULL);
+ break;
+ case 70:
+ // No break on purpose
+ case 75:
+ // No break on purpose
+ case 80:
+ R2_GLOBALS._player.setup(3156, 6, 1);
+ R2_GLOBALS._player._numFrames = 5;
+ R2_GLOBALS._player.animate(ANIM_MODE_5, this);
+ break;
+ case 71:
+ // No break on purpose
+ case 76:
+ // No break on purpose
+ case 97:
+ R2_GLOBALS._player.setup(3157, 3, 1);
+ R2_GLOBALS._player.animate(ANIM_MODE_5, this);
+ break;
+ case 77:
+ // No break on purpose
+ case 111:
+ // No break on purpose
+ case 116:
+ R2_GLOBALS._player.setup(3157, 4, 1);
+ R2_GLOBALS._player.animate(ANIM_MODE_5, this);
+ break;
+ case 78:
+ // No break on purpose
+ case 102:
+ // No break on purpose
+ case 112:
+ R2_GLOBALS._player.setup(3156, 1, 6);
+ _sceneMode = 1;
+ setAction(&_sequenceManager, this, 1, &R2_GLOBALS._player, NULL);
+ break;
+ case 81:
+ R2_GLOBALS._player.setup(3157, 2, 5);
+ R2_GLOBALS._player.animate(ANIM_MODE_6, this);
+ break;
+ case 90:
+ // No break on purpose
+ case 95:
+ // No break on purpose
+ case 100:
+ R2_GLOBALS._player.setup(3156, 7, 1);
+ R2_GLOBALS._player._numFrames = 5;
+ R2_GLOBALS._player.animate(ANIM_MODE_5, this);
+ break;
+ case 101:
+ R2_GLOBALS._player.setup(3157, 1, 5);
+ R2_GLOBALS._player.animate(ANIM_MODE_6, this);
+ break;
+ case 110:
+ // No break on purpose
+ case 115:
+ // No break on purpose
+ case 120:
+ R2_GLOBALS._player.setup(3156, 8, 1);
+ R2_GLOBALS._player._numFrames = 5;
+ R2_GLOBALS._player.animate(ANIM_MODE_5, this);
+ break;
+ case 121:
+ R2_GLOBALS._player.setup(3157, 3, 5);
+ R2_GLOBALS._player.animate(ANIM_MODE_6, this);
+ break;
+ default:
+ // CHECKME: The original is walling _eventManager.waitEvent();
+ _sceneMode = 2;
+ break;
+ }
+}
+
+void Scene1200::process(Event &event) {
+ if (_field414 != 0)
+ return;
+
+ Scene::process(event);
+
+ if (!R2_GLOBALS._player._canWalk)
+ return;
+
+ if (event.eventType == EVENT_BUTTON_DOWN) {
+ Common::Point cellPos = R2_GLOBALS._ventCellPos;
+ _mazeUI.pixelToCellXY(cellPos);
+
+ int cellId = _mazeUI.getCellFromPixelXY(event.mousePos);
+ switch (R2_GLOBALS._events.getCursor()) {
+ case CURSOR_WALK:
+ event.handled = true;
+ if ((event.mousePos.x > 179) && (event.mousePos.x < 210) && (event.mousePos.y > 50) && (event.mousePos.y < 89))
+ startCrawling(CRAWL_EAST);
+
+ if ((event.mousePos.x > 109) && (event.mousePos.x < 140) && (event.mousePos.y > 50) && (event.mousePos.y < 89))
+ startCrawling(CRAWL_WEST);
+
+ if ((event.mousePos.x > 140) && (event.mousePos.x < 179) && (event.mousePos.y > 89) && (event.mousePos.y < 120))
+ startCrawling(CRAWL_SOUTH);
+
+ if ((event.mousePos.x > 140) && (event.mousePos.x < 179) && (event.mousePos.y > 19) && (event.mousePos.y < 50))
+ startCrawling(CRAWL_NORTH);
+ break;
+ case CURSOR_USE:
+ if (cellId > 36) {
+ if ( ((cellPos.x == 3) && (cellPos.y == 33))
+ || ((cellPos.x == 7) && (cellPos.y == 33))
+ || ((cellPos.x == 33) && (cellPos.y == 41))
+ || ((cellPos.x == 5) && (cellPos.y == 5))
+ || ((cellPos.x == 13) && (cellPos.y == 21))
+ || ((cellPos.x == 17) && (cellPos.y == 21))
+ || ((cellPos.x == 17) && (cellPos.y == 5))
+ || ((cellPos.x == 17) && (cellPos.y == 9))
+ || ((cellPos.x == 29) && (cellPos.y == 17))
+ || ((cellPos.x == 33) && (cellPos.y == 17))
+ || ((cellPos.x == 35) && (cellPos.y == 17))
+ || ((cellPos.x == 41) && (cellPos.y == 21)) ) {
+ _laserPanel.postInit();
+ event.handled = true;
+ }
+ }
+
+ if ((cellId == 1) || (cellId == 4) || (cellId == 11) || (cellId == 14)) {
+ if ( ((cellPos.x == 3) && (cellPos.y == 9))
+ || ((cellPos.x == 11) && (cellPos.y == 27))
+ || ((cellPos.x == 17) && (cellPos.y == 7))
+ || ((cellPos.x == 17) && (cellPos.y == 27))
+ || ((cellPos.x == 17) && (cellPos.y == 33))
+ || (cellPos.x == 33) ) {
+ switch (cellPos.x) {
+ case 3:
+ R2_GLOBALS._sceneManager.changeScene(3150);
+ break;
+ case 33:
+ if (R2_GLOBALS._scientistConvIndex >= 4)
+ R2_GLOBALS._sceneManager.changeScene(3250);
+ else
+ SceneItem::display(1200, 6, 0, 280, 1, 160, 9, 1, 2, 20, 7, 154, LIST_END);
+ break;
+ default:
+ SceneItem::display(1200, 5, 0, 280, 1, 160, 9, 1, 2, 20, 7, 154, LIST_END);
+ break;
+ }
+ event.handled = true;
+ }
+ }
+ break;
+ case CURSOR_LOOK:
+ if ((cellId == 1) || (cellId == 4) || (cellId == 11) || (cellId == 14)) {
+ event.handled = true;
+ switch (cellPos.x) {
+ case 3:
+ // It was your cell.
+ SceneItem::display(1200, 8, 0, 280, 1, 160, 9, 1, 2, 20, 7, 7, LIST_END);
+ break;
+ case 9:
+ R2_GLOBALS._sceneManager.changeScene(3240);
+ break;
+ case 11:
+ if (cellPos.y == 27)
+ R2_GLOBALS._sceneManager.changeScene(3210);
+ else
+ // A vent grill
+ SceneItem::display(1200, 10, 0, 280, 1, 160, 9, 1, 2, 20, 7, 7, LIST_END);
+ break;
+ case 17:
+ switch (cellPos.y) {
+ case 5:
+ R2_GLOBALS._sceneManager.changeScene(3230);
+ break;
+ case 21:
+ R2_GLOBALS._sceneManager.changeScene(3220);
+ break;
+ case 33:
+ R2_GLOBALS._sceneManager.changeScene(3200);
+ break;
+ default:
+ // A vent grill
+ SceneItem::display(1200, 10, 0, 280, 1, 160, 9, 1, 2, 20, 7, 7, LIST_END);
+ break;
+ }
+ break;
+ case 33:
+ R2_GLOBALS._sceneManager.changeScene(3245);
+ break;
+ default:
+ SceneItem::display(1200, 10, 0, 280, 1, 160, 9, 1, 2, 20, 7, 7, LIST_END);
+ break;
+ }
+ }
+ if (cellId > 36) {
+ // "An anti-pest laser"
+ event.handled = true;
+ SceneItem::display(1200, 9, 0, 280, 1, 160, 9, 1, 2, 20, 7, 7, LIST_END);
+ }
+ break;
+ case CURSOR_TALK:
+ event.handled = true;
+ break;
+ default:
+ return;
+ }
+ } else if (event.eventType == EVENT_KEYPRESS) {
+ if (_field414) {
+ event.handled = false;
+ return;
+ }
+
+ switch (event.kbd.keycode) {
+ case Common::KEYCODE_KP8:
+ case Common::KEYCODE_UP:
+ startCrawling(CRAWL_NORTH);
+ break;
+ case Common::KEYCODE_KP4:
+ case Common::KEYCODE_LEFT:
+ startCrawling(CRAWL_WEST);
+ break;
+ case Common::KEYCODE_KP6:
+ case Common::KEYCODE_RIGHT:
+ startCrawling(CRAWL_EAST);
+ break;
+ case Common::KEYCODE_KP2:
+ case Common::KEYCODE_DOWN:
+ startCrawling(CRAWL_SOUTH);
+ break;
+ default:
+ event.handled = false;
+ return;
+ break;
+ }
+ } else
+ return;
+}
+
+void Scene1200::dispatch() {
+ Rect tmpRect;
+ Scene::dispatch();
+
+ if (_fixupMaze) {
+ _mazeUI.setMazePosition(R2_GLOBALS._ventCellPos);
+ //_mazeUI.draw();
+ _fixupMaze = false;
+ }
+
+ if (_field414 != 0) {
+ tmpRect.set(110, 20, 210, 120);
+ _field414--;
+
+ switch (_nextCrawlDirection) {
+ case CRAWL_EAST:
+ R2_GLOBALS._ventCellPos.x += 2;
+ break;
+ case CRAWL_WEST:
+ R2_GLOBALS._ventCellPos.x -= 2;
+ break;
+ case CRAWL_SOUTH:
+ R2_GLOBALS._ventCellPos.y += 2;
+ break;
+ case CRAWL_NORTH:
+ R2_GLOBALS._ventCellPos.y -= 2;
+ break;
+ default:
+ break;
+ }
+
+ _mazeUI.setMazePosition(R2_GLOBALS._ventCellPos);
+ //_mazeUI.draw();
+
+ if (_field416 != 0) {
+ switch(_nextCrawlDirection) {
+ case CRAWL_EAST:
+ R2_GLOBALS._player.setPosition(Common::Point(R2_GLOBALS._player._position.x - 2, R2_GLOBALS._player._position.y));
+ break;
+ case CRAWL_WEST:
+ R2_GLOBALS._player.setPosition(Common::Point(R2_GLOBALS._player._position.x + 2, R2_GLOBALS._player._position.y));
+ break;
+ case CRAWL_SOUTH:
+ R2_GLOBALS._player.setPosition(Common::Point(R2_GLOBALS._player._position.x, R2_GLOBALS._player._position.y - 2));
+ break;
+ case CRAWL_NORTH:
+ R2_GLOBALS._player.setPosition(Common::Point(R2_GLOBALS._player._position.x, R2_GLOBALS._player._position.y + 2));
+ break;
+ default:
+ break;
+ }
+ }
+ if (_field414 == 0) {
+ if (_field416 == 0)
+ R2_GLOBALS._player.animate(ANIM_MODE_NONE, NULL);
+ signal();
+ }
+ }
+}
+
+void Scene1200::saveCharacter(int characterIndex) {
+ R2_GLOBALS._sound1.fadeOut2(NULL);
+ SceneExt::saveCharacter(characterIndex);
+}
+
+void Scene1200::startCrawling(CrawlDirection dir) {
+ Common::Point cellPos = R2_GLOBALS._ventCellPos;
+ _mazeUI.pixelToCellXY(cellPos);
+
+ switch (dir) {
+ case CRAWL_EAST:
+ if ( ((_mazeUI.getCellFromPixelXY(Common::Point(200, 50)) > 36) || (_mazeUI.getCellFromPixelXY(Common::Point(200, 88)) > 36))
+ && ( ((cellPos.x == 3) && (cellPos.y == 33) && (_field418 != 4))
+ || ((cellPos.x == 13) && (cellPos.y == 21) && (_field418 != 2))
+ || ((cellPos.x == 29) && (cellPos.y == 17) && (_field418 != 1))
+ || ((cellPos.x == 33) && (cellPos.y == 41)) )
+ ) {
+ R2_GLOBALS._player.disableControl();
+ _sceneMode = 1200;
+ setAction(&_sequenceManager, this, 1200, &_actor1, NULL);
+ } else if (_mazeUI.getCellFromPixelXY(Common::Point(200, 69)) == 36) {
+ switch (_nextCrawlDirection) {
+ case CRAWL_EAST:
+ if (R2_GLOBALS._player._visage == 3155)
+ _sceneMode = 15;
+ else
+ _sceneMode = 10;
+ break;
+ case CRAWL_WEST:
+ if (R2_GLOBALS._player._visage == 3156)
+ _sceneMode = 76;
+ else
+ _sceneMode = 75;
+ break;
+ case CRAWL_SOUTH:
+ if (R2_GLOBALS._player._visage == 3156)
+ _sceneMode = 101;
+ else
+ _sceneMode = 100;
+ break;
+ case CRAWL_NORTH:
+ if (R2_GLOBALS._player._visage == 3156)
+ _sceneMode = 111;
+ else
+ _sceneMode = 110;
+ break;
+ default:
+ break;
+ }
+ R2_GLOBALS._player.disableControl();
+ _nextCrawlDirection = 1;
+ signal();
+ }
+ break;
+ case CRAWL_WEST:
+ if ( ((_mazeUI.getCellFromPixelXY(Common::Point(120, 50)) > 36) || (_mazeUI.getCellFromPixelXY(Common::Point(120, 88)) > 36))
+ && ( ((cellPos.x == 7) && (cellPos.y == 33) && (_field418 != 4))
+ || ((cellPos.x == 17) && (cellPos.y == 21) && (_field418 != 2))
+ || ((cellPos.x == 33) && (cellPos.y == 17) && (_field418 != 1))
+ || ((cellPos.x == 5) && (cellPos.y == 5)) )
+ ) {
+ R2_GLOBALS._player.disableControl();
+ _sceneMode = 1201;
+ setAction(&_sequenceManager, this, 1201, &_actor1, NULL);
+ } else if (_mazeUI.getCellFromPixelXY(Common::Point(120, 69)) == 36) {
+ switch (_nextCrawlDirection) {
+ case CRAWL_EAST:
+ if (R2_GLOBALS._player._visage == 3156)
+ _sceneMode = 56;
+ else
+ _sceneMode = 55;
+ break;
+ case CRAWL_WEST:
+ if (R2_GLOBALS._player._visage == 3155)
+ _sceneMode = 25;
+ else
+ _sceneMode = 20;
+ break;
+ case CRAWL_SOUTH:
+ if (R2_GLOBALS._player._visage == 3156)
+ _sceneMode = 91;
+ else
+ _sceneMode = 90;
+ break;
+ case CRAWL_NORTH:
+ if (R2_GLOBALS._player._visage == 3156)
+ _sceneMode = 121;
+ else
+ _sceneMode = 120;
+ break;
+ default:
+ break;
+ }
+ R2_GLOBALS._player.disableControl();
+ _nextCrawlDirection = 2;
+ signal();
+ }
+ break;
+ case CRAWL_SOUTH:
+ if ( ((_mazeUI.getCellFromPixelXY(Common::Point(140, 110)) > 36) || (_mazeUI.getCellFromPixelXY(Common::Point(178, 110)) > 36))
+ && ( ((cellPos.x == 17) && (cellPos.y == 5) && (_field418 != 3))
+ || ((cellPos.x == 41) && (cellPos.y == 21)) )
+ ) {
+ R2_GLOBALS._player.disableControl();
+ _sceneMode = 1203;
+ setAction(&_sequenceManager, this, 1203, &_actor1, NULL);
+ } else if (_mazeUI.getCellFromPixelXY(Common::Point(160, 110)) == 36) {
+ switch (_nextCrawlDirection) {
+ case CRAWL_EAST:
+ if (R2_GLOBALS._player._visage == 3156)
+ _sceneMode = 51;
+ else
+ _sceneMode = 50;
+ break;
+ case CRAWL_WEST:
+ if (R2_GLOBALS._player._visage == 3156)
+ _sceneMode = 81;
+ else
+ _sceneMode = 80;
+ break;
+ case CRAWL_SOUTH:
+ if (R2_GLOBALS._player._visage == 3155)
+ _sceneMode = 35;
+ else
+ _sceneMode = 30;
+ break;
+ case CRAWL_NORTH:
+ if (R2_GLOBALS._player._visage == 3156)
+ _sceneMode = 116;
+ else
+ _sceneMode = 115;
+ break;
+ default:
+ break;
+ }
+ R2_GLOBALS._player.disableControl();
+ _nextCrawlDirection = 3;
+ signal();
+ }
+ break;
+ case CRAWL_NORTH:
+ if ( ((_mazeUI.getCellFromPixelXY(Common::Point(140, 30)) > 36) || (_mazeUI.getCellFromPixelXY(Common::Point(178, 30)) > 36))
+ && ( ((cellPos.x == 17) && (cellPos.y == 9) && (_field418 != 3))
+ || ((cellPos.x == 35) && (cellPos.y == 17)) )
+ ) {
+ R2_GLOBALS._player.disableControl();
+ _sceneMode = 1202;
+ setAction(&_sequenceManager, this, 1202, &_actor1, NULL);
+ } else if (_mazeUI.getCellFromPixelXY(Common::Point(160, 30)) == 36) {
+ switch (_nextCrawlDirection) {
+ case CRAWL_EAST:
+ if (R2_GLOBALS._player._visage == 3156)
+ _sceneMode = 61;
+ else
+ _sceneMode = 60;
+ break;
+ case CRAWL_WEST:
+ if (R2_GLOBALS._player._visage == 3156)
+ _sceneMode = 71;
+ else
+ _sceneMode = 70;
+ break;
+ case CRAWL_SOUTH:
+ if (R2_GLOBALS._player._visage == 3156)
+ _sceneMode = 96;
+ else
+ _sceneMode = 95;
+ break;
+ case CRAWL_NORTH:
+ if (R2_GLOBALS._player._visage == 3155)
+ _sceneMode = 45;
+ else
+ _sceneMode = 40;
+ break;
+ default:
+ _sceneMode = 1;
+ R2_GLOBALS._player.setup(3156, 4, 6);
+ break;
+ }
+ R2_GLOBALS._player.disableControl();
+ _nextCrawlDirection = 4;
+ signal();
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+} // End of namespace Ringworld2
+} // End of namespace TsAGE
diff --git a/engines/tsage/ringworld2/ringworld2_airduct.h b/engines/tsage/ringworld2/ringworld2_airduct.h
new file mode 100644
index 0000000000..89dfe778d0
--- /dev/null
+++ b/engines/tsage/ringworld2/ringworld2_airduct.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 TSAGE_RINGWORLD2_AIRDUCT_H
+#define TSAGE_RINGWORLD2_AIRDUCT_H
+
+#include "tsage/events.h"
+#include "tsage/core.h"
+#include "tsage/scenes.h"
+#include "tsage/globals.h"
+#include "tsage/sound.h"
+#include "tsage/ringworld2/ringworld2_logic.h"
+
+namespace TsAGE {
+
+namespace Ringworld2 {
+
+using namespace TsAGE;
+
+class Scene1200 : public SceneExt {
+ enum CrawlDirection { CRAWL_EAST = 1, CRAWL_WEST = 2, CRAWL_SOUTH = 3, CRAWL_NORTH = 4 };
+
+ class LaserPanel: public ModalWindow {
+ public:
+ class Jumper : public SceneActorExt {
+ public:
+ void init(int state);
+ virtual bool startAction(CursorType action, Event &event);
+ };
+
+ Jumper _jumper1;
+ Jumper _jumper2;
+ Jumper _jumper3;
+
+ LaserPanel();
+
+ virtual void postInit(SceneObjectList *OwnerList = NULL);
+ virtual void remove();
+ };
+
+public:
+ NamedHotspot _item1;
+ SceneActor _actor1;
+ LaserPanel _laserPanel;
+ MazeUI _mazeUI;
+ SequenceManager _sequenceManager;
+
+ int _nextCrawlDirection;
+ int _field414;
+ int _field416;
+ int _field418;
+ int _field41A;
+ bool _fixupMaze;
+
+ Scene1200();
+ void synchronize(Serializer &s);
+
+ void startCrawling(CrawlDirection dir);
+
+ virtual void postInit(SceneObjectList *OwnerList = NULL);
+ virtual void signal();
+ virtual void process(Event &event);
+ virtual void dispatch();
+ virtual void saveCharacter(int characterIndex);
+};
+
+} // End of namespace Ringworld2
+} // End of namespace TsAGE
+
+#endif
diff --git a/engines/tsage/ringworld2/ringworld2_logic.cpp b/engines/tsage/ringworld2/ringworld2_logic.cpp
index 99188c1ab6..d24541932f 100644
--- a/engines/tsage/ringworld2/ringworld2_logic.cpp
+++ b/engines/tsage/ringworld2/ringworld2_logic.cpp
@@ -32,6 +32,9 @@
#include "tsage/ringworld2/ringworld2_scenes1.h"
#include "tsage/ringworld2/ringworld2_scenes2.h"
#include "tsage/ringworld2/ringworld2_scenes3.h"
+#include "tsage/ringworld2/ringworld2_airduct.h"
+#include "tsage/ringworld2/ringworld2_outpost.h"
+#include "tsage/ringworld2/ringworld2_vampire.h"
namespace TsAGE {
@@ -355,6 +358,11 @@ SceneExt::SceneExt(): Scene() {
// to make inter-scene debugging easier, I'm explicitly resetting the _animationCtr
// on scene start, since scene objects aren't drawn while it's non-zero
R2_GLOBALS._animationCtr = 0;
+
+ // WORKAROUND: We had a case where at some point the number of modal dialogs
+ // open became incorrect. So reset it on scene changes to fix the problem if
+ // it ever happens
+ R2_GLOBALS._insetUp = 0;
}
void SceneExt::synchronize(Serializer &s) {
diff --git a/engines/tsage/ringworld2/ringworld2_outpost.cpp b/engines/tsage/ringworld2/ringworld2_outpost.cpp
new file mode 100644
index 0000000000..cad21b4623
--- /dev/null
+++ b/engines/tsage/ringworld2/ringworld2_outpost.cpp
@@ -0,0 +1,4700 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "graphics/cursorman.h"
+#include "tsage/tsage.h"
+#include "tsage/staticres.h"
+#include "tsage/ringworld2/ringworld2_outpost.h"
+
+namespace TsAGE {
+
+namespace Ringworld2 {
+
+/*--------------------------------------------------------------------------
+ * Scene 1337 - Card game
+ *
+ *--------------------------------------------------------------------------*/
+
+Scene1337::Card::Card() {
+ _cardId = 0;
+ _stationPos = Common::Point(0, 0);
+}
+
+void Scene1337::Card::synchronize(Serializer &s) {
+ _card.synchronize(s);
+
+ s.syncAsSint16LE(_cardId);
+ s.syncAsSint16LE(_stationPos.x);
+ s.syncAsSint16LE(_stationPos.y);
+}
+
+bool Scene1337::Card::isIn(Common::Point pt) {
+ if ((_stationPos.x > pt.x) || (_stationPos.x + 24 < pt.x))
+ return false;
+
+ if ((_stationPos.y > pt.y) || (_stationPos.y + 24 < pt.y))
+ return false;
+
+ return true;
+}
+
+Scene1337::GameBoardSide::GameBoardSide() {
+ _card1Pos = Common::Point(0, 0);
+ _card2Pos = Common::Point(0, 0);
+ _card3Pos = Common::Point(0, 0);
+ _card4Pos = Common::Point(0, 0);
+ _frameNum = 0;
+}
+
+void Scene1337::GameBoardSide::synchronize(Serializer &s) {
+ SceneHotspot::synchronize(s);
+
+ for (int i = 0; i < 4; i++)
+ _handCard[i].synchronize(s);
+
+ for (int i = 0; i < 8; i++)
+ _outpostStation[i].synchronize(s);
+
+ _delayCard.synchronize(s);
+ _emptyStationPos.synchronize(s);
+
+ s.syncAsSint16LE(_card1Pos.x);
+ s.syncAsSint16LE(_card1Pos.y);
+ s.syncAsSint16LE(_card2Pos.x);
+ s.syncAsSint16LE(_card2Pos.y);
+ s.syncAsSint16LE(_card3Pos.x);
+ s.syncAsSint16LE(_card3Pos.y);
+ s.syncAsSint16LE(_card4Pos.x);
+ s.syncAsSint16LE(_card4Pos.y);
+ s.syncAsSint16LE(_frameNum);
+}
+
+Scene1337::Scene1337() {
+ _autoplay = false;
+ _cardsAvailableNumb = 0;
+ _currentDiscardIndex = 0;
+
+ for (int i = 0; i < 100; i++)
+ _availableCardsPile[i] = 0;
+
+ _shuffleEndedFl = false;
+ _currentPlayerNumb = 0;
+ _actionPlayerIdx = 0;
+ _actionVictimIdx = 0;
+ _showPlayerTurn = false;
+ _displayHelpFl = false;
+ _winnerId = -1;
+ _instructionsDisplayedFl = false;
+ _instructionsWaitCount = 0;
+
+ _delayedFunction = nullptr;
+ _actionCard1 = nullptr;
+ _actionCard2 = nullptr;
+ _actionCard3 = nullptr;
+
+ _cursorCurRes = 0;
+ _cursorCurStrip = 0;
+ _cursorCurFrame = 0;
+}
+
+void Scene1337::synchronize(Serializer &s) {
+ _actionCard1->synchronize(s);
+ _actionCard2->synchronize(s);
+ _actionCard3->synchronize(s);
+ _animatedCard.synchronize(s);
+ _shuffleAnimation.synchronize(s);
+ _discardedPlatformCard.synchronize(s);
+ _selectedCard.synchronize(s);
+ _discardPile.synchronize(s);
+ _stockCard.synchronize(s);
+ _aSound1.synchronize(s);
+ _aSound2.synchronize(s);
+ _helpIcon.synchronize(s);
+ _stockPile.synchronize(s);
+ _actionItem.synchronize(s);
+ _currentPlayerArrow.synchronize(s);
+
+ for (int i = 0; i < 4; i++)
+ _gameBoardSide[i].synchronize(s);
+
+ for (int i = 0; i < 8; i++) {
+ _upperDisplayCard[i].synchronize(s);
+ _lowerDisplayCard[i].synchronize(s);
+ }
+
+ // TODO s.syncPointer(_delayedFunction);
+ s.syncAsByte(_autoplay);
+ s.syncAsByte(_shuffleEndedFl);
+ s.syncAsByte(_showPlayerTurn);
+ s.syncAsByte(_displayHelpFl);
+ s.syncAsByte(_instructionsDisplayedFl);
+ s.syncAsSint16LE(_currentDiscardIndex);
+ s.syncAsSint16LE(_cardsAvailableNumb);
+ s.syncAsSint16LE(_currentPlayerNumb);
+ s.syncAsSint16LE(_actionPlayerIdx);
+ s.syncAsSint16LE(_actionVictimIdx);
+ s.syncAsSint16LE(_winnerId);
+ s.syncAsSint16LE(_instructionsWaitCount);
+ s.syncAsSint16LE(_cursorCurRes);
+ s.syncAsSint16LE(_cursorCurStrip);
+ s.syncAsSint16LE(_cursorCurFrame);
+
+ for (int i = 0; i < 100; i++)
+ s.syncAsSint16LE(_availableCardsPile[i]);
+
+}
+
+void Scene1337::Action1337::waitFrames(int32 frameCount) {
+ uint32 firstFrameNumber = g_globals->_events.getFrameNumber();
+ uint32 curFrame = firstFrameNumber;
+ uint32 destFrame = firstFrameNumber + frameCount;
+
+ while ((curFrame < destFrame) && !g_vm->shouldQuit()) {
+ TsAGE::Event event;
+ g_globals->_events.getEvent(event);
+ curFrame = g_globals->_events.getFrameNumber();
+ }
+
+ // CHECKME: The original is calling _eventManager.waitEvent();
+}
+
+/**
+ * Display instructions
+ */
+void Scene1337::Action1::signal() {
+ Scene1337 *scene = (Scene1337 *)R2_GLOBALS._sceneManager._scene;
+
+ switch (_actionIndex++) {
+ case 1: {
+ scene->actionDisplay(1331, 6, 159, 10, 1, 200, 0, 7, 0, 154, 154);
+ R2_GLOBALS._sceneObjects->draw();
+ scene->actionDisplay(1331, 7, 159, 10, 1, 200, 0, 7, 0, 154, 154);
+ scene->actionDisplay(1331, 8, 159, 10, 1, 200, 0, 7, 0, 154, 154);
+
+ scene->_gameBoardSide[1]._outpostStation[0]._cardId = 2;
+ scene->_gameBoardSide[1]._outpostStation[0]._card.postInit();
+ scene->_gameBoardSide[1]._outpostStation[0]._card.setVisage(1332);
+ scene->_gameBoardSide[1]._outpostStation[0]._card.setPosition(scene->_gameBoardSide[1]._outpostStation[0]._stationPos, 0);
+ scene->_gameBoardSide[1]._outpostStation[0]._card.setStrip(2);
+ scene->_gameBoardSide[1]._outpostStation[0]._card.setFrame(scene->_gameBoardSide[1]._outpostStation[0]._cardId);
+ scene->_gameBoardSide[1]._outpostStation[0]._card.fixPriority(170);
+ scene->setAnimationInfo(&scene->_gameBoardSide[1]._outpostStation[0]);
+
+ scene->_gameBoardSide[1]._outpostStation[1]._cardId = 3;
+ scene->_gameBoardSide[1]._outpostStation[1]._card.postInit();
+ scene->_gameBoardSide[1]._outpostStation[1]._card.setVisage(1332);
+ scene->_gameBoardSide[1]._outpostStation[1]._card.setPosition(scene->_gameBoardSide[1]._outpostStation[1]._stationPos, 0);
+ scene->_gameBoardSide[1]._outpostStation[1]._card.setStrip(2);
+ scene->_gameBoardSide[1]._outpostStation[1]._card.setFrame(scene->_gameBoardSide[1]._outpostStation[1]._cardId);
+ scene->_gameBoardSide[1]._outpostStation[1]._card.fixPriority(170);
+ scene->setAnimationInfo(&scene->_gameBoardSide[1]._outpostStation[1]);
+
+ scene->_gameBoardSide[2]._outpostStation[0]._cardId = 4;
+ scene->_gameBoardSide[2]._outpostStation[0]._card.postInit();
+ scene->_gameBoardSide[2]._outpostStation[0]._card.setVisage(1332);
+ scene->_gameBoardSide[2]._outpostStation[0]._card.setPosition(scene->_gameBoardSide[2]._outpostStation[0]._stationPos, 0);
+ scene->_gameBoardSide[2]._outpostStation[0]._card.setStrip(2);
+ scene->_gameBoardSide[2]._outpostStation[0]._card.setFrame(scene->_gameBoardSide[2]._outpostStation[0]._cardId);
+ scene->setAnimationInfo(&scene->_gameBoardSide[2]._outpostStation[0]);
+
+ scene->_gameBoardSide[3]._outpostStation[0]._cardId = 5;
+ scene->_gameBoardSide[3]._outpostStation[0]._card.postInit();
+ scene->_gameBoardSide[3]._outpostStation[0]._card.setVisage(1332);
+ scene->_gameBoardSide[3]._outpostStation[0]._card.setPosition(scene->_gameBoardSide[3]._outpostStation[0]._stationPos, 0);
+ scene->_gameBoardSide[3]._outpostStation[0]._card.setStrip(2);
+ scene->_gameBoardSide[3]._outpostStation[0]._card.setFrame(scene->_gameBoardSide[3]._outpostStation[0]._cardId);
+ scene->_gameBoardSide[3]._outpostStation[0]._card.fixPriority(170);
+ scene->setAnimationInfo(&scene->_gameBoardSide[3]._outpostStation[0]);
+
+ scene->_gameBoardSide[3]._outpostStation[1]._cardId = 6;
+ scene->_gameBoardSide[3]._outpostStation[1]._card.postInit();
+ scene->_gameBoardSide[3]._outpostStation[1]._card.setVisage(1332);
+ scene->_gameBoardSide[3]._outpostStation[1]._card.setPosition(scene->_gameBoardSide[3]._outpostStation[1]._stationPos, 0);
+ scene->_gameBoardSide[3]._outpostStation[1]._card.setStrip(2);
+ scene->_gameBoardSide[3]._outpostStation[1]._card.setFrame(scene->_gameBoardSide[3]._outpostStation[1]._cardId);
+ scene->_gameBoardSide[3]._outpostStation[1]._card.fixPriority(170);
+ scene->setAnimationInfo(&scene->_gameBoardSide[3]._outpostStation[1]);
+
+ scene->_gameBoardSide[3]._outpostStation[2]._cardId = 7;
+ scene->_gameBoardSide[3]._outpostStation[2]._card.postInit();
+ scene->_gameBoardSide[3]._outpostStation[2]._card.setVisage(1332);
+ scene->_gameBoardSide[3]._outpostStation[2]._card.setPosition(scene->_gameBoardSide[3]._outpostStation[2]._stationPos, 0);
+ scene->_gameBoardSide[3]._outpostStation[2]._card.setStrip(2);
+ scene->_gameBoardSide[3]._outpostStation[2]._card.setFrame(scene->_gameBoardSide[3]._outpostStation[2]._cardId);
+ scene->_gameBoardSide[3]._outpostStation[2]._card.fixPriority(170);
+ scene->setAnimationInfo(&scene->_gameBoardSide[3]._outpostStation[2]);
+
+ scene->_gameBoardSide[0]._outpostStation[0]._cardId = 8;
+ scene->_gameBoardSide[0]._outpostStation[0]._card.postInit();
+ scene->_gameBoardSide[0]._outpostStation[0]._card.setVisage(1332);
+ scene->_gameBoardSide[0]._outpostStation[0]._card.setPosition(scene->_gameBoardSide[0]._outpostStation[0]._stationPos, 0);
+ scene->_gameBoardSide[0]._outpostStation[0]._card.setStrip(2);
+ scene->_gameBoardSide[0]._outpostStation[0]._card.setFrame(scene->_gameBoardSide[0]._outpostStation[0]._cardId);
+ scene->_gameBoardSide[0]._outpostStation[0]._card.fixPriority(170);
+ scene->setAnimationInfo(&scene->_gameBoardSide[0]._outpostStation[0]);
+
+ scene->_gameBoardSide[0]._outpostStation[1]._cardId = 9;
+ scene->_gameBoardSide[0]._outpostStation[1]._card.postInit();
+ scene->_gameBoardSide[0]._outpostStation[1]._card.setVisage(1332);
+ scene->_gameBoardSide[0]._outpostStation[1]._card.setPosition(scene->_gameBoardSide[0]._outpostStation[1]._stationPos, 0);
+ scene->_gameBoardSide[0]._outpostStation[1]._card.setStrip(2);
+ scene->_gameBoardSide[0]._outpostStation[1]._card.setFrame(scene->_gameBoardSide[0]._outpostStation[1]._cardId);
+ scene->_gameBoardSide[0]._outpostStation[1]._card.fixPriority(170);
+ scene->setAnimationInfo(&scene->_gameBoardSide[0]._outpostStation[1]);
+
+ R2_GLOBALS._sceneObjects->draw();
+
+ waitFrames(60);
+ scene->actionDisplay(1331, 9, 159, 10, 1, 200, 0, 7, 0, 154, 154);
+
+ scene->_gameBoardSide[2]._outpostStation[1]._cardId = 2;
+ scene->_gameBoardSide[2]._outpostStation[1]._card.postInit();
+ scene->_gameBoardSide[2]._outpostStation[1]._card.setVisage(1332);
+ scene->_gameBoardSide[2]._outpostStation[1]._card.setPosition(scene->_gameBoardSide[2]._outpostStation[1]._stationPos, 0);
+ scene->_gameBoardSide[2]._outpostStation[1]._card.setStrip(2);
+ scene->_gameBoardSide[2]._outpostStation[1]._card.setFrame(scene->_gameBoardSide[2]._outpostStation[1]._cardId);
+ scene->_gameBoardSide[2]._outpostStation[1]._card.fixPriority(170);
+ scene->setAnimationInfo(&scene->_gameBoardSide[2]._outpostStation[1]);
+
+ scene->_gameBoardSide[2]._outpostStation[2]._cardId = 3;
+ scene->_gameBoardSide[2]._outpostStation[2]._card.postInit();
+ scene->_gameBoardSide[2]._outpostStation[2]._card.setVisage(1332);
+ scene->_gameBoardSide[2]._outpostStation[2]._card.setPosition(scene->_gameBoardSide[2]._outpostStation[2]._stationPos, 0);
+ scene->_gameBoardSide[2]._outpostStation[2]._card.setStrip(2);
+ scene->_gameBoardSide[2]._outpostStation[2]._card.setFrame(scene->_gameBoardSide[2]._outpostStation[2]._cardId);
+ scene->_gameBoardSide[2]._outpostStation[2]._card.fixPriority(170);
+ scene->setAnimationInfo(&scene->_gameBoardSide[2]._outpostStation[2]);
+
+ scene->_gameBoardSide[2]._outpostStation[3]._cardId = 5;
+ scene->_gameBoardSide[2]._outpostStation[3]._card.postInit();
+ scene->_gameBoardSide[2]._outpostStation[3]._card.setVisage(1332);
+ scene->_gameBoardSide[2]._outpostStation[3]._card.setPosition(scene->_gameBoardSide[2]._outpostStation[3]._stationPos, 0);
+ scene->_gameBoardSide[2]._outpostStation[3]._card.setStrip(2);
+ scene->_gameBoardSide[2]._outpostStation[3]._card.setFrame(scene->_gameBoardSide[2]._outpostStation[3]._cardId);
+ scene->_gameBoardSide[2]._outpostStation[3]._card.fixPriority(170);
+ scene->setAnimationInfo(&scene->_gameBoardSide[2]._outpostStation[3]);
+
+ scene->_gameBoardSide[2]._outpostStation[4]._cardId = 6;
+ scene->_gameBoardSide[2]._outpostStation[4]._card.postInit();
+ scene->_gameBoardSide[2]._outpostStation[4]._card.setVisage(1332);
+ scene->_gameBoardSide[2]._outpostStation[4]._card.setPosition(scene->_gameBoardSide[2]._outpostStation[4]._stationPos, 0);
+ scene->_gameBoardSide[2]._outpostStation[4]._card.setStrip(2);
+ scene->_gameBoardSide[2]._outpostStation[4]._card.setFrame(scene->_gameBoardSide[2]._outpostStation[4]._cardId);
+ scene->_gameBoardSide[2]._outpostStation[4]._card.fixPriority(170);
+ scene->setAnimationInfo(&scene->_gameBoardSide[2]._outpostStation[4]);
+
+ scene->_gameBoardSide[2]._outpostStation[5]._cardId = 7;
+ scene->_gameBoardSide[2]._outpostStation[5]._card.postInit();
+ scene->_gameBoardSide[2]._outpostStation[5]._card.setVisage(1332);
+ scene->_gameBoardSide[2]._outpostStation[5]._card.setPosition(scene->_gameBoardSide[2]._outpostStation[5]._stationPos, 0);
+ scene->_gameBoardSide[2]._outpostStation[5]._card.setStrip(2);
+ scene->_gameBoardSide[2]._outpostStation[5]._card.setFrame(scene->_gameBoardSide[2]._outpostStation[5]._cardId);
+ scene->_gameBoardSide[2]._outpostStation[5]._card.fixPriority(170);
+ scene->setAnimationInfo(&scene->_gameBoardSide[2]._outpostStation[5]);
+
+ scene->_gameBoardSide[2]._outpostStation[6]._cardId = 8;
+ scene->_gameBoardSide[2]._outpostStation[6]._card.postInit();
+ scene->_gameBoardSide[2]._outpostStation[6]._card.setVisage(1332);
+ scene->_gameBoardSide[2]._outpostStation[6]._card.setPosition(scene->_gameBoardSide[2]._outpostStation[6]._stationPos, 0);
+ scene->_gameBoardSide[2]._outpostStation[6]._card.setStrip(2);
+ scene->_gameBoardSide[2]._outpostStation[6]._card.setFrame(scene->_gameBoardSide[2]._outpostStation[6]._cardId);
+ scene->_gameBoardSide[2]._outpostStation[6]._card.fixPriority(170);
+ scene->setAnimationInfo(&scene->_gameBoardSide[2]._outpostStation[6]);
+
+ scene->_gameBoardSide[2]._outpostStation[7]._cardId = 9;
+ scene->_gameBoardSide[2]._outpostStation[7]._card.postInit();
+ scene->_gameBoardSide[2]._outpostStation[7]._card.setVisage(1332);
+ scene->_gameBoardSide[2]._outpostStation[7]._card.setPosition(scene->_gameBoardSide[2]._outpostStation[7]._stationPos, 0);
+ scene->_gameBoardSide[2]._outpostStation[7]._card.setStrip(2);
+ scene->_gameBoardSide[2]._outpostStation[7]._card.setFrame(scene->_gameBoardSide[2]._outpostStation[7]._cardId);
+ scene->_gameBoardSide[2]._outpostStation[7]._card.fixPriority(170);
+ scene->setAnimationInfo(&scene->_gameBoardSide[2]._outpostStation[7]);
+
+ scene->_aSound1.play(62);
+
+ R2_GLOBALS._sceneObjects->draw();
+
+ waitFrames(120);
+ scene->_gameBoardSide[2]._outpostStation[0]._card.remove();
+ scene->_gameBoardSide[2]._outpostStation[1]._card.remove();
+ scene->_gameBoardSide[2]._outpostStation[2]._card.remove();
+ scene->_gameBoardSide[2]._outpostStation[3]._card.remove();
+ scene->_gameBoardSide[2]._outpostStation[4]._card.remove();
+ scene->_gameBoardSide[2]._outpostStation[5]._card.remove();
+ scene->_gameBoardSide[2]._outpostStation[6]._card.remove();
+ scene->_gameBoardSide[2]._outpostStation[7]._card.remove();
+
+ scene->_gameBoardSide[1]._outpostStation[0]._card.remove();
+ scene->_gameBoardSide[1]._outpostStation[1]._card.remove();
+
+ scene->_gameBoardSide[3]._outpostStation[0]._card.remove();
+ scene->_gameBoardSide[3]._outpostStation[1]._card.remove();
+ scene->_gameBoardSide[3]._outpostStation[2]._card.remove();
+
+ scene->_gameBoardSide[0]._outpostStation[0]._card.remove();
+ scene->_gameBoardSide[0]._outpostStation[1]._card.remove();
+
+ scene->_stockPile.setup(1332, 5, 1);
+ scene->_stockPile.setPosition(Common::Point(162, 95));
+ scene->_stockPile.setPriority(110);
+ scene->_stockPile._effect = EFFECT_SHADED;
+ scene->_stockPile.show();
+
+ scene->_gameBoardSide[1]._handCard[0]._card.postInit();
+ scene->_gameBoardSide[1]._handCard[0]._card.setVisage(1332);
+ scene->_gameBoardSide[1]._handCard[0]._card.setPosition(scene->_gameBoardSide[1]._handCard[0]._stationPos, 0);
+ scene->_gameBoardSide[1]._handCard[0]._card.setStrip(1);
+ scene->_gameBoardSide[1]._handCard[0]._card.setFrame(4);
+ scene->_gameBoardSide[1]._handCard[0]._card.fixPriority(170);
+
+ scene->_gameBoardSide[1]._handCard[1]._card.postInit();
+ scene->_gameBoardSide[1]._handCard[1]._card.setVisage(1332);
+ scene->_gameBoardSide[1]._handCard[1]._card.setPosition(scene->_gameBoardSide[1]._handCard[1]._stationPos, 0);
+ scene->_gameBoardSide[1]._handCard[1]._card.setStrip(1);
+ scene->_gameBoardSide[1]._handCard[1]._card.setFrame(4);
+ scene->_gameBoardSide[1]._handCard[1]._card.fixPriority(170);
+
+ scene->_gameBoardSide[1]._handCard[2]._card.postInit();
+ scene->_gameBoardSide[1]._handCard[2]._card.setVisage(1332);
+ scene->_gameBoardSide[1]._handCard[2]._card.setPosition(scene->_gameBoardSide[1]._handCard[2]._stationPos, 0);
+ scene->_gameBoardSide[1]._handCard[2]._card.setStrip(1);
+ scene->_gameBoardSide[1]._handCard[2]._card.setFrame(4);
+ scene->_gameBoardSide[1]._handCard[2]._card.fixPriority(170);
+
+ scene->_gameBoardSide[2]._handCard[0]._cardId = 30;
+ scene->_gameBoardSide[2]._handCard[0]._card.postInit();
+ scene->_gameBoardSide[2]._handCard[0]._card.setVisage(1332);
+ scene->_gameBoardSide[2]._handCard[0]._card.setPosition(scene->_gameBoardSide[2]._handCard[0]._stationPos, 0);
+ scene->_gameBoardSide[2]._handCard[0]._card.setStrip(1);
+ scene->_gameBoardSide[2]._handCard[0]._card.setFrame(2);
+ scene->_gameBoardSide[2]._handCard[0]._card.fixPriority(170);
+ scene->setAnimationInfo(&scene->_gameBoardSide[2]._handCard[0]);
+
+ scene->_gameBoardSide[2]._handCard[1]._cardId = 16;
+ scene->_gameBoardSide[2]._handCard[1]._card.postInit();
+ scene->_gameBoardSide[2]._handCard[1]._card.setVisage(1332);
+ scene->_gameBoardSide[2]._handCard[1]._card.setPosition(scene->_gameBoardSide[2]._handCard[1]._stationPos, 0);
+ scene->_gameBoardSide[2]._handCard[1]._card.setStrip(1);
+ scene->_gameBoardSide[2]._handCard[1]._card.setFrame(2);
+ scene->_gameBoardSide[2]._handCard[1]._card.fixPriority(170);
+ scene->setAnimationInfo(&scene->_gameBoardSide[2]._handCard[1]);
+
+ scene->_gameBoardSide[2]._handCard[2]._cardId = 1;
+ scene->_gameBoardSide[2]._handCard[2]._card.postInit();
+ scene->_gameBoardSide[2]._handCard[2]._card.setVisage(1332);
+ scene->_gameBoardSide[2]._handCard[2]._card.setPosition(scene->_gameBoardSide[2]._handCard[2]._stationPos, 0);
+ scene->_gameBoardSide[2]._handCard[2]._card.setStrip(1);
+ scene->_gameBoardSide[2]._handCard[2]._card.setFrame(2);
+ scene->_gameBoardSide[2]._handCard[2]._card.fixPriority(170);
+ scene->setAnimationInfo(&scene->_gameBoardSide[2]._handCard[2]);
+
+ scene->_gameBoardSide[3]._handCard[0]._card.postInit();
+ scene->_gameBoardSide[3]._handCard[0]._card.setVisage(1332);
+ scene->_gameBoardSide[3]._handCard[0]._card.setPosition(scene->_gameBoardSide[3]._handCard[0]._stationPos, 0);
+ scene->_gameBoardSide[3]._handCard[0]._card.setStrip(1);
+ scene->_gameBoardSide[3]._handCard[0]._card.setFrame(3);
+ scene->_gameBoardSide[3]._handCard[0]._card.fixPriority(170);
+
+ scene->_gameBoardSide[3]._handCard[1]._card.postInit();
+ scene->_gameBoardSide[3]._handCard[1]._card.setVisage(1332);
+ scene->_gameBoardSide[3]._handCard[1]._card.setPosition(scene->_gameBoardSide[3]._handCard[1]._stationPos, 0);
+ scene->_gameBoardSide[3]._handCard[1]._card.setStrip(1);
+ scene->_gameBoardSide[3]._handCard[1]._card.setFrame(3);
+ scene->_gameBoardSide[3]._handCard[1]._card.fixPriority(170);
+
+ scene->_gameBoardSide[3]._handCard[2]._card.postInit();
+ scene->_gameBoardSide[3]._handCard[2]._card.setVisage(1332);
+ scene->_gameBoardSide[3]._handCard[2]._card.setPosition(scene->_gameBoardSide[3]._handCard[2]._stationPos, 0);
+ scene->_gameBoardSide[3]._handCard[2]._card.setStrip(1);
+ scene->_gameBoardSide[3]._handCard[2]._card.setFrame(3);
+ scene->_gameBoardSide[3]._handCard[2]._card.fixPriority(170);
+
+ scene->_gameBoardSide[0]._handCard[0]._card.postInit();
+ scene->_gameBoardSide[0]._handCard[0]._card.setVisage(1332);
+ scene->_gameBoardSide[0]._handCard[0]._card.setPosition(scene->_gameBoardSide[0]._handCard[0]._stationPos, 0);
+ scene->_gameBoardSide[0]._handCard[0]._card.setStrip(1);
+ scene->_gameBoardSide[0]._handCard[0]._card.setFrame(2);
+ scene->_gameBoardSide[0]._handCard[0]._card.fixPriority(170);
+
+ scene->_gameBoardSide[0]._handCard[1]._card.postInit();
+ scene->_gameBoardSide[0]._handCard[1]._card.setVisage(1332);
+ scene->_gameBoardSide[0]._handCard[1]._card.setPosition(scene->_gameBoardSide[0]._handCard[1]._stationPos, 0);
+ scene->_gameBoardSide[0]._handCard[1]._card.setStrip(1);
+ scene->_gameBoardSide[0]._handCard[1]._card.setFrame(2);
+ scene->_gameBoardSide[0]._handCard[1]._card.fixPriority(170);
+
+ scene->_gameBoardSide[0]._handCard[2]._card.postInit();
+ scene->_gameBoardSide[0]._handCard[2]._card.setVisage(1332);
+ scene->_gameBoardSide[0]._handCard[2]._card.setPosition(scene->_gameBoardSide[0]._handCard[2]._stationPos, 0);
+ scene->_gameBoardSide[0]._handCard[2]._card.setStrip(1);
+ scene->_gameBoardSide[0]._handCard[2]._card.setFrame(2);
+ scene->_gameBoardSide[0]._handCard[2]._card.fixPriority(170);
+
+ R2_GLOBALS._sceneObjects->draw();
+
+ scene->actionDisplay(1331, 10, 159, 10, 1, 200, 0, 7, 0, 154, 154);
+ scene->_animatedCard._card.setPosition(Common::Point(162, 95), 0);
+ scene->_animatedCard._card.show();
+ scene->_aSound2.play(61);
+
+ Common::Point pt(91, 174);
+ NpcMover *mover = new NpcMover();
+ scene->_animatedCard._card.addMover(mover, &pt, this);
+ }
+ break;
+ case 2: {
+ scene->_gameBoardSide[2]._handCard[3]._cardId = 2;
+ scene->_gameBoardSide[2]._handCard[3]._card.postInit();
+ scene->_gameBoardSide[2]._handCard[3]._card.setVisage(1332);
+ scene->_gameBoardSide[2]._handCard[3]._card.setPosition(scene->_gameBoardSide[2]._handCard[3]._stationPos, 0);
+ scene->_gameBoardSide[2]._handCard[3]._card.setStrip(1);
+ scene->_gameBoardSide[2]._handCard[3]._card.setFrame(2);
+ scene->_gameBoardSide[2]._handCard[3]._card.fixPriority(170);
+
+ scene->_animatedCard._card.hide();
+ scene->setAnimationInfo(&scene->_gameBoardSide[2]._handCard[3]);
+
+ R2_GLOBALS._sceneObjects->draw();
+
+ waitFrames(60);
+ scene->actionDisplay(1331, 11, 159, 10, 1, 200, 0, 7, 0, 154, 154);
+ scene->actionDisplay(1331, 12, 159, 10, 1, 200, 0, 7, 0, 154, 154);
+
+ scene->_gameBoardSide[2]._outpostStation[1]._cardId = 1;
+ scene->_gameBoardSide[2]._outpostStation[1]._card.postInit();
+ scene->_gameBoardSide[2]._outpostStation[1]._card.setVisage(1332);
+ scene->_gameBoardSide[2]._outpostStation[1]._card.setPosition(scene->_gameBoardSide[2]._outpostStation[1]._stationPos, 0);
+ scene->_gameBoardSide[2]._outpostStation[1]._card.hide();
+
+ scene->_animatedCard._card.setStrip(scene->_gameBoardSide[2]._handCard[2]._card._strip);
+ scene->_animatedCard._card.setFrame(scene->_gameBoardSide[2]._handCard[2]._card._frame);
+ scene->_animatedCard._card.animate(ANIM_MODE_NONE, NULL);
+
+ scene->_gameBoardSide[2]._handCard[2]._cardId = 0;
+ scene->_gameBoardSide[2]._handCard[2]._card.remove();
+
+ scene->_animatedCard._card.setPosition(scene->_gameBoardSide[2]._handCard[2]._stationPos, 0);
+ scene->_animatedCard._card.show();
+
+ NpcMover *mover = new NpcMover();
+ scene->_animatedCard._card.addMover(mover, &scene->_gameBoardSide[2]._outpostStation[1]._stationPos, this);
+ }
+ break;
+ case 3: {
+ scene->_animatedCard._card.hide();
+ scene->setAnimationInfo(&scene->_gameBoardSide[2]._outpostStation[1]);
+ scene->_aSound1.play(59);
+
+ R2_GLOBALS._sceneObjects->draw();
+
+ waitFrames(60);
+ scene->actionDisplay(1331, 13, 159, 10, 1, 200, 0, 7, 0, 154, 154);
+
+ scene->_gameBoardSide[2]._outpostStation[1]._cardId = scene->_gameBoardSide[2]._handCard[3]._cardId;
+
+ scene->_animatedCard._card.setStrip(scene->_gameBoardSide[2]._handCard[3]._card._strip);
+ scene->_animatedCard._card.setFrame(scene->_gameBoardSide[2]._handCard[3]._card._frame);
+
+ scene->_gameBoardSide[2]._handCard[3]._cardId = 0;
+ scene->_gameBoardSide[2]._handCard[3]._card.remove();
+
+ scene->_animatedCard._card.setPosition(scene->_gameBoardSide[2]._handCard[3]._stationPos, 0);
+ scene->_animatedCard._card.show();
+
+ NpcMover *mover = new NpcMover();
+ scene->_animatedCard._card.addMover(mover, &scene->_gameBoardSide[2]._outpostStation[1]._stationPos, this);
+ }
+ break;
+ case 4: {
+ scene->_animatedCard._card.hide();
+ scene->setAnimationInfo(&scene->_gameBoardSide[2]._outpostStation[1]);
+ scene->_aSound1.play(59);
+
+ scene->_discardPile._cardId = 1;
+ scene->_discardPile._card.hide();
+
+ scene->_animatedCard._card.setStrip(5);
+ scene->_animatedCard._card.setFrame(1);
+ scene->_animatedCard._card.animate(ANIM_MODE_2, NULL);
+ scene->_animatedCard._card.setPosition(scene->_gameBoardSide[2]._outpostStation[1]._stationPos, 0);
+ scene->_animatedCard._card.show();
+
+ NpcMover *mover = new NpcMover();
+ scene->_animatedCard._card.addMover(mover, &scene->_discardPile._stationPos, this);
+ }
+ break;
+ case 5: {
+ scene->_animatedCard._card.hide();
+
+ scene->_discardPile._card.postInit();
+ scene->_discardPile._card.setVisage(1332);
+ scene->_discardPile._card.setPosition(scene->_discardPile._stationPos, 0);
+ scene->setAnimationInfo(&scene->_discardPile);
+ scene->_aSound2.play(61);
+
+ R2_GLOBALS._sceneObjects->draw();
+
+ waitFrames(60);
+ scene->actionDisplay(1331, 14, 159, 10, 1, 200, 0, 7, 0, 154, 154);
+
+ scene->_gameBoardSide[2]._delayCard._card.postInit();
+ scene->_gameBoardSide[2]._delayCard._card.setVisage(1332);
+ scene->_gameBoardSide[2]._delayCard._card.setPosition(scene->_gameBoardSide[2]._delayCard._stationPos, 0);
+ scene->_gameBoardSide[2]._delayCard._card.hide();
+
+ scene->_gameBoardSide[3]._handCard[2]._cardId = 0;
+ scene->_gameBoardSide[3]._handCard[2].remove();
+
+ scene->_animatedCard._card.setPosition(scene->_gameBoardSide[3]._handCard[2]._stationPos, 0);
+ scene->_animatedCard._card.show();
+
+ NpcMover *mover = new NpcMover();
+ scene->_animatedCard._card.addMover(mover, &scene->_gameBoardSide[2]._delayCard._stationPos, this);
+ }
+ break;
+ case 6: {
+ scene->_animatedCard._card.hide();
+ scene->_gameBoardSide[2]._delayCard._cardId = 21;
+ scene->setAnimationInfo(&scene->_gameBoardSide[2]._delayCard);
+ scene->_aSound1.play(57);
+
+ R2_GLOBALS._sceneObjects->draw();
+
+ waitFrames(60);
+ scene->actionDisplay(1331, 15, 159, 10, 1, 200, 0, 7, 0, 154, 154);
+
+ int tmpVal = 15;
+ int i = -1;
+
+ for (i = 0; i <= 7; i++) {
+ tmpVal += 29;
+
+ scene->_upperDisplayCard[i].postInit();
+ scene->_upperDisplayCard[i].setVisage(1332);
+ scene->_upperDisplayCard[i].setPosition(Common::Point(tmpVal, 90), 0);
+ scene->_upperDisplayCard[i].setStrip(3);
+ scene->_upperDisplayCard[i].fixPriority(190);
+
+ scene->_lowerDisplayCard[i].postInit();
+ scene->_lowerDisplayCard[i].setVisage(1332);
+ scene->_lowerDisplayCard[i].setPosition(Common::Point(tmpVal, 90), 0);
+ scene->_lowerDisplayCard[i].setStrip(7);
+ scene->_lowerDisplayCard[i].setFrame(1);
+ scene->_lowerDisplayCard[i].fixPriority(180);
+ }
+
+ scene->_upperDisplayCard[0].setFrame(1);
+ scene->_upperDisplayCard[1].setFrame(3);
+ scene->_upperDisplayCard[2].setFrame(6);
+ scene->_upperDisplayCard[3].setFrame(8);
+ scene->_upperDisplayCard[4].setFrame(9);
+ scene->_upperDisplayCard[5].setFrame(10);
+ scene->_upperDisplayCard[6].setFrame(11);
+ scene->_upperDisplayCard[7].setFrame(12);
+
+ R2_GLOBALS._sceneObjects->draw();
+
+ waitFrames(240);
+
+ scene->_upperDisplayCard[0].remove();
+ scene->_upperDisplayCard[1].remove();
+ scene->_upperDisplayCard[2].remove();
+ scene->_upperDisplayCard[3].remove();
+ scene->_upperDisplayCard[4].remove();
+ scene->_upperDisplayCard[5].remove();
+ scene->_upperDisplayCard[6].remove();
+ scene->_upperDisplayCard[7].remove();
+
+ scene->_lowerDisplayCard[0].remove();
+ scene->_lowerDisplayCard[1].remove();
+ scene->_lowerDisplayCard[2].remove();
+ scene->_lowerDisplayCard[3].remove();
+ scene->_lowerDisplayCard[4].remove();
+ scene->_lowerDisplayCard[5].remove();
+ scene->_lowerDisplayCard[6].remove();
+ scene->_lowerDisplayCard[7].remove();
+
+ scene->_discardPile._cardId = scene->_gameBoardSide[2]._delayCard._cardId;
+
+ scene->_gameBoardSide[2]._delayCard._cardId = 0;
+ scene->_gameBoardSide[2]._delayCard._card.remove();
+
+ scene->_animatedCard._card.setPosition(scene->_gameBoardSide[2]._delayCard._stationPos, 0);
+ scene->_animatedCard._card.show();
+
+ NpcMover *mover = new NpcMover();
+ scene->_animatedCard._card.addMover(mover, &scene->_discardPile._stationPos, this);
+ }
+ break;
+ case 7: {
+ scene->_animatedCard._card.hide();
+ scene->setAnimationInfo(&scene->_discardPile);
+ scene->_aSound2.play(61);
+
+ R2_GLOBALS._sceneObjects->draw();
+
+ scene->_gameBoardSide[2]._delayCard._card.postInit();
+ scene->_gameBoardSide[2]._delayCard._card.setVisage(1332);
+ scene->_gameBoardSide[2]._delayCard._card.setPosition(scene->_gameBoardSide[2]._delayCard._stationPos, 0);
+ scene->_gameBoardSide[2]._delayCard._card.hide();
+
+ scene->_gameBoardSide[3]._handCard[1]._cardId = 0;
+ scene->_gameBoardSide[3]._handCard[1].remove();
+
+ scene->_animatedCard._card.setPosition(scene->_gameBoardSide[3]._handCard[1]._stationPos, 0);
+ scene->_animatedCard._card.show();
+
+ NpcMover *mover = new NpcMover();
+ scene->_animatedCard._card.addMover(mover, &scene->_gameBoardSide[2]._delayCard._stationPos, this);
+ }
+ break;
+ case 8: {
+ scene->_animatedCard._card.hide();
+ scene->_gameBoardSide[2]._delayCard._cardId = 14;
+ scene->setAnimationInfo(&scene->_gameBoardSide[2]._delayCard);
+ scene->_aSound1.play(57);
+
+ R2_GLOBALS._sceneObjects->draw();
+
+ scene->actionDisplay(1331, 16, 159, 10, 1, 200, 0, 7, 0, 154, 154);
+ int tmpVal = 72;
+ int i = -1;
+
+ for (i = 0; i <= 3; i++) {
+ tmpVal += 29;
+ scene->_upperDisplayCard[i].postInit();
+ scene->_upperDisplayCard[i].setVisage(1332);
+ scene->_upperDisplayCard[i].setPosition(Common::Point(tmpVal, 71), 0);
+ scene->_upperDisplayCard[i].setStrip(3);
+ scene->_upperDisplayCard[i].fixPriority(190);
+
+ scene->_lowerDisplayCard[i].postInit();
+ scene->_lowerDisplayCard[i].setVisage(1332);
+ scene->_lowerDisplayCard[i].setPosition(Common::Point(tmpVal, 71), 0);
+ scene->_lowerDisplayCard[i].setStrip(7);
+ scene->_lowerDisplayCard[i].setFrame(1);
+ scene->_lowerDisplayCard[i].fixPriority(180);
+ }
+
+ scene->_upperDisplayCard[0].setFrame(2);
+ scene->_upperDisplayCard[1].setFrame(5);
+ scene->_upperDisplayCard[2].setFrame(7);
+ scene->_upperDisplayCard[3].setFrame(15);
+
+ R2_GLOBALS._sceneObjects->draw();
+
+ waitFrames(240);
+ scene->actionDisplay(1331, 17, 159, 10, 1, 200, 0, 7, 0, 154, 154);
+
+ tmpVal = 72;
+ for (i = 4; i <= 7; i++) {
+ tmpVal += 29;
+
+ scene->_upperDisplayCard[i].postInit();
+ scene->_upperDisplayCard[i].setVisage(1332);
+ scene->_upperDisplayCard[i].setPosition(Common::Point(tmpVal, 100), 0);
+ scene->_upperDisplayCard[i].setStrip(4);
+ scene->_upperDisplayCard[i].fixPriority(190);
+
+ scene->_lowerDisplayCard[i].postInit();
+ scene->_lowerDisplayCard[i].setVisage(1332);
+ scene->_lowerDisplayCard[i].setPosition(Common::Point(tmpVal, 100), 0);
+ scene->_lowerDisplayCard[i].setStrip(7);
+ scene->_lowerDisplayCard[i].setFrame(1);
+ scene->_lowerDisplayCard[i].fixPriority(180);
+ }
+
+ scene->_upperDisplayCard[4].setFrame(1);
+ scene->_upperDisplayCard[5].setFrame(5);
+ scene->_upperDisplayCard[6].setFrame(7);
+ scene->_upperDisplayCard[7].setFrame(3);
+
+ R2_GLOBALS._sceneObjects->draw();
+
+ waitFrames(240);
+
+ scene->_upperDisplayCard[0].remove();
+ scene->_upperDisplayCard[1].remove();
+ scene->_upperDisplayCard[2].remove();
+ scene->_upperDisplayCard[3].remove();
+ scene->_upperDisplayCard[4].remove();
+ scene->_upperDisplayCard[5].remove();
+ scene->_upperDisplayCard[6].remove();
+ scene->_upperDisplayCard[7].remove();
+
+ scene->_lowerDisplayCard[0].remove();
+ scene->_lowerDisplayCard[1].remove();
+ scene->_lowerDisplayCard[2].remove();
+ scene->_lowerDisplayCard[3].remove();
+ scene->_lowerDisplayCard[4].remove();
+ scene->_lowerDisplayCard[5].remove();
+ scene->_lowerDisplayCard[6].remove();
+ scene->_lowerDisplayCard[7].remove();
+
+ scene->_discardPile._cardId = scene->_gameBoardSide[2]._handCard[0]._cardId;
+
+ scene->_animatedCard._card.setStrip(scene->_gameBoardSide[2]._handCard[0]._card._strip);
+ scene->_animatedCard._card.setFrame(scene->_gameBoardSide[2]._handCard[0]._card._frame);
+ scene->_animatedCard._card.animate(ANIM_MODE_NONE, NULL);
+
+ scene->_gameBoardSide[2]._handCard[0]._cardId = 0;
+ scene->_gameBoardSide[2]._handCard[0]._card.remove();
+
+ scene->_animatedCard._card.setPosition(scene->_gameBoardSide[2]._handCard[0]._stationPos, 0);
+ scene->_animatedCard._card.show();
+
+ NpcMover *mover = new NpcMover();
+ scene->_animatedCard._card.addMover(mover, &scene->_gameBoardSide[2]._delayCard._stationPos, this);
+ }
+ break;
+ case 9: {
+ scene->_aSound1.play(58);
+ scene->_gameBoardSide[2]._delayCard._cardId = 0;
+ scene->_gameBoardSide[2]._delayCard.remove();
+ scene->_animatedCard._card.setStrip(5);
+ scene->_animatedCard._card.setFrame(1);
+ scene->_animatedCard._card.animate(ANIM_MODE_2, NULL);
+ scene->_animatedCard._card.setPosition(scene->_gameBoardSide[2]._delayCard._stationPos, 0);
+ scene->_animatedCard._card.show();
+
+ NpcMover *mover = new NpcMover();
+ scene->_animatedCard._card.addMover(mover, &scene->_discardPile._stationPos, this);
+ }
+ break;
+ case 10: {
+ scene->_animatedCard._card.hide();
+ scene->setAnimationInfo(&scene->_discardPile);
+ scene->_aSound2.play(61);
+
+ R2_GLOBALS._sceneObjects->draw();
+ scene->actionDisplay(1331, 18, 159, 10, 1, 200, 0, 7, 0, 154, 154);
+
+ scene->_upperDisplayCard[0].postInit();
+ scene->_upperDisplayCard[0].setVisage(1332);
+ scene->_upperDisplayCard[0].setPosition(Common::Point(131, 71), 0);
+ scene->_upperDisplayCard[0].fixPriority(190);
+ scene->_upperDisplayCard[0].setStrip(3);
+ scene->_upperDisplayCard[0].setFrame(4);
+
+ scene->_lowerDisplayCard[0].postInit();
+ scene->_lowerDisplayCard[0].setVisage(1332);
+ scene->_lowerDisplayCard[0].setPosition(Common::Point(131, 71), 0);
+ scene->_lowerDisplayCard[0].setStrip(7);
+ scene->_lowerDisplayCard[0].setFrame(1);
+ scene->_lowerDisplayCard[0].fixPriority(180);
+
+ scene->_upperDisplayCard[1].postInit();
+ scene->_upperDisplayCard[1].setVisage(1332);
+ scene->_upperDisplayCard[1].setPosition(Common::Point(160, 71), 0);
+ scene->_upperDisplayCard[1].fixPriority(190);
+ scene->_upperDisplayCard[1].setStrip(3);
+ scene->_upperDisplayCard[1].setFrame(16);
+
+ scene->_lowerDisplayCard[1].postInit();
+ scene->_lowerDisplayCard[1].setVisage(1332);
+ scene->_lowerDisplayCard[1].setPosition(Common::Point(160, 71), 0);
+ scene->_lowerDisplayCard[1].setStrip(7);
+ scene->_lowerDisplayCard[1].setFrame(1);
+ scene->_lowerDisplayCard[1].fixPriority(180);
+
+ scene->_upperDisplayCard[2].postInit();
+ scene->_upperDisplayCard[2].setVisage(1332);
+ scene->_upperDisplayCard[2].setPosition(Common::Point(131, 100), 0);
+ scene->_upperDisplayCard[2].fixPriority(190);
+ scene->_upperDisplayCard[2].setStrip(4);
+ scene->_upperDisplayCard[2].setFrame(4);
+
+ scene->_lowerDisplayCard[2].postInit();
+ scene->_lowerDisplayCard[2].setVisage(1332);
+ scene->_lowerDisplayCard[2].setPosition(Common::Point(131, 100), 0);
+ scene->_lowerDisplayCard[2].setStrip(7);
+ scene->_lowerDisplayCard[2].setFrame(1);
+ scene->_lowerDisplayCard[2].fixPriority(180);
+
+ scene->_upperDisplayCard[3].postInit();
+ scene->_upperDisplayCard[3].setVisage(1332);
+ scene->_upperDisplayCard[3].setPosition(Common::Point(160, 100), 0);
+ scene->_upperDisplayCard[3].fixPriority(190);
+ scene->_upperDisplayCard[3].setStrip(4);
+ scene->_upperDisplayCard[3].setFrame(2);
+
+ scene->_lowerDisplayCard[3].postInit();
+ scene->_lowerDisplayCard[3].setVisage(1332);
+ scene->_lowerDisplayCard[3].setPosition(Common::Point(160, 100), 0);
+ scene->_lowerDisplayCard[3].setStrip(7);
+ scene->_lowerDisplayCard[3].setFrame(1);
+ scene->_lowerDisplayCard[3].fixPriority(180);
+
+ R2_GLOBALS._sceneObjects->draw();
+
+ waitFrames(240);
+
+ scene->_upperDisplayCard[0].remove();
+ scene->_upperDisplayCard[1].remove();
+ scene->_upperDisplayCard[2].remove();
+ scene->_upperDisplayCard[3].remove();
+
+ scene->_lowerDisplayCard[0].remove();
+ scene->_lowerDisplayCard[1].remove();
+ scene->_lowerDisplayCard[2].remove();
+ scene->_lowerDisplayCard[3].remove();
+
+ scene->_currentPlayerArrow.setFrame(1);
+ scene->_currentPlayerArrow.show();
+ scene->_currentPlayerArrow.animate(ANIM_MODE_2, NULL);
+
+ R2_GLOBALS._sceneObjects->draw();
+
+ scene->actionDisplay(1331, 19, 159, 10, 1, 220, 0, 7, 0, 154, 154);
+
+ scene->_currentPlayerArrow.hide();
+
+ scene->actionDisplay(1331, 20, 159, 10, 1, 220, 0, 7, 0, 154, 154);
+ scene->actionDisplay(1331, 21, 159, 10, 1, 220, 0, 7, 0, 154, 154);
+
+ scene->_discardPile._cardId = scene->_gameBoardSide[2]._handCard[1]._cardId;
+
+ scene->_animatedCard._card.setStrip(scene->_gameBoardSide[2]._handCard[1]._card._strip);
+ scene->_animatedCard._card.setFrame(scene->_gameBoardSide[2]._handCard[1]._card._frame);
+ scene->_animatedCard._card.animate(ANIM_MODE_NONE, NULL);
+
+ scene->_gameBoardSide[2]._handCard[1]._cardId = 0;
+ scene->_gameBoardSide[2]._handCard[1]._card.remove();
+
+ scene->_animatedCard._card.setPosition(scene->_gameBoardSide[2]._handCard[1]._stationPos, 0);
+ scene->_animatedCard._card.show();
+
+ NpcMover *mover = new NpcMover();
+ scene->_animatedCard._card.addMover(mover, &scene->_discardPile._stationPos, this);
+ }
+ break;
+ case 11: {
+ scene->_animatedCard._card.hide();
+ scene->setAnimationInfo(&scene->_discardPile);
+ scene->_aSound2.play(61);
+ scene->_animatedCard._card.setStrip(5);
+ scene->_animatedCard._card.setFrame(1);
+ scene->_animatedCard._card.animate(ANIM_MODE_2, NULL);
+
+ R2_GLOBALS._sceneObjects->draw();
+
+ scene->actionDisplay(1331, 22, 159, 10, 1, 200, 0, 7, 0, 154, 154);
+
+ int i = -1;
+ for (i = 0; i <= 3; i ++) {
+ scene->_gameBoardSide[3]._handCard[i]._cardId = 0;
+ scene->_gameBoardSide[3]._handCard[i]._card.remove();
+
+ scene->_gameBoardSide[2]._handCard[i]._cardId = 0;
+ scene->_gameBoardSide[2]._handCard[i]._card.remove();
+
+ scene->_gameBoardSide[0]._handCard[i]._cardId = 0;
+ scene->_gameBoardSide[0]._handCard[i]._card.remove();
+
+ scene->_gameBoardSide[1]._handCard[i]._cardId = 0;
+ scene->_gameBoardSide[1]._handCard[i]._card.remove();
+ }
+
+ for (i = 0; i <= 7; i++) {
+ scene->_gameBoardSide[3]._outpostStation[i]._cardId = 0;
+ scene->_gameBoardSide[3]._outpostStation[i]._card.remove();
+
+ scene->_gameBoardSide[2]._outpostStation[i]._cardId = 0;
+ scene->_gameBoardSide[2]._outpostStation[i]._card.remove();
+
+ scene->_gameBoardSide[0]._outpostStation[i]._cardId = 0;
+ scene->_gameBoardSide[0]._outpostStation[i]._card.remove();
+
+ scene->_gameBoardSide[1]._outpostStation[i]._cardId = 0;
+ scene->_gameBoardSide[1]._outpostStation[i]._card.remove();
+ }
+
+ scene->_gameBoardSide[2]._delayCard._cardId = 0;
+ scene->_gameBoardSide[2]._delayCard._card.remove();
+
+ scene->_discardPile._cardId = 0;
+ scene->_discardPile._card.remove();
+
+ scene->_stockPile.remove();
+ }
+ // No break on purpose
+ case 0:
+ R2_GLOBALS._sceneObjects->draw();
+ signal();
+ break;
+ case 12:
+ scene->suggestInstructions();
+ remove();
+ break;
+ default:
+ break;
+ }
+}
+
+/**
+ * Shuffle cards animation
+ */
+void Scene1337::Action2::signal() {
+ Scene1337 *scene = (Scene1337 *)R2_GLOBALS._sceneManager._scene;
+
+ switch (_actionIndex++) {
+ case 0:
+ scene->_shuffleAnimation._card.postInit();
+ scene->_shuffleAnimation._card.setVisage(1332);
+ scene->_shuffleAnimation._card.setStrip(8);
+ scene->_shuffleAnimation._card.setFrame(1);
+ scene->_shuffleAnimation._card.fixPriority(300);
+ scene->_shuffleAnimation._card.setPosition(Common::Point(156, 108));
+
+ scene->_discardPile._card.remove();
+ scene->_discardPile._cardId = 0;
+
+ scene->_aSound1.play(60);
+ scene->_shuffleAnimation._card.animate(ANIM_MODE_5, this);
+ break;
+ case 1:
+ scene->_shuffleAnimation._card.setFrame(1);
+
+ scene->_aSound1.play(60);
+ scene->_shuffleAnimation._card.animate(ANIM_MODE_5, this);
+ break;
+ case 2: {
+ Common::Point pt(156, 108);
+ NpcMover *mover = new NpcMover();
+ scene->_shuffleAnimation._card.addMover(mover, &pt, this);
+ }
+ break;
+ case 3:
+ scene->_shuffleAnimation._card.remove();
+ scene->_stockPile.setup(1332, 5, 1);
+ scene->_stockPile.setPosition(Common::Point(162, 95));
+ scene->_stockPile.setPriority(110);
+ scene->_stockPile._effect = EFFECT_SHADED;
+ scene->_stockPile.show();
+ scene->_shuffleEndedFl = true;
+ break;
+ default:
+ break;
+ }
+}
+
+/**
+ * Deal cards
+ */
+void Scene1337::Action3::signal() {
+ Scene1337 *scene = (Scene1337 *)R2_GLOBALS._sceneManager._scene;
+
+ scene->_animatedCard._card.setPosition(Common::Point(162, 95), 0);
+
+ switch (_actionIndex++) {
+ case 0: {
+ scene->_animatedCard._card._moveDiff = Common::Point(30, 30);
+ scene->_animatedCard._card.setVisage(1332);
+ scene->_animatedCard._card.setStrip(5);
+ scene->_animatedCard._card.setFrame(1);
+ scene->_animatedCard._card.fixPriority(400);
+ scene->_animatedCard._card.animate(ANIM_MODE_2, NULL);
+ scene->_aSound2.play(61);
+
+ Common::Point pt(283, 146);
+ NpcMover *mover = new NpcMover();
+ scene->_animatedCard._card.addMover(mover, &pt, this);
+
+ scene->_animatedCard._card.show();
+ scene->_gameBoardSide[1]._handCard[0]._cardId = scene->_availableCardsPile[scene->_cardsAvailableNumb];
+ }
+ break;
+ case 1: {
+ scene->_gameBoardSide[1]._handCard[0]._card.postInit();
+ scene->_gameBoardSide[1]._handCard[0]._card._moveDiff = Common::Point(30, 30);
+ scene->_gameBoardSide[1]._handCard[0]._card.setVisage(1332);
+ scene->_gameBoardSide[1]._handCard[0]._card.setPosition(scene->_gameBoardSide[1]._handCard[0]._stationPos, 0);
+ scene->_gameBoardSide[1]._handCard[0]._card.setStrip(1);
+ scene->_gameBoardSide[1]._handCard[0]._card.setFrame(4);
+ scene->_gameBoardSide[1]._handCard[0]._card.fixPriority(170);
+ scene->_aSound2.play(61);
+
+ Common::Point pt(10, 174);
+ NpcMover *mover = new NpcMover();
+ scene->_animatedCard._card.addMover(mover, &pt, this);
+
+ scene->_gameBoardSide[2]._handCard[0]._cardId = scene->_availableCardsPile[scene->_cardsAvailableNumb];
+ }
+ break;
+ case 2: {
+ scene->_gameBoardSide[2]._handCard[0]._card.postInit();
+ scene->_gameBoardSide[2]._handCard[0]._card._moveDiff = Common::Point(30, 30);
+ scene->_gameBoardSide[2]._handCard[0]._card.setVisage(1332);
+ scene->_gameBoardSide[2]._handCard[0]._card.setPosition(scene->_gameBoardSide[2]._handCard[0]._stationPos, 0);
+ scene->_gameBoardSide[2]._handCard[0]._card.fixPriority(170);
+ if (scene->_gameBoardSide[2]._handCard[0]._cardId > 25) {
+ scene->_gameBoardSide[2]._handCard[0]._card.setStrip(4);
+ scene->_gameBoardSide[2]._handCard[0]._card.setFrame(scene->_gameBoardSide[2]._handCard[0]._cardId - 25);
+ } else if (scene->_gameBoardSide[2]._handCard[0]._cardId > 9) {
+ scene->_gameBoardSide[2]._handCard[0]._card.setStrip(3);
+ scene->_gameBoardSide[2]._handCard[0]._card.setFrame(scene->_gameBoardSide[2]._handCard[0]._cardId - 9);
+ } else {
+ scene->_gameBoardSide[2]._handCard[0]._card.setStrip(2);
+ scene->_gameBoardSide[2]._handCard[0]._card.setFrame(scene->_gameBoardSide[2]._handCard[0]._cardId);
+ }
+ scene->_aSound2.play(61);
+
+ Common::Point pt(14, 14);
+ NpcMover *mover = new NpcMover();
+ scene->_animatedCard._card.addMover(mover, &pt, this);
+
+ scene->_gameBoardSide[3]._handCard[0]._cardId = scene->_availableCardsPile[scene->_cardsAvailableNumb];
+ }
+ break;
+ case 3: {
+ scene->_gameBoardSide[3]._handCard[0]._card.postInit();
+ scene->_gameBoardSide[3]._handCard[0]._card._moveDiff = Common::Point(30, 30);
+ scene->_gameBoardSide[3]._handCard[0]._card.setVisage(1332);
+ scene->_gameBoardSide[3]._handCard[0]._card.setPosition(scene->_gameBoardSide[3]._handCard[0]._stationPos, 0);
+ scene->_gameBoardSide[3]._handCard[0]._card.setStrip(1);
+ scene->_gameBoardSide[3]._handCard[0]._card.setFrame(3);
+ scene->_gameBoardSide[3]._handCard[0]._card.fixPriority(170);
+ scene->_aSound2.play(61);
+
+ Common::Point pt(280, 5);
+ NpcMover *mover = new NpcMover();
+ scene->_animatedCard._card.addMover(mover, &pt, this);
+
+ scene->_gameBoardSide[0]._handCard[0]._cardId = scene->_availableCardsPile[scene->_cardsAvailableNumb];
+ }
+ break;
+ case 4: {
+ scene->_gameBoardSide[0]._handCard[0]._card.postInit();
+ scene->_gameBoardSide[0]._handCard[0]._card._moveDiff = Common::Point(30,30);
+ scene->_gameBoardSide[0]._handCard[0]._card.setVisage(1332);
+ scene->_gameBoardSide[0]._handCard[0]._card.setPosition(scene->_gameBoardSide[0]._handCard[0]._stationPos, 0);
+ scene->_gameBoardSide[0]._handCard[0]._card.setStrip(5);
+ scene->_gameBoardSide[0]._handCard[0]._card.setFrame(1);
+ scene->_gameBoardSide[0]._handCard[0]._card.fixPriority(170);
+ scene->_aSound2.play(61);
+
+ Common::Point pt(283, 124);
+ NpcMover *mover = new NpcMover();
+ scene->_animatedCard._card.addMover(mover, &pt, this);
+
+ scene->_gameBoardSide[1]._handCard[1]._cardId = scene->_availableCardsPile[scene->_cardsAvailableNumb];
+ }
+ break;
+ case 5: {
+ scene->_gameBoardSide[1]._handCard[1]._card.postInit();
+ scene->_gameBoardSide[1]._handCard[1]._card._moveDiff = Common::Point(30, 30);
+ scene->_gameBoardSide[1]._handCard[1]._card.setVisage(1332);
+ scene->_gameBoardSide[1]._handCard[1]._card.setPosition(scene->_gameBoardSide[1]._handCard[1]._stationPos, 0);
+ scene->_gameBoardSide[1]._handCard[1]._card.setStrip(1);
+ scene->_gameBoardSide[1]._handCard[1]._card.setFrame(4);
+ scene->_gameBoardSide[1]._handCard[1]._card.fixPriority(170);
+ scene->_aSound2.play(61);
+
+ Common::Point pt(37, 174);
+ NpcMover *mover = new NpcMover();
+ scene->_animatedCard._card.addMover(mover, &pt, this);
+
+ scene->_gameBoardSide[2]._handCard[1]._cardId = scene->_availableCardsPile[scene->_cardsAvailableNumb];
+ }
+ break;
+ case 6: {
+ scene->_gameBoardSide[2]._handCard[1]._card.postInit();
+ scene->_gameBoardSide[2]._handCard[1]._card._moveDiff = Common::Point(30, 30);
+ scene->_gameBoardSide[2]._handCard[1]._card.setVisage(1332);
+ scene->_gameBoardSide[2]._handCard[1]._card.setPosition(scene->_gameBoardSide[2]._handCard[1]._stationPos, 0);
+ scene->_gameBoardSide[2]._handCard[1]._card.fixPriority(170);
+
+ if (scene->_gameBoardSide[2]._handCard[1]._cardId > 25) {
+ scene->_gameBoardSide[2]._handCard[1]._card.setStrip(4);
+ scene->_gameBoardSide[2]._handCard[1]._card.setFrame(scene->_gameBoardSide[2]._handCard[1]._cardId - 25);
+ } else if (scene->_gameBoardSide[2]._handCard[1]._cardId > 9) {
+ scene->_gameBoardSide[2]._handCard[1]._card.setStrip(3);
+ scene->_gameBoardSide[2]._handCard[1]._card.setFrame(scene->_gameBoardSide[2]._handCard[1]._cardId - 9);
+ } else {
+ scene->_gameBoardSide[2]._handCard[1]._card.setStrip(2);
+ scene->_gameBoardSide[2]._handCard[1]._card.setFrame(scene->_gameBoardSide[2]._handCard[1]._cardId);
+ }
+
+ scene->_aSound2.play(61);
+
+ Common::Point pt(14, 36);
+ NpcMover *mover = new NpcMover();
+ scene->_animatedCard._card.addMover(mover, &pt, this);
+
+ scene->_gameBoardSide[3]._handCard[1]._cardId = scene->_availableCardsPile[scene->_cardsAvailableNumb];
+ }
+ break;
+ case 7: {
+ scene->_gameBoardSide[3]._handCard[1]._card.postInit();
+ scene->_gameBoardSide[3]._handCard[1]._card._moveDiff = Common::Point(30, 30);
+ scene->_gameBoardSide[3]._handCard[1]._card.setVisage(1332);
+ scene->_gameBoardSide[3]._handCard[1]._card.setPosition(scene->_gameBoardSide[3]._handCard[1]._stationPos);
+ scene->_gameBoardSide[3]._handCard[1]._card.setStrip(1);
+ scene->_gameBoardSide[3]._handCard[1]._card.setFrame(3);
+ scene->_gameBoardSide[3]._handCard[1]._card.fixPriority(170);
+ scene->_aSound2.play(61);
+
+ Common::Point pt(253, 5);
+ NpcMover *mover = new NpcMover();
+ scene->_animatedCard._card.addMover(mover, &pt, this);
+
+ scene->_gameBoardSide[0]._handCard[1]._cardId = scene->_availableCardsPile[scene->_cardsAvailableNumb];
+ }
+ break;
+ case 8: {
+ scene->_gameBoardSide[0]._handCard[1]._card.postInit();
+ scene->_gameBoardSide[0]._handCard[1]._card._moveDiff = Common::Point(30, 30);
+ scene->_gameBoardSide[0]._handCard[1]._card.setVisage(1332);
+ scene->_gameBoardSide[0]._handCard[1]._card.setPosition(scene->_gameBoardSide[0]._handCard[1]._stationPos, 0);
+ scene->_gameBoardSide[0]._handCard[1]._card.setStrip(5);
+ scene->_gameBoardSide[0]._handCard[1]._card.setFrame(1);
+ scene->_gameBoardSide[0]._handCard[1]._card.fixPriority(170);
+ scene->_aSound2.play(61);
+
+ Common::Point pt(283, 102);
+ NpcMover *mover = new NpcMover();
+ scene->_animatedCard._card.addMover(mover, &pt, this);
+
+ scene->_gameBoardSide[1]._handCard[2]._cardId = scene->_availableCardsPile[scene->_cardsAvailableNumb];
+ }
+ break;
+ case 9: {
+ scene->_gameBoardSide[1]._handCard[2]._card.postInit();
+ scene->_gameBoardSide[1]._handCard[2]._card._moveDiff = Common::Point(30, 30);
+ scene->_gameBoardSide[1]._handCard[2]._card.setVisage(1332);
+ scene->_gameBoardSide[1]._handCard[2]._card.setPosition(scene->_gameBoardSide[1]._handCard[2]._stationPos, 0);
+ scene->_gameBoardSide[1]._handCard[2]._card.setStrip(1);
+ scene->_gameBoardSide[1]._handCard[2]._card.setFrame(4);
+ scene->_gameBoardSide[1]._handCard[2]._card.fixPriority(170);
+ scene->_aSound2.play(61);
+
+ Common::Point pt(64, 174);
+ NpcMover *mover = new NpcMover();
+ scene->_animatedCard._card.addMover(mover, &pt, this);
+
+ scene->_gameBoardSide[2]._handCard[2]._cardId = scene->_availableCardsPile[scene->_cardsAvailableNumb];
+ }
+ break;
+ case 10: {
+ scene->_gameBoardSide[2]._handCard[2]._card.postInit();
+ scene->_gameBoardSide[2]._handCard[2]._card._moveDiff = Common::Point(30, 30);
+ scene->_gameBoardSide[2]._handCard[2]._card.setVisage(1332);
+ scene->_gameBoardSide[2]._handCard[2]._card.setPosition(scene->_gameBoardSide[2]._handCard[2]._stationPos, 0);
+ scene->_gameBoardSide[2]._handCard[2]._card.fixPriority(170);
+
+ if (scene->_gameBoardSide[2]._handCard[2]._cardId > 25) {
+ scene->_gameBoardSide[2]._handCard[2]._card.setStrip(4);
+ scene->_gameBoardSide[2]._handCard[2]._card.setFrame(scene->_gameBoardSide[2]._handCard[2]._cardId - 25);
+ } else if (scene->_gameBoardSide[2]._handCard[2]._cardId > 9) {
+ scene->_gameBoardSide[2]._handCard[2]._card.setStrip(3);
+ scene->_gameBoardSide[2]._handCard[2]._card.setFrame(scene->_gameBoardSide[2]._handCard[2]._cardId - 9);
+ } else {
+ scene->_gameBoardSide[2]._handCard[2]._card.setStrip(2);
+ scene->_gameBoardSide[2]._handCard[2]._card.setFrame(scene->_gameBoardSide[2]._handCard[2]._cardId);
+ }
+
+ scene->_aSound2.play(61);
+
+ Common::Point pt(14, 58);
+ NpcMover *mover = new NpcMover();
+ scene->_animatedCard._card.addMover(mover, &pt, this);
+
+ scene->_gameBoardSide[3]._handCard[2]._cardId = scene->_availableCardsPile[scene->_cardsAvailableNumb];
+ }
+ break;
+ case 11: {
+ scene->_gameBoardSide[3]._handCard[2]._card.postInit();
+ scene->_gameBoardSide[3]._handCard[2]._card._moveDiff = Common::Point(30, 30);
+ scene->_gameBoardSide[3]._handCard[2]._card.setVisage(1332);
+ scene->_gameBoardSide[3]._handCard[2]._card.setPosition(scene->_gameBoardSide[3]._handCard[2]._stationPos, 0);
+ scene->_gameBoardSide[3]._handCard[2]._card.setStrip(1);
+ scene->_gameBoardSide[3]._handCard[2]._card.setFrame(3);
+ scene->_gameBoardSide[3]._handCard[2]._card.fixPriority(170);
+ scene->_aSound2.play(61);
+
+ Common::Point pt(226, 5);
+ NpcMover *mover = new NpcMover();
+ scene->_animatedCard._card.addMover(mover, &pt, this);
+
+ scene->_gameBoardSide[0]._handCard[2]._cardId = scene->_availableCardsPile[scene->_cardsAvailableNumb];
+ }
+ break;
+ case 12:
+ scene->_gameBoardSide[0]._handCard[2]._card.postInit();
+ scene->_gameBoardSide[0]._handCard[2]._card._moveDiff = Common::Point(30, 30);
+ scene->_gameBoardSide[0]._handCard[2]._card.setVisage(1332);
+ scene->_gameBoardSide[0]._handCard[2]._card.setPosition(scene->_gameBoardSide[0]._handCard[2]._stationPos, 0);
+ scene->_gameBoardSide[0]._handCard[2]._card.setStrip(5);
+ scene->_gameBoardSide[0]._handCard[2]._card.setFrame(1);
+ scene->_gameBoardSide[0]._handCard[2]._card.fixPriority(170);
+ scene->_animatedCard._card.hide();
+ default:
+ break;
+ }
+
+ if (_actionIndex > 12) {
+ scene->_currentPlayerNumb = 0;
+ R2_GLOBALS._sceneObjects->draw();
+ scene->actionDisplay(1330, 0, 159, 10, 1, 200, 0, 7, 0, 154, 154);
+ scene->handleNextTurn();
+ } else if (_actionIndex >= 1) {
+ scene->_availableCardsPile[scene->_cardsAvailableNumb] = 0;
+ scene->_cardsAvailableNumb--;
+ }
+}
+
+/**
+ * Action used to handle the other players' turn
+ */
+void Scene1337::Action4::signal() {
+ Scene1337 *scene = (Scene1337 *)R2_GLOBALS._sceneManager._scene;
+
+ switch (_actionIndex++) {
+ case 0:
+ if ( (scene->_gameBoardSide[scene->_currentPlayerNumb]._handCard[0]._cardId == 0)
+ && (!scene->isStationCard(scene->_gameBoardSide[scene->_currentPlayerNumb]._delayCard._cardId))) {
+ if (scene->_cardsAvailableNumb < 0)
+ scene->shuffleCards();
+ scene->_animatedCard._card.setPosition(Common::Point(162, 95), 0);
+ scene->_animatedCard._card.show();
+ scene->_aSound2.play(61);
+
+ NpcMover *mover = new NpcMover();
+ scene->_animatedCard._card.addMover(mover, &scene->_gameBoardSide[scene->_currentPlayerNumb]._card1Pos, this);
+
+ scene->_gameBoardSide[scene->_currentPlayerNumb]._handCard[0]._cardId = scene->_availableCardsPile[scene->_cardsAvailableNumb];
+ scene->_availableCardsPile[scene->_cardsAvailableNumb] = 0;
+ scene->_cardsAvailableNumb--;
+
+ if (scene->_cardsAvailableNumb < 0)
+ scene->_stockPile.remove();
+ } else {
+ // Self call, forcing next actionIndex
+ signal();
+ }
+ break;
+ case 1:
+ if ( (scene->_animatedCard._card._position.x == scene->_gameBoardSide[scene->_currentPlayerNumb]._card1Pos.x)
+ && (scene->_animatedCard._card._position.y == scene->_gameBoardSide[scene->_currentPlayerNumb]._card1Pos.y) ) {
+ scene->_gameBoardSide[scene->_currentPlayerNumb]._handCard[0]._card.postInit();
+ scene->_gameBoardSide[scene->_currentPlayerNumb]._handCard[0]._card._moveDiff = Common::Point(30, 30);
+ scene->_gameBoardSide[scene->_currentPlayerNumb]._handCard[0]._card.setVisage(1332);
+ scene->_gameBoardSide[scene->_currentPlayerNumb]._handCard[0]._card.setPosition(scene->_gameBoardSide[scene->_currentPlayerNumb]._handCard[0]._stationPos, 0);
+ scene->_gameBoardSide[scene->_currentPlayerNumb]._handCard[0]._card.setStrip(1);
+ scene->_gameBoardSide[scene->_currentPlayerNumb]._handCard[0]._card.setFrame(scene->_gameBoardSide[scene->_currentPlayerNumb]._frameNum);
+ scene->_gameBoardSide[scene->_currentPlayerNumb]._handCard[0]._card.fixPriority(170);
+ }
+
+ if ((R2_GLOBALS._debugCardGame) || (scene->_currentPlayerNumb == 2))
+ scene->setAnimationInfo(&scene->_gameBoardSide[scene->_currentPlayerNumb]._handCard[0]);
+
+ scene->_animatedCard._card.hide();
+ if ( (scene->_gameBoardSide[scene->_currentPlayerNumb]._handCard[1]._cardId == 0)
+ && (!scene->isStationCard(scene->_gameBoardSide[scene->_currentPlayerNumb]._delayCard._cardId))) {
+ if (scene->_cardsAvailableNumb < 0)
+ scene->shuffleCards();
+ scene->_animatedCard._card.setPosition(Common::Point(162, 95));
+ scene->_animatedCard._card.show();
+
+ scene->_aSound2.play(61);
+
+ NpcMover *mover = new NpcMover();
+ scene->_animatedCard._card.addMover(mover, &scene->_gameBoardSide[scene->_currentPlayerNumb]._card2Pos, this);
+
+ scene->_gameBoardSide[scene->_currentPlayerNumb]._handCard[1]._cardId = scene->_availableCardsPile[scene->_cardsAvailableNumb];
+ scene->_availableCardsPile[scene->_cardsAvailableNumb] = 0;
+ scene->_cardsAvailableNumb--;
+ if (scene->_cardsAvailableNumb < 0)
+ scene->_stockPile.remove();
+ } else
+ signal();
+ break;
+ case 2:
+ if ( (scene->_animatedCard._card._position.x == scene->_gameBoardSide[scene->_currentPlayerNumb]._card2Pos.x)
+ && (scene->_animatedCard._card._position.y == scene->_gameBoardSide[scene->_currentPlayerNumb]._card2Pos.y) ) {
+ scene->_gameBoardSide[scene->_currentPlayerNumb]._handCard[1]._card.postInit();
+ scene->_gameBoardSide[scene->_currentPlayerNumb]._handCard[1]._card._moveDiff = Common::Point(30, 30);
+ scene->_gameBoardSide[scene->_currentPlayerNumb]._handCard[1]._card.setVisage(1332);
+ scene->_gameBoardSide[scene->_currentPlayerNumb]._handCard[1]._card.setPosition(scene->_gameBoardSide[scene->_currentPlayerNumb]._handCard[1]._stationPos, 0);
+ scene->_gameBoardSide[scene->_currentPlayerNumb]._handCard[1]._card.setStrip(1);
+ scene->_gameBoardSide[scene->_currentPlayerNumb]._handCard[1]._card.setFrame(scene->_gameBoardSide[scene->_currentPlayerNumb]._frameNum);
+ scene->_gameBoardSide[scene->_currentPlayerNumb]._handCard[1]._card.fixPriority(170);
+ }
+
+ if ((R2_GLOBALS._debugCardGame) || (scene->_currentPlayerNumb == 2))
+ scene->setAnimationInfo(&scene->_gameBoardSide[scene->_currentPlayerNumb]._handCard[1]);
+
+ scene->_animatedCard._card.hide();
+ if ( (scene->_gameBoardSide[scene->_currentPlayerNumb]._handCard[2]._cardId == 0)
+ && (!scene->isStationCard(scene->_gameBoardSide[scene->_currentPlayerNumb]._delayCard._cardId))) {
+ if (scene->_cardsAvailableNumb < 0)
+ scene->shuffleCards();
+ scene->_animatedCard._card.setPosition(Common::Point(162, 95));
+ scene->_animatedCard._card.show();
+
+ scene->_aSound2.play(61);
+
+ NpcMover *mover = new NpcMover();
+ scene->_animatedCard._card.addMover(mover, &scene->_gameBoardSide[scene->_currentPlayerNumb]._card3Pos, this);
+
+ scene->_gameBoardSide[scene->_currentPlayerNumb]._handCard[2]._cardId = scene->_availableCardsPile[scene->_cardsAvailableNumb];
+ scene->_availableCardsPile[scene->_cardsAvailableNumb] = 0;
+ scene->_cardsAvailableNumb--;
+ if (scene->_cardsAvailableNumb < 0)
+ scene->_stockPile.remove();
+ } else
+ signal();
+ break;
+ case 3:
+ if ( (scene->_animatedCard._card._position.x == scene->_gameBoardSide[scene->_currentPlayerNumb]._card3Pos.x)
+ && (scene->_animatedCard._card._position.y == scene->_gameBoardSide[scene->_currentPlayerNumb]._card3Pos.y) ) {
+ scene->_gameBoardSide[scene->_currentPlayerNumb]._handCard[2]._card.postInit();
+ scene->_gameBoardSide[scene->_currentPlayerNumb]._handCard[2]._card._moveDiff = Common::Point(30, 30);
+ scene->_gameBoardSide[scene->_currentPlayerNumb]._handCard[2]._card.setVisage(1332);
+ scene->_gameBoardSide[scene->_currentPlayerNumb]._handCard[2]._card.setPosition(scene->_gameBoardSide[scene->_currentPlayerNumb]._handCard[2]._stationPos, 0);
+ scene->_gameBoardSide[scene->_currentPlayerNumb]._handCard[2]._card.setStrip(1);
+ scene->_gameBoardSide[scene->_currentPlayerNumb]._handCard[2]._card.setFrame(scene->_gameBoardSide[scene->_currentPlayerNumb]._frameNum);
+ scene->_gameBoardSide[scene->_currentPlayerNumb]._handCard[2]._card.fixPriority(170);
+ }
+
+ if ((R2_GLOBALS._debugCardGame) || (scene->_currentPlayerNumb == 2))
+ scene->setAnimationInfo(&scene->_gameBoardSide[scene->_currentPlayerNumb]._handCard[2]);
+
+ scene->_animatedCard._card.hide();
+ if ( (scene->_gameBoardSide[scene->_currentPlayerNumb]._handCard[3]._cardId == 0)
+ && (!scene->isStationCard(scene->_gameBoardSide[scene->_currentPlayerNumb]._delayCard._cardId))) {
+ if (scene->_cardsAvailableNumb < 0)
+ scene->shuffleCards();
+ scene->_animatedCard._card.setPosition(Common::Point(162, 95));
+ scene->_animatedCard._card.show();
+
+ scene->_aSound2.play(61);
+
+ NpcMover *mover = new NpcMover();
+ scene->_animatedCard._card.addMover(mover, &scene->_gameBoardSide[scene->_currentPlayerNumb]._card4Pos, this);
+
+ scene->_gameBoardSide[scene->_currentPlayerNumb]._handCard[3]._cardId = scene->_availableCardsPile[scene->_cardsAvailableNumb];
+ scene->_availableCardsPile[scene->_cardsAvailableNumb] = 0;
+ scene->_cardsAvailableNumb--;
+ if (scene->_cardsAvailableNumb < 0)
+ scene->_stockPile.remove();
+ } else
+ signal();
+ break;
+ case 4:
+ if ( (scene->_animatedCard._card._position.x == scene->_gameBoardSide[scene->_currentPlayerNumb]._card4Pos.x)
+ && (scene->_animatedCard._card._position.y == scene->_gameBoardSide[scene->_currentPlayerNumb]._card4Pos.y) ) {
+ scene->_gameBoardSide[scene->_currentPlayerNumb]._handCard[3]._card.postInit();
+ scene->_gameBoardSide[scene->_currentPlayerNumb]._handCard[3]._card._moveDiff = Common::Point(30, 30);
+ scene->_gameBoardSide[scene->_currentPlayerNumb]._handCard[3]._card.setVisage(1332);
+ scene->_gameBoardSide[scene->_currentPlayerNumb]._handCard[3]._card.setPosition(scene->_gameBoardSide[scene->_currentPlayerNumb]._handCard[3]._stationPos, 0);
+ scene->_gameBoardSide[scene->_currentPlayerNumb]._handCard[3]._card.setStrip(1);
+ scene->_gameBoardSide[scene->_currentPlayerNumb]._handCard[3]._card.setFrame(scene->_gameBoardSide[scene->_currentPlayerNumb]._frameNum);
+ scene->_gameBoardSide[scene->_currentPlayerNumb]._handCard[3]._card.fixPriority(170);
+ }
+
+ if ((R2_GLOBALS._debugCardGame) || (scene->_currentPlayerNumb == 2))
+ scene->setAnimationInfo(&scene->_gameBoardSide[scene->_currentPlayerNumb]._handCard[3]);
+
+ scene->_animatedCard._card.hide();
+ switch (scene->_currentPlayerNumb) {
+ case 0:
+ scene->handlePlayer0();
+ break;
+ case 1:
+ scene->handlePlayer1();
+ break;
+ case 2:
+ scene->handleAutoplayPlayer2();
+ break;
+ case 3:
+ scene->handlePlayer3();
+ break;
+ default:
+ break;
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+/**
+ * Animations for discarding a card
+ */
+void Scene1337::Action5::signal() {
+ Scene1337 *scene = (Scene1337 *)R2_GLOBALS._sceneManager._scene;
+
+ switch (_actionIndex++) {
+ case 0: {
+ scene->_availableCardsPile[scene->_currentDiscardIndex] = scene->_actionCard1->_cardId;
+ scene->_currentDiscardIndex--;
+ if (!g_globals->_sceneObjects->contains(&scene->_discardPile._card)) {
+ // The first discarded card makes the pile appear
+ scene->_discardPile._card.postInit();
+ scene->_discardPile._card.hide();
+ scene->_discardPile._card.setVisage(1332);
+ scene->_discardPile._card.setPosition(scene->_discardPile._stationPos, 0);
+ scene->_discardPile._card.fixPriority(170);
+ }
+
+ scene->_discardPile._cardId = scene->_actionCard1->_cardId;
+ scene->_actionCard1->_cardId = 0;
+ scene->_actionCard1->_card.remove();
+
+ if (scene->_actionCard1 == &scene->_selectedCard) {
+ scene->setCursorData(5, 1, 4);
+ scene->subC4CEC();
+ }
+ scene->_animatedCard._card.setPosition(scene->_actionCard1->_stationPos, 0);
+ scene->_animatedCard._card.show();
+ Common::Point pt(128, 95);
+ NpcMover *mover = new NpcMover();
+ scene->_animatedCard._card.addMover(mover, &pt, this);
+ }
+ break;
+ case 1:
+ scene->_animatedCard._card.hide();
+ scene->setAnimationInfo(&scene->_discardPile);
+ scene->_aSound2.play(61);
+ scene->handleNextTurn();
+ break;
+ default:
+ break;
+ }
+}
+
+/**
+ * Animations for playing a platform card
+ */
+void Scene1337::Action6::signal() {
+ Scene1337 *scene = (Scene1337 *)R2_GLOBALS._sceneManager._scene;
+
+ switch (_actionIndex++) {
+ case 0: {
+ scene->_actionCard2->_cardId = 1;
+ scene->_actionCard2->_card.postInit();
+ scene->_actionCard2->_card.hide();
+ scene->_actionCard2->_card.setVisage(1332);
+ scene->_actionCard2->_card.setPosition(scene->_actionCard2->_stationPos);
+ scene->_actionCard2->_card.fixPriority(170);
+
+ scene->_actionCard1->_cardId = 0;
+ scene->_actionCard1->_card.remove();
+
+ scene->_animatedCard._card.setPosition(scene->_actionCard1->_stationPos);
+ scene->_animatedCard._card.show();
+
+ NpcMover *mover = new NpcMover();
+ scene->_animatedCard._card.addMover(mover, &scene->_actionCard2->_stationPos, this);
+ }
+ break;
+ case 1:
+ scene->_animatedCard._card.hide();
+ scene->setAnimationInfo(scene->_actionCard2);
+ scene->_aSound1.play(59);
+ if (scene->_actionCard1 == &scene->_selectedCard) {
+ scene->setCursorData(5, 1, 4);
+ scene->subC4CEC();
+ }
+ scene->handleNextTurn();
+ break;
+ default:
+ break;
+ }
+}
+
+/**
+ * Upgrade platform to station by playing a station card on top of it
+ */
+void Scene1337::Action7::signal() {
+ Scene1337 *scene = (Scene1337 *)R2_GLOBALS._sceneManager._scene;
+
+ switch (_actionIndex++) {
+ case 0: {
+ scene->_actionCard2->_cardId = scene->_actionCard1->_cardId;
+
+ scene->_actionCard1->_cardId = 0;
+ scene->_actionCard1->_card.remove();
+
+ scene->_animatedCard._card.setPosition(scene->_actionCard1->_stationPos, 0);
+ scene->_animatedCard._card.show();
+ NpcMover *mover = new NpcMover();
+ scene->_animatedCard._card.addMover(mover, &scene->_actionCard2->_stationPos, this);
+ }
+ break;
+ case 1:
+ if (scene->_actionCard1 == &scene->_selectedCard) {
+ scene->setCursorData(5, 1, 4);
+ scene->subC4CEC();
+ }
+ scene->setAnimationInfo(scene->_actionCard2);
+ scene->_aSound1.play(59);
+ scene->_discardedPlatformCard._cardId = 1;
+ scene->_discardedPlatformCard._stationPos = scene->_actionCard2->_stationPos;
+ scene->_discardedPlatformCard._card.postInit();
+ scene->_discardedPlatformCard._card.hide();
+ scene->_discardedPlatformCard._card._flags = OBJFLAG_HIDING;
+
+ scene->discardCard(&scene->_discardedPlatformCard);
+ break;
+ default:
+ break;
+ }
+}
+
+// Remove a delay card
+void Scene1337::Action8::signal() {
+ Scene1337 *scene = (Scene1337 *)R2_GLOBALS._sceneManager._scene;
+
+ switch (_actionIndex++) {
+ case 0: {
+ scene->_availableCardsPile[scene->_currentDiscardIndex] = scene->_actionCard2->_cardId;
+ scene->_currentDiscardIndex--;
+
+ scene->_actionCard2->_cardId = scene->_actionCard1->_cardId;
+ scene->_actionCard1->_card.remove();
+
+ scene->_animatedCard._card.setPosition(scene->_actionCard1->_stationPos, 0);
+ scene->_animatedCard._card.show();
+
+ NpcMover *mover = new NpcMover();
+ scene->_animatedCard._card.addMover(mover, &scene->_actionCard2->_stationPos, this);
+ }
+ break;
+ case 1:
+ scene->_animatedCard._card.hide();
+
+ if (scene->_actionCard1 == &scene->_selectedCard) {
+ scene->setCursorData(5, 1, 4);
+ scene->subC4CEC();
+ }
+ scene->setAnimationInfo(scene->_actionCard2);
+ scene->_aSound1.play(58);
+ scene->discardCard(scene->_actionCard2);
+ break;
+ default:
+ break;
+ }
+}
+
+// Play delay card
+void Scene1337::Action9::signal() {
+ Scene1337 *scene = (Scene1337 *)R2_GLOBALS._sceneManager._scene;
+
+ switch (_actionIndex++) {
+ case 0: {
+ scene->_actionCard2->_cardId = scene->_actionCard1->_cardId;
+ scene->_actionCard2->_card.postInit();
+ scene->_actionCard2->_card.hide();
+ scene->_actionCard2->_card.setVisage(1332);
+ scene->_actionCard2->_card.setPosition(scene->_actionCard2->_stationPos, 0);
+ scene->_actionCard2->_card.fixPriority(170);
+
+ scene->_actionCard1->_cardId = 0;
+ scene->_actionCard1->_card.remove();
+
+ scene->_animatedCard._card.setPosition(scene->_actionCard1->_stationPos, 0);
+ scene->_animatedCard._card.show();
+
+ NpcMover *mover = new NpcMover();
+ scene->_animatedCard._card.addMover(mover, &scene->_actionCard2->_stationPos, this);
+ }
+ break;
+ case 1:
+ scene->_animatedCard._card.hide();
+ scene->setAnimationInfo(scene->_actionCard2);
+ scene->_aSound1.play(57);
+
+ if (scene->_actionCard1 == &scene->_selectedCard) {
+ scene->setCursorData(5, 1, 4);
+ scene->subC4CEC();
+ }
+
+ scene->handleNextTurn();
+ break;
+ default:
+ break;
+ }
+}
+
+// Play a card on the central outpost.
+// This card is either a counter-trick card or a meteor card
+void Scene1337::Action10::signal() {
+ Scene1337 *scene = (Scene1337 *)R2_GLOBALS._sceneManager._scene;
+
+ switch (_actionIndex++) {
+ case 0: {
+ scene->_actionCard3->_card.postInit();
+ scene->_actionCard3->_card.hide();
+ scene->_actionCard3->_card.setVisage(1332);
+ scene->_actionCard3->_card.setPosition(scene->_actionCard3->_stationPos, 0);
+ scene->_actionCard3->_card.fixPriority(170);
+ scene->_actionCard3->_cardId = scene->_actionCard1->_cardId;
+
+ scene->_actionCard1->_cardId = 0;
+ scene->_actionCard1->_card.remove();
+
+ if (scene->_actionCard1 == &scene->_selectedCard) {
+ scene->setCursorData(5, 1, 4);
+ scene->subC4CEC();
+ }
+
+ scene->_animatedCard._card.setPosition(scene->_actionCard1->_stationPos, 0);
+ scene->_animatedCard._card.show();
+ NpcMover *mover = new NpcMover();
+ scene->_animatedCard._card.addMover(mover, &scene->_actionCard3->_stationPos, this);
+ }
+ break;
+ case 1: {
+ scene->_animatedCard._card.hide();
+ scene->setAnimationInfo(scene->_actionCard3);
+ scene->_aSound1.play(57);
+
+ bool found = false;
+ int indexFound = -1;
+
+ switch (scene->_actionPlayerIdx) {
+ case 0:
+ for (indexFound = 0; indexFound < 3; indexFound++) {
+ // Check for the presence of an interceptor card
+ if (scene->_gameBoardSide[0]._handCard[indexFound]._cardId == 29) {
+ found = true;
+ break;
+ }
+ }
+ break;
+ case 1:
+ for (indexFound = 0; indexFound < 3; indexFound++) {
+ // Check for the presence of an interceptor card
+ if (scene->_gameBoardSide[1]._handCard[indexFound]._cardId == 29) {
+ found = true;
+ break;
+ }
+ }
+ break;
+ case 2:
+ for (indexFound = 0; indexFound < 3; indexFound++) {
+ // Check for the presence of an interceptor card
+ if (scene->_gameBoardSide[2]._handCard[indexFound]._cardId == 29) {
+ found = true;
+ break;
+ }
+ }
+ break;
+ case 3:
+ for (indexFound = 0; indexFound < 3; indexFound++) {
+ // Check for the presence of an interceptor card
+ if (scene->_gameBoardSide[3]._handCard[indexFound]._cardId == 29) {
+ found = true;
+ break;
+ }
+ }
+ break;
+ default:
+ break;
+ }
+
+ bool found2 = false;
+
+ if (found) {
+ switch (scene->_actionPlayerIdx) {
+ case 0:
+ scene->playInterceptorCard(&scene->_gameBoardSide[0]._handCard[indexFound], scene->_actionCard3);
+ found2 = true;
+ break;
+ case 1:
+ scene->playInterceptorCard(&scene->_gameBoardSide[1]._handCard[indexFound], scene->_actionCard3);
+ found2 = true;
+ break;
+ case 2:
+ scene->subC4CD2();
+ if (MessageDialog::show(USE_INTERCEPTOR, NO_MSG, YES_MSG) == 0)
+ scene->subC4CEC();
+ else {
+ scene->playInterceptorCard(&scene->_gameBoardSide[2]._handCard[indexFound], scene->_actionCard3);
+ found2 = true;
+ }
+ break;
+ case 3:
+ scene->playInterceptorCard(&scene->_gameBoardSide[3]._handCard[indexFound], scene->_actionCard3);
+ found2 = true;
+ break;
+ default:
+ break;
+ }
+ }
+
+ if (found2)
+ break;
+
+ if (scene->_actionPlayerIdx == 2) {
+ int stationCount = 0;
+ for (int i = 0; i <= 7; i++) {
+ if (scene->_gameBoardSide[2]._outpostStation[i]._cardId != 0)
+ ++stationCount;
+ }
+
+ if (stationCount <= 1) {
+ for (int i = 0; i <= 7; i++) {
+ if (scene->_gameBoardSide[2]._outpostStation[i]._cardId != 0) {
+ scene->_actionCard2 = &scene->_gameBoardSide[2]._outpostStation[i];
+ break;
+ }
+ }
+ } else {
+ scene->subC4CD2();
+
+ found2 = false;
+ while (!found2) {
+ scene->actionDisplay(1330, 130, 159, 10, 1, 200, 0, 7, 0, 154, 154);
+
+ // Wait for a mouse or keypress
+ Event event;
+ while (!g_globals->_events.getEvent(event, EVENT_BUTTON_DOWN | EVENT_KEYPRESS) && !g_vm->shouldQuit()) {
+ g_globals->_scenePalette.signalListeners();
+ R2_GLOBALS._sceneObjects->draw();
+ g_globals->_events.delay(g_globals->_sceneHandler->_delayTicks);
+ }
+
+ scene->_selectedCard._stationPos = event.mousePos;
+
+ for (int i = 0; i <= 7; i++) {
+ if (scene->_gameBoardSide[2]._outpostStation[i].isIn(scene->_selectedCard._stationPos) && (scene->_gameBoardSide[2]._outpostStation[i]._cardId != 0)) {
+ scene->_actionCard2 = &scene->_gameBoardSide[2]._outpostStation[i];
+ found2 = true;
+ break;
+ }
+ }
+ }
+ scene->subC4CEC();
+ }
+ }
+
+ scene->_availableCardsPile[scene->_currentDiscardIndex] = scene->_actionCard2->_cardId;
+ scene->_currentDiscardIndex--;
+ scene->_actionCard2->_cardId = 0;
+ scene->_actionCard2->_card.remove();
+
+ scene->_animatedCard._card.setPosition(scene->_actionCard2->_stationPos, 0);
+ scene->_animatedCard._card.show();
+
+ NpcMover *mover = new NpcMover();
+ scene->_animatedCard._card.addMover(mover, &scene->_actionCard3->_stationPos, this);
+ }
+ break;
+ case 2:
+ scene->_animatedCard._card.hide();
+ scene->discardCard(scene->_actionCard3);
+ break;
+ default:
+ break;
+ }
+}
+
+// Use Thief card (#25) and pick a card from the opponent
+void Scene1337::Action11::signal() {
+ Scene1337 *scene = (Scene1337 *)R2_GLOBALS._sceneManager._scene;
+
+ switch (_actionIndex++) {
+ case 0: {
+ scene->_actionCard2->_card.postInit();
+ scene->_actionCard2->_card.hide();
+ scene->_actionCard2->_card.setVisage(1332);
+ scene->_actionCard2->_card.setPosition(scene->_actionCard2->_stationPos, 0);
+ scene->_actionCard2->_card.fixPriority(170);
+ scene->_actionCard2->_cardId = 25;
+
+ if (scene->_actionPlayerIdx == 2) {
+ scene->_animatedCard._card.setPosition(scene->_actionCard2->_stationPos, 0);
+ scene->setCursorData(5, 1, 4);
+ } else {
+ scene->_actionCard1->_cardId = 0;
+ scene->_actionCard1->_card.remove();
+ scene->_animatedCard._card.setPosition(scene->_actionCard1->_stationPos, 0);
+ }
+ scene->_animatedCard._card.show();
+
+ NpcMover *mover = new NpcMover();
+ scene->_animatedCard._card.addMover(mover, &scene->_actionCard2->_stationPos, this);
+ }
+ break;
+ case 1: {
+ scene->_animatedCard._card.hide();
+ scene->setAnimationInfo(scene->_actionCard2);
+ scene->_aSound1.play(57);
+
+ bool found = false;
+ bool noAction = true;
+
+ int i = -1;
+
+ switch (scene->_actionVictimIdx) {
+ case 0:
+ for (i = 0; i <= 3; i++) {
+ if (scene->_gameBoardSide[0]._handCard[i]._cardId == 27) {
+ found = true;
+ break;
+ }
+ }
+
+ if ((found) && (scene->getRandomCardFromHand(scene->_actionPlayerIdx) != -1)) {
+ scene->_actionCard1 = &scene->_gameBoardSide[0]._handCard[i];
+ scene->_actionCard2 = &scene->_gameBoardSide[0]._emptyStationPos;
+ if (scene->_actionPlayerIdx != 0) {
+ int tmpVal = scene->getRandomCardFromHand(scene->_actionPlayerIdx);
+ scene->_actionCard3 = &scene->_gameBoardSide[scene->_actionPlayerIdx]._handCard[tmpVal];
+ }
+ scene->_actionItem.setAction(&scene->_action12);
+ noAction = false;
+ }
+ break;
+ case 1:
+ for (i = 0; i <= 3; i++) {
+ if (scene->_gameBoardSide[1]._handCard[i]._cardId == 27) {
+ found = true;
+ break;
+ }
+ }
+
+ if ((found) && (scene->getRandomCardFromHand(scene->_actionPlayerIdx) != -1)) {
+ scene->_actionCard1 = &scene->_gameBoardSide[1]._handCard[i];
+ scene->_actionCard2 = &scene->_gameBoardSide[1]._emptyStationPos;
+ if (scene->_actionPlayerIdx != 1) {
+ int tmpVal = scene->getRandomCardFromHand(scene->_actionPlayerIdx);
+ scene->_actionCard3 = &scene->_gameBoardSide[scene->_actionPlayerIdx]._handCard[tmpVal];
+ }
+ scene->_actionItem.setAction(&scene->_action12);
+ noAction = false;
+ }
+ break;
+ case 2:
+ for (i = 0; i <= 3; i++) {
+ if (scene->_gameBoardSide[2]._handCard[i]._cardId == 27) {
+ found = true;
+ break;
+ }
+ }
+
+ if ((found) && (scene->getRandomCardFromHand(scene->_actionPlayerIdx) != -1)) {
+ scene->subC4CD2();
+ if (MessageDialog::show(USE_DOUBLE_AGENT, NO_MSG, YES_MSG) == 0)
+ scene->subC4CEC();
+ else {
+ scene->subC4CEC();
+ scene->_actionCard1 = &scene->_gameBoardSide[2]._handCard[i];
+ scene->_actionCard2 = &scene->_gameBoardSide[2]._emptyStationPos;
+ if (scene->_actionPlayerIdx != 2) {
+ int tmpVal = scene->getRandomCardFromHand(scene->_actionPlayerIdx);
+ scene->_actionCard3 = &scene->_gameBoardSide[scene->_actionPlayerIdx]._handCard[tmpVal];
+ }
+ scene->_actionItem.setAction(&scene->_action12);
+ noAction = false;
+ }
+ }
+ break;
+ case 3:
+ for (i = 0; i <= 3; i++) {
+ if (scene->_gameBoardSide[3]._handCard[i]._cardId == 27) {
+ found = true;
+ break;
+ }
+ }
+
+ if ((found) && (scene->getRandomCardFromHand(scene->_actionPlayerIdx) != -1)) {
+ scene->_actionCard1 = &scene->_gameBoardSide[3]._handCard[i];
+ scene->_actionCard2 = &scene->_gameBoardSide[3]._emptyStationPos;
+ if (scene->_actionPlayerIdx != 3) {
+ int tmpVal = scene->getRandomCardFromHand(scene->_actionPlayerIdx);
+ scene->_actionCard3 = &scene->_gameBoardSide[scene->_actionPlayerIdx]._handCard[tmpVal];
+ }
+ scene->_actionItem.setAction(&scene->_action12);
+ noAction = false;
+ }
+ break;
+ default:
+ break;
+ }
+
+ if (!noAction)
+ break;
+
+ if (scene->_actionPlayerIdx == 2) {
+ int count = 0;
+ if (scene->_actionVictimIdx != 2) {
+ for (i = 0; i <= 3; i++) {
+ if (scene->_gameBoardSide[scene->_actionVictimIdx]._handCard[i]._cardId != 0)
+ ++count;
+ }
+ }
+
+ if (count > 1) {
+ scene->subC4CD2();
+
+ found = false;
+ while (!found) {
+ switch (scene->_actionVictimIdx) {
+ case 0:
+ scene->actionDisplay(1330, 131, 159, 10, 1, 200, 0, 7, 0, 154, 154);
+ break;
+ case 1:
+ scene->actionDisplay(1330, 132, 159, 10, 1, 200, 0, 7, 0, 154, 154);
+ break;
+ case 3:
+ scene->actionDisplay(1330, 133, 159, 10, 1, 200, 0, 7, 0, 154, 154);
+ break;
+ default:
+ break;
+ }
+
+ Event event;
+ while (!g_globals->_events.getEvent(event, EVENT_BUTTON_DOWN | EVENT_KEYPRESS) && !g_vm->shouldQuit()) {
+ g_globals->_scenePalette.signalListeners();
+ R2_GLOBALS._sceneObjects->draw();
+ g_globals->_events.delay(g_globals->_sceneHandler->_delayTicks);
+ }
+
+ scene->_selectedCard._stationPos = event.mousePos;
+
+ found = false;
+
+ if (scene->_actionVictimIdx != 2) {
+ for (i = 0; i <= 3; i++) {
+ if (scene->_gameBoardSide[scene->_actionVictimIdx]._handCard[i].isIn(scene->_selectedCard._stationPos) && (scene->_gameBoardSide[scene->_actionVictimIdx]._handCard[i]._cardId != 0)) {
+ scene->_actionCard3 = &scene->_gameBoardSide[scene->_actionVictimIdx]._handCard[i];
+ found = true;
+ break;
+ }
+ }
+ }
+ } // while
+ scene->_displayHelpFl = true;
+ scene->subC4CEC();
+ } else if (scene->_actionVictimIdx != 2) {
+ int tmpVal = scene->getRandomCardFromHand(scene->_actionVictimIdx);
+ scene->_actionCard3 = &scene->_gameBoardSide[scene->_actionVictimIdx]._handCard[tmpVal];
+ }
+ }
+
+ scene->_actionCard1->_card.postInit();
+ scene->_actionCard1->_card.hide();
+ scene->_actionCard1->_card.setVisage(1332);
+ scene->_actionCard1->_card.setPosition(scene->_actionCard1->_stationPos, 0);
+ scene->_actionCard1->_card.fixPriority(170);
+ scene->_actionCard1->_card.setStrip2(1);
+ scene->_actionCard1->_cardId = scene->_actionCard3->_cardId;
+
+ scene->_actionCard3->_cardId = 0;
+ scene->_actionCard3->_card.remove();
+
+ scene->_animatedCard._card.setPosition(scene->_actionCard3->_stationPos, 0);
+ scene->_animatedCard._card.show();
+
+ NpcMover *mover = new NpcMover();
+ scene->_animatedCard._card.addMover(mover, &scene->_actionCard1->_stationPos, this);
+ }
+ break;
+ case 2:
+ scene->_animatedCard._card.hide();
+ switch (scene->_actionPlayerIdx) {
+ case 0:
+ scene->_actionCard1->_card.setFrame2(2);
+ scene->_actionCard1->_card.show();
+ break;
+ case 1:
+ scene->_actionCard1->_card.setFrame2(4);
+ scene->_actionCard1->_card.show();
+ break;
+ case 3:
+ scene->_actionCard1->_card.setFrame2(3);
+ scene->_actionCard1->_card.show();
+ break;
+ default:
+ scene->setAnimationInfo(scene->_actionCard1);
+ break;
+ }
+
+ scene->_currentPlayerNumb--;
+ scene->_showPlayerTurn = false;
+ scene->discardCard(scene->_actionCard2);
+ break;
+ default:
+ break;
+ }
+}
+
+// Pick a card in opponent hand
+void Scene1337::Action12::signal() {
+ Scene1337 *scene = (Scene1337 *)R2_GLOBALS._sceneManager._scene;
+
+ switch (_actionIndex++) {
+ case 0:
+ signal();
+ break;
+ case 1: {
+ scene->_availableCardsPile[scene->_currentDiscardIndex] = scene->_actionCard2->_cardId;
+ scene->_currentDiscardIndex++;
+ scene->_actionCard2->_cardId = scene->_actionCard1->_cardId;
+ scene->_actionCard1->_cardId = 0;
+ scene->_actionCard1->_card.remove();
+ scene->_animatedCard._card.setPosition(scene->_actionCard1->_stationPos, 0);
+ scene->_animatedCard._card.show();
+
+ NpcMover *mover = new NpcMover();
+ scene->_animatedCard._card.addMover(mover, &scene->_actionCard2->_stationPos, this);
+ }
+ break;
+ case 2:
+ scene->_animatedCard._card.hide();
+ scene->setAnimationInfo(scene->_actionCard2);
+ scene->_aSound1.play(58);
+ if (scene->_actionVictimIdx == 2) {
+ int count = 0;
+ int i = -1;
+ switch (scene->_actionPlayerIdx) {
+ case 0:
+ for (i = 0; i <= 3; i++) {
+ if (scene->_gameBoardSide[0]._handCard[i]._cardId != 0)
+ ++count;
+ }
+ break;
+ case 1:
+ for (i = 0; i <= 3; i++) {
+ // The original game was counting in the hand of player 3, which is obviously wrong
+ if (scene->_gameBoardSide[1]._handCard[i]._cardId != 0)
+ ++count;
+ }
+ break;
+ case 3:
+ for (i = 0; i <= 3; i++) {
+ if (scene->_gameBoardSide[3]._handCard[i]._cardId != 0)
+ ++count;
+ }
+ break;
+ default:
+ break;
+ }
+
+ if (count > 1) {
+ scene->subC4CD2();
+
+ bool found = false;
+
+ while (!found) {
+ switch (scene->_actionPlayerIdx) {
+ case 0:
+ scene->actionDisplay(1330, 131, 159, 10, 1, 200, 0, 7, 0, 154, 154);
+ break;
+ case 1:
+ scene->actionDisplay(1330, 132, 159, 10, 1, 200, 0, 7, 0, 154, 154);
+ break;
+ case 3:
+ scene->actionDisplay(1330, 133, 159, 10, 1, 200, 0, 7, 0, 154, 154);
+ break;
+ default:
+ break;
+ }
+
+ Event event;
+ while (!g_globals->_events.getEvent(event, EVENT_BUTTON_DOWN | EVENT_KEYPRESS) && !g_vm->shouldQuit()) {
+ g_globals->_scenePalette.signalListeners();
+ R2_GLOBALS._sceneObjects->draw();
+ g_globals->_events.delay(g_globals->_sceneHandler->_delayTicks);
+ }
+
+ scene->_selectedCard._stationPos = event.mousePos;
+
+ switch (scene->_actionPlayerIdx) {
+ case 0:
+ for (i = 0; i <= 3; i++) {
+ if (scene->_gameBoardSide[0]._handCard[i].isIn(scene->_selectedCard._stationPos) && (scene->_gameBoardSide[0]._handCard[i]._cardId != 0)) {
+ found = true;
+ scene->_actionCard3 = &scene->_gameBoardSide[0]._handCard[i];
+ break;
+ }
+ }
+ break;
+ case 1:
+ for (i = 0; i <= 3; i++) {
+ if (scene->_gameBoardSide[1]._handCard[i].isIn(scene->_selectedCard._stationPos) && (scene->_gameBoardSide[1]._handCard[i]._cardId != 0)) {
+ found = true;
+ scene->_actionCard3 = &scene->_gameBoardSide[1]._handCard[i];
+ break;
+ }
+ }
+ break;
+ case 3:
+ for (i = 0; i <= 3; i++) {
+ if (scene->_gameBoardSide[3]._handCard[i].isIn(scene->_selectedCard._stationPos) && (scene->_gameBoardSide[3]._handCard[i]._cardId != 0)) {
+ found = true;
+ scene->_actionCard3 = &scene->_gameBoardSide[3]._handCard[i];
+ break;
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ scene->subC4CEC();
+ } else {
+ switch (scene->_actionPlayerIdx) {
+ case 0:
+ scene->_actionCard3 = &scene->_gameBoardSide[0]._handCard[scene->getRandomCardFromHand(0)];
+ break;
+ case 1:
+ scene->_actionCard3 = &scene->_gameBoardSide[1]._handCard[scene->getRandomCardFromHand(1)];
+ break;
+ case 3:
+ scene->_actionCard3 = &scene->_gameBoardSide[3]._handCard[scene->getRandomCardFromHand(3)];
+ break;
+ default:
+ break;
+ }
+ }
+
+ scene->_actionCard1->_card.postInit();
+ scene->_actionCard1->_card.hide();
+ scene->_actionCard1->_card.setVisage(1332);
+ scene->_actionCard1->_card.setPosition(scene->_actionCard1->_stationPos);
+ scene->_actionCard1->_card.fixPriority(170);
+ scene->_actionCard1->_card.setStrip2(1);
+ scene->_actionCard1->_cardId = scene->_actionCard3->_cardId;
+
+ scene->_actionCard3->_cardId = 0;
+ scene->_actionCard3->_card.remove();
+
+ scene->_animatedCard._card.setPosition(scene->_actionCard3->_stationPos);
+ scene->_animatedCard._card.show();
+ scene->_aSound1.play(57);
+
+ NpcMover *mover = new NpcMover();
+ scene->_animatedCard._card.addMover(mover, &scene->_actionCard1->_stationPos, this);
+ }
+ break;
+ case 3:
+ scene->_animatedCard._card.hide();
+ switch (scene->_actionVictimIdx) {
+ case 0:
+ scene->_actionCard1->_card.setFrame2(2);
+ scene->_actionCard1->_card.show();
+ break;
+ case 1:
+ scene->_actionCard1->_card.setFrame2(4);
+ scene->_actionCard1->_card.show();
+ break;
+ case 3:
+ scene->_actionCard1->_card.setFrame2(3);
+ scene->_actionCard1->_card.show();
+ break;
+ default:
+ scene->setAnimationInfo(scene->_actionCard1);
+ break;
+ }
+ scene->discardCard(scene->_actionCard2);
+ break;
+ default:
+ break;
+ }
+}
+
+// Handle the animations of the interceptor card
+void Scene1337::Action13::signal() {
+ Scene1337 *scene = (Scene1337 *)R2_GLOBALS._sceneManager._scene;
+
+ switch (_actionIndex++) {
+ case 0: {
+ scene->_availableCardsPile[scene->_currentDiscardIndex] = scene->_actionCard2->_cardId;
+ scene->_currentDiscardIndex--;
+
+ scene->_actionCard2->_cardId = scene->_actionCard1->_cardId;
+
+ scene->_actionCard1->_cardId = 0;
+ scene->_actionCard1->_card.remove();
+
+ scene->_animatedCard._card.setPosition(scene->_actionCard1->_stationPos, 0);
+ scene->_animatedCard._card.show();
+
+ NpcMover *mover = new NpcMover();
+ scene->_animatedCard._card.addMover(mover, &scene->_actionCard2->_stationPos, this);
+ }
+ break;
+ case 1:
+ scene->_animatedCard._card.hide();
+ scene->setAnimationInfo(scene->_actionCard2);
+ scene->_aSound1.play(58);
+ signal();
+ break;
+ case 2:
+ scene->discardCard(scene->_actionCard2);
+ break;
+ default:
+ break;
+ }
+}
+
+void Scene1337::postInit(SceneObjectList *OwnerList) {
+// In the original, may be found in subPostInit.
+// Without it, enableControl asserts
+ loadScene(1330);
+ R2_GLOBALS._uiElements._active = false;
+ SceneExt::postInit();
+//
+
+ // Hide the user interface
+ BF_GLOBALS._interfaceY = SCREEN_HEIGHT;
+ R2_GLOBALS._uiElements._visible = false;
+
+ R2_GLOBALS._player.enableControl();
+ R2_GLOBALS._player._canWalk = false;
+ R2_GLOBALS._player._uiEnabled = false;
+
+ _delayedFunction = nullptr;
+
+ _actionCard1 = nullptr;
+ _actionCard2 = nullptr;
+ _actionCard3 = nullptr;
+
+ _gameBoardSide[2]._handCard[0]._stationPos = Common::Point(10, 174);
+ _gameBoardSide[2]._handCard[1]._stationPos = Common::Point(37, 174);
+ _gameBoardSide[2]._handCard[2]._stationPos = Common::Point(64, 174);
+ _gameBoardSide[2]._handCard[3]._stationPos = Common::Point(91, 174);
+
+ _gameBoardSide[2]._outpostStation[0]._stationPos = Common::Point(119, 174);
+ _gameBoardSide[2]._outpostStation[1]._stationPos = Common::Point(119, 148);
+ _gameBoardSide[2]._outpostStation[2]._stationPos = Common::Point(119, 122);
+ _gameBoardSide[2]._outpostStation[3]._stationPos = Common::Point(145, 122);
+ _gameBoardSide[2]._outpostStation[4]._stationPos = Common::Point(171, 122);
+ _gameBoardSide[2]._outpostStation[5]._stationPos = Common::Point(171, 148);
+ _gameBoardSide[2]._outpostStation[6]._stationPos = Common::Point(171, 174);
+ _gameBoardSide[2]._outpostStation[7]._stationPos = Common::Point(145, 174);
+
+ _gameBoardSide[2]._delayCard._stationPos = Common::Point(199, 174);
+
+ _gameBoardSide[2]._emptyStationPos._stationPos = Common::Point(145, 148);
+
+ _gameBoardSide[2]._card1Pos = Common::Point(10, 174);
+ _gameBoardSide[2]._card2Pos = Common::Point(37, 174);
+ _gameBoardSide[2]._card3Pos = Common::Point(64, 174);
+ _gameBoardSide[2]._card4Pos = Common::Point(91, 174);
+ _gameBoardSide[2]._frameNum = 2;
+
+ _gameBoardSide[3]._handCard[0]._stationPos = Common::Point(14, 14);
+ _gameBoardSide[3]._handCard[1]._stationPos = Common::Point(14, 36);
+ _gameBoardSide[3]._handCard[2]._stationPos = Common::Point(14, 58);
+ _gameBoardSide[3]._handCard[3]._stationPos = Common::Point(14, 80);
+
+ _gameBoardSide[3]._outpostStation[0]._stationPos = Common::Point(37, 66);
+ _gameBoardSide[3]._outpostStation[1]._stationPos = Common::Point(63, 66);
+ _gameBoardSide[3]._outpostStation[2]._stationPos = Common::Point(89, 66);
+ _gameBoardSide[3]._outpostStation[3]._stationPos = Common::Point(89, 92);
+ _gameBoardSide[3]._outpostStation[4]._stationPos = Common::Point(89, 118);
+ _gameBoardSide[3]._outpostStation[5]._stationPos = Common::Point(63, 118);
+ _gameBoardSide[3]._outpostStation[6]._stationPos = Common::Point(37, 118);
+ _gameBoardSide[3]._outpostStation[7]._stationPos = Common::Point(37, 92);
+
+ _gameBoardSide[3]._delayCard._stationPos = Common::Point(37, 145);
+
+ _gameBoardSide[3]._emptyStationPos._stationPos = Common::Point(63, 92);
+
+ _gameBoardSide[3]._card1Pos = Common::Point(14, 14);
+ _gameBoardSide[3]._card2Pos = Common::Point(14, 36);
+ _gameBoardSide[3]._card3Pos = Common::Point(14, 58);
+ _gameBoardSide[3]._card4Pos = Common::Point(14, 80);
+ _gameBoardSide[3]._frameNum = 3;
+
+ _gameBoardSide[0]._handCard[0]._stationPos = Common::Point(280, 5);
+ _gameBoardSide[0]._handCard[1]._stationPos = Common::Point(253, 5);
+ _gameBoardSide[0]._handCard[2]._stationPos = Common::Point(226, 5);
+ _gameBoardSide[0]._handCard[3]._stationPos = Common::Point(199, 5);
+
+ _gameBoardSide[0]._outpostStation[0]._stationPos = Common::Point(171, 16);
+ _gameBoardSide[0]._outpostStation[1]._stationPos = Common::Point(171, 42);
+ _gameBoardSide[0]._outpostStation[2]._stationPos = Common::Point(171, 68);
+ _gameBoardSide[0]._outpostStation[3]._stationPos = Common::Point(145, 68);
+ _gameBoardSide[0]._outpostStation[4]._stationPos = Common::Point(119, 68);
+ _gameBoardSide[0]._outpostStation[5]._stationPos = Common::Point(119, 42);
+ _gameBoardSide[0]._outpostStation[6]._stationPos = Common::Point(119, 16);
+ _gameBoardSide[0]._outpostStation[7]._stationPos = Common::Point(145, 16);
+
+ _gameBoardSide[0]._delayCard._stationPos = Common::Point(91, 16);
+
+ _gameBoardSide[0]._emptyStationPos._stationPos = Common::Point(145, 42);
+
+ _gameBoardSide[0]._card1Pos = Common::Point(280, 5);
+ _gameBoardSide[0]._card2Pos = Common::Point(253, 5);
+ _gameBoardSide[0]._card3Pos = Common::Point(226, 5);
+ _gameBoardSide[0]._card4Pos = Common::Point(199, 5);
+ _gameBoardSide[0]._frameNum = 2;
+
+ _gameBoardSide[1]._handCard[0]._stationPos = Common::Point(283, 146);
+ _gameBoardSide[1]._handCard[1]._stationPos = Common::Point(283, 124);
+ _gameBoardSide[1]._handCard[2]._stationPos = Common::Point(283, 102);
+ _gameBoardSide[1]._handCard[3]._stationPos = Common::Point(283, 80);
+
+ _gameBoardSide[1]._outpostStation[0]._stationPos = Common::Point(253, 122);
+ _gameBoardSide[1]._outpostStation[1]._stationPos = Common::Point(227, 122);
+ _gameBoardSide[1]._outpostStation[2]._stationPos = Common::Point(201, 122);
+ _gameBoardSide[1]._outpostStation[3]._stationPos = Common::Point(201, 96);
+ _gameBoardSide[1]._outpostStation[4]._stationPos = Common::Point(201, 70);
+ _gameBoardSide[1]._outpostStation[5]._stationPos = Common::Point(227, 70);
+ _gameBoardSide[1]._outpostStation[6]._stationPos = Common::Point(253, 70);
+ _gameBoardSide[1]._outpostStation[7]._stationPos = Common::Point(253, 96);
+
+ _gameBoardSide[1]._delayCard._stationPos = Common::Point(253, 43);
+
+ _gameBoardSide[1]._emptyStationPos._stationPos = Common::Point(227, 96);
+
+ _gameBoardSide[1]._card1Pos = Common::Point(283, 146);
+ _gameBoardSide[1]._card2Pos = Common::Point(283, 124);
+ _gameBoardSide[1]._card3Pos = Common::Point(283, 102);
+ _gameBoardSide[1]._card4Pos = Common::Point(283, 80);
+ _gameBoardSide[1]._frameNum = 4;
+
+ subPostInit();
+
+ _stockPile.postInit();
+}
+
+void Scene1337::remove() {
+ if (R2_GLOBALS._v57709 > 1) {
+ subD1917();
+ subD1940(false);
+ }
+
+ R2_GLOBALS._uiElements._active = true;
+ R2_GLOBALS._uiElements._visible = true;
+ SceneExt::remove();
+}
+
+void Scene1337::process(Event &event) {
+ if (event.eventType == EVENT_BUTTON_DOWN) {
+ if (event.btnState == BTNSHIFT_RIGHT) {
+ updateCursorId(R2_GLOBALS._mouseCursorId, true);
+ event.handled = true;
+ } else if (_delayedFunction) {
+ FunctionPtrType tmpFctPtr = _delayedFunction;
+ _delayedFunction = nullptr;
+ (this->*tmpFctPtr)();
+ event.handled = true;
+ }
+ } else if (event.eventType == EVENT_KEYPRESS) {
+ if (event.kbd.keycode == Common::KEYCODE_SPACE) {
+ if (_delayedFunction) {
+ FunctionPtrType tmpFctPtr = _delayedFunction;
+ _delayedFunction = nullptr;
+ (this->*tmpFctPtr)();
+ event.handled = true;
+ }
+ } else
+ warning("Fixme: Find proper keycode value");
+ }
+
+ if (!event.handled)
+ Scene::process(event);
+}
+
+void Scene1337::dispatch() {
+ if (!_instructionsDisplayedFl) {
+ ++_instructionsWaitCount;
+ if (_instructionsWaitCount == 4) {
+ _instructionsDisplayedFl = true;
+ suggestInstructions();
+ }
+ }
+
+ // The following code is in the original in sceneHandler::process(),
+ // which is terrible as it's checked in every scene of the game.
+ setCursorData(5, _cursorCurStrip, _cursorCurFrame);
+ //
+
+ Scene::dispatch();
+}
+
+void Scene1337::actionDisplay(int resNum, int lineNum, int x, int y, int keepOnScreen, int width, int textMode, int fontNum, int colFG, int colBGExt, int colFGExt) {
+ // TODO: Check if it's normal that arg5 is unused and replaced by an hardcoded 0 value
+ // May hide an original bug
+
+ SceneItem::display(resNum, lineNum, SET_X, x, SET_Y, y, SET_KEEP_ONSCREEN, 0,
+ SET_WIDTH, width, SET_POS_MODE, -1, SET_TEXT_MODE, textMode,
+ SET_FONT, fontNum, SET_FG_COLOR, colFG, SET_EXT_BGCOLOR, colBGExt,
+ SET_EXT_FGCOLOR, colFGExt, LIST_END);
+}
+
+void Scene1337::setAnimationInfo(Card *card) {
+ if (!card)
+ return;
+
+ if (card->_cardId > 25) {
+ card->_card.setStrip2(4);
+ card->_card.setFrame(card->_cardId - 25);
+ } else if (card->_cardId > 9) {
+ card->_card.setStrip2(3);
+ card->_card.setFrame(card->_cardId - 9);
+ } else {
+ card->_card.setStrip2(2);
+ card->_card.setFrame(card->_cardId);
+ }
+
+ card->_card.show();
+ R2_GLOBALS._sceneObjects->draw();
+}
+
+void Scene1337::handleNextTurn() {
+ switch (_winnerId) {
+ case -1:
+ ++_currentPlayerNumb;
+ if (_currentPlayerNumb > 3)
+ _currentPlayerNumb = 0;
+
+ if (_showPlayerTurn) {
+ _currentPlayerArrow.show();
+ switch (_currentPlayerNumb) {
+ case 0:
+ _currentPlayerArrow.setStrip(3);
+ break;
+ case 1:
+ _currentPlayerArrow.setStrip(4);
+ break;
+ case 2:
+ subD1975(174, 107);
+ _currentPlayerArrow.setStrip(1);
+ break;
+ case 3:
+ subC4CEC();
+ _currentPlayerArrow.setStrip(2);
+ break;
+ default:
+ break;
+ }
+
+ if (!_autoplay)
+ _delayedFunction = &Scene1337::handlePlayerTurn;
+ else
+ handlePlayerTurn();
+ } else {
+ handlePlayerTurn();
+ }
+ break;
+ case 0:
+ _aSound2.play(62);
+ actionDisplay(1330, 135, 159, 10, 1, 200, 0, 7, 0, 154, 154);
+ actionDisplay(1330, 121, 20, 99, 1, 136, 0, 7, 0, 172, 172);
+ actionDisplay(1330, 122, 300, 99, 1, 136, 0, 7, 0, 117, 117);
+ R2_GLOBALS._sceneObjects->draw();
+ actionDisplay(1330, 123, 159, 134, 1, 200, 0, 7, 0, 105, 105);
+ break;
+ case 1:
+ _aSound2.play(62);
+ actionDisplay(1330, 151, 300, 99, 1, 136, 0, 7, 0, 117, 117);
+ actionDisplay(1330, 118, 20, 99, 1, 136, 0, 7, 0, 172, 172);
+ actionDisplay(1330, 119, 159, 10, 1, 200, 0, 7, 0, 154, 154);
+ R2_GLOBALS._sceneObjects->draw();
+ actionDisplay(1330, 120, 159, 134, 1, 200, 0, 7, 0, 105, 105);
+ break;
+ case 2:
+ _aSound2.play(62);
+ actionDisplay(1330, 134, 159, 134, 1, 200, 0, 7, 0, 105, 105);
+ actionDisplay(1330, 124, 20, 99, 1, 136, 0, 7, 0, 172, 172);
+ actionDisplay(1330, 126, 159, 10, 1, 200, 0, 7, 0, 154, 154);
+ R2_GLOBALS._sceneObjects->draw();
+ actionDisplay(1330, 125, 300, 99, 1, 136, 0, 7, 0, 117, 117);
+ break;
+ case 3:
+ _aSound2.play(62);
+ actionDisplay(1330, 150, 20, 99, 1, 136, 0, 7, 0, 172, 172);
+ actionDisplay(1330, 115, 300, 99, 1, 136, 0, 7, 0, 117, 117);
+ actionDisplay(1330, 116, 159, 10, 1, 200, 0, 7, 0, 154, 154);
+ R2_GLOBALS._sceneObjects->draw();
+ actionDisplay(1330, 117, 159, 134, 1, 200, 0, 7, 0, 105, 105);
+ break;
+ default:
+ break;
+ }
+
+ if (_winnerId != -1)
+ R2_GLOBALS._sceneManager.changeScene(125);
+
+}
+
+void Scene1337::handlePlayerTurn() {
+ if (_showPlayerTurn)
+ _currentPlayerArrow.hide();
+
+ switch (_currentPlayerNumb) {
+ case 2:
+ subC4CD2();
+ if (_displayHelpFl)
+ actionDisplay(1330, 114, 159, 10, 1, 200, 0, 7, 0, 154, 154);
+ _displayHelpFl = false;
+ // No break on purpose
+ case 0:
+ // No break on purpose
+ case 1:
+ // No break on purpose
+ case 3:
+ _actionItem.setAction(&_action4);
+ default:
+ break;
+ }
+
+ _showPlayerTurn = true;
+
+}
+
+bool Scene1337::isStationCard(int cardId) {
+ switch (cardId) {
+ case 10:
+ // No break on purpose
+ case 12:
+ // No break on purpose
+ case 15:
+ // No break on purpose
+ case 17:
+ // No break on purpose
+ case 18:
+ // No break on purpose
+ case 19:
+ // No break on purpose
+ case 20:
+ // No break on purpose
+ case 21:
+ return true;
+ default:
+ return false;
+ }
+}
+
+bool Scene1337::isStopConstructionCard(int cardId) {
+ switch (cardId) {
+ case 11:
+ // No break on purpose
+ case 14:
+ // No break on purpose
+ case 16:
+ // No break on purpose
+ case 24:
+ return true;
+ default:
+ return false;
+ }
+}
+
+int Scene1337::getStationId(int playerId, int handCardId) {
+ if ((_gameBoardSide[playerId]._handCard[handCardId]._cardId > 1) && (_gameBoardSide[playerId]._handCard[handCardId]._cardId <= 9))
+ return handCardId;
+
+ return -1;
+}
+
+int Scene1337::findPlatformCardInHand(int playerId) {
+ for (int i = 0; i <= 3; i++) {
+ if (_gameBoardSide[playerId]._handCard[i]._cardId == 1)
+ return i;
+ }
+
+ return -1;
+}
+
+int Scene1337::findMeteorCardInHand(int playerId) {
+ for (int i = 0; i <= 3; i++) {
+ if (_gameBoardSide[playerId]._handCard[i]._cardId == 13)
+ return i;
+ }
+
+ return -1;
+}
+
+int Scene1337::findThieftCardInHand(int playerId) {
+ for (int i = 0; i <= 3; i++) {
+ if (_gameBoardSide[playerId]._handCard[i]._cardId == 25)
+ return i;
+ }
+
+ return -1;
+}
+
+int Scene1337::isDelayCard(int cardId) {
+ switch (cardId) {
+ case 11:
+ // No break on purpose
+ case 14:
+ // No break on purpose
+ case 16:
+ // No break on purpose
+ case 24:
+ return cardId;
+ break;
+ default:
+ return -1;
+ break;
+ }
+}
+
+int Scene1337::getStationCardId(int cardId) {
+ switch (cardId) {
+ case 10:
+ // No break on purpose
+ case 12:
+ // No break on purpose
+ case 15:
+ // No break on purpose
+ case 17:
+ // No break on purpose
+ case 18:
+ // No break on purpose
+ case 19:
+ // No break on purpose
+ case 20:
+ // No break on purpose
+ case 21:
+ return cardId;
+ default:
+ return -1;
+ }
+}
+
+void Scene1337::handlePlayer01Discard(int playerId) {
+ switch (playerId) {
+ case 0:
+ for (int i = 0; i <= 3; i++) {
+ if (getStationCardId(_gameBoardSide[playerId]._handCard[i]._cardId) != -1) {
+ discardCard(&_gameBoardSide[playerId]._handCard[i]);
+ return;
+ }
+ }
+
+ for (int i = 0; i <= 3; i++) {
+ if (isDelayCard(_gameBoardSide[playerId]._handCard[i]._cardId) != -1) {
+ discardCard(&_gameBoardSide[playerId]._handCard[i]);
+ return;
+ }
+ }
+
+ for (int i = 0; i <= 3; i++) {
+ // Outpost Card
+ if ((_gameBoardSide[playerId]._handCard[i]._cardId > 1) && (_gameBoardSide[playerId]._handCard[i]._cardId <= 9)) {
+ discardCard(&_gameBoardSide[playerId]._handCard[i]);
+ return;
+ }
+ }
+
+ for (int i = 0; i <= 3; i++) {
+ if ((_gameBoardSide[playerId]._handCard[i]._cardId >= 26) && (_gameBoardSide[playerId]._handCard[i]._cardId <= 33)) {
+ discardCard(&_gameBoardSide[playerId]._handCard[i]);
+ return;
+ }
+ }
+
+ for (int i = 0; i <= 3; i++) {
+ // Station Card
+ if (_gameBoardSide[playerId]._handCard[i]._cardId == 1) {
+ discardCard(&_gameBoardSide[playerId]._handCard[i]);
+ return;
+ }
+ }
+
+ for (int i = 0; i <= 3; i++) {
+ // Thief card
+ if (_gameBoardSide[playerId]._handCard[i]._cardId == 25) {
+ discardCard(&_gameBoardSide[playerId]._handCard[i]);
+ return;
+ }
+ }
+
+ for (int i = 0; i <= 3; i++) {
+ // Meteor Card
+ if (_gameBoardSide[playerId]._handCard[i]._cardId == 13) {
+ discardCard(&_gameBoardSide[playerId]._handCard[i]);
+ return;
+ }
+ }
+ break;
+ case 1:
+ for (int i = 0; i <= 3; i++) {
+ if ((_gameBoardSide[playerId]._handCard[i]._cardId >= 26) && (_gameBoardSide[playerId]._handCard[i]._cardId <= 33)) {
+ discardCard(&_gameBoardSide[playerId]._handCard[i]);
+ return;
+ }
+ }
+
+ for (int i = 0; i <= 3; i++) {
+ // Station Card
+ if (_gameBoardSide[playerId]._handCard[i]._cardId == 1) {
+ discardCard(&_gameBoardSide[playerId]._handCard[i]);
+ return;
+ }
+ }
+
+ for (int i = 0; i <= 3; i++) {
+ // Outpost Card
+ if ((_gameBoardSide[playerId]._handCard[i]._cardId > 1) && (_gameBoardSide[playerId]._handCard[i]._cardId <= 9)) {
+ discardCard(&_gameBoardSide[playerId]._handCard[i]);
+ return;
+ }
+ }
+
+ for (int i = 0; i <= 3; i++) {
+ if (getStationCardId(_gameBoardSide[playerId]._handCard[i]._cardId) != -1) {
+ discardCard(&_gameBoardSide[playerId]._handCard[i]);
+ return;
+ }
+ }
+
+ for (int i = 0; i <= 3; i++) {
+ if (isDelayCard(_gameBoardSide[playerId]._handCard[i]._cardId) != -1) {
+ discardCard(&_gameBoardSide[playerId]._handCard[i]);
+ return;
+ }
+ }
+
+ for (int i = 0; i <= 3; i++) {
+ // Thief card
+ if (_gameBoardSide[playerId]._handCard[i]._cardId == 25) {
+ discardCard(&_gameBoardSide[playerId]._handCard[i]);
+ return;
+ }
+ }
+
+ for (int i = 0; i <= 3; i++) {
+ // Meteor Card
+ if (_gameBoardSide[playerId]._handCard[i]._cardId == 13) {
+ discardCard(&_gameBoardSide[playerId]._handCard[i]);
+ return;
+ }
+ }
+
+ break;
+ default:
+ break;
+ }
+}
+
+void Scene1337::playThieftCard(int playerId, Card *card, int victimId) {
+ _actionPlayerIdx = playerId;
+ _actionVictimIdx = victimId;
+
+ int randIndx;
+
+ for (;;) {
+ randIndx = R2_GLOBALS._randomSource.getRandomNumber(3);
+ if (_gameBoardSide[victimId]._handCard[randIndx]._cardId != 0)
+ break;
+ }
+
+ _actionCard1 = card;
+ _actionCard2 = &_gameBoardSide[victimId]._emptyStationPos;
+ _actionCard3 = &_gameBoardSide[victimId]._handCard[randIndx];
+
+ _actionItem.setAction(&_action11);
+}
+
+int Scene1337::getPreventionCardId(int cardId) {
+ int retVal;
+
+ switch (cardId) {
+ case 10:
+ retVal = 2;
+ break;
+ case 12:
+ retVal = 3;
+ break;
+ case 15:
+ retVal = 5;
+ break;
+ case 17:
+ retVal = 9;
+ break;
+ case 18:
+ retVal = 6;
+ break;
+ case 19:
+ retVal = 4;
+ break;
+ case 20:
+ retVal = 8;
+ break;
+ case 21:
+ retVal = 7;
+ break;
+ default:
+ retVal = -1;
+ }
+
+ return retVal;
+}
+
+bool Scene1337::isAttackPossible(int victimId, int cardId) {
+ if (victimId < 0 || victimId >= ARRAYSIZE(_gameBoardSide))
+ error("Scene1337::isAttackPossible() victimId:%d out of range 0 to %d", victimId, ARRAYSIZE(_gameBoardSide)-1);
+
+ for (int i = 0; i <= 7; i++) {
+ if (_gameBoardSide[victimId]._outpostStation[i]._cardId != 0) {
+ if (getPreventionCardId(cardId) == _gameBoardSide[victimId]._outpostStation[i]._cardId)
+ return false;
+ }
+ }
+ return true;
+}
+
+int Scene1337::getPlayerWithOutpost(int playerId) {
+ int randPlayerId = R2_GLOBALS._randomSource.getRandomNumber(3);
+
+ for (int i = 0; i <= 3; i++) {
+ if (randPlayerId != playerId) {
+ for (int j = 0; j <= 7; j++) {
+ if (_gameBoardSide[randPlayerId]._outpostStation[j]._cardId != 0)
+ return randPlayerId;
+ }
+ }
+
+ if (playerId == 1) {
+ randPlayerId--;
+ if (randPlayerId < 0)
+ randPlayerId = 3;
+ } else {
+ ++randPlayerId;
+ if (randPlayerId > 3)
+ randPlayerId = 0;
+ }
+ }
+
+ return -1;
+}
+
+bool Scene1337::checkAntiDelayCard(int delayCardId, int cardId) {
+ if ((delayCardId == 11) && (cardId == 26)) // Diplomacy
+ return true;
+
+ if ((delayCardId == 14) && (cardId == 30)) // Cure
+ return true;
+
+ if ((delayCardId == 16) && (cardId == 32)) // Agreement
+ return true;
+
+ if ((delayCardId == 24) && (cardId == 28)) // Innovation
+ return true;
+
+ return false;
+}
+
+void Scene1337::playStationCard(Card *station, Card *platform) {
+ _actionCard1 = station;
+ _actionCard2 = platform;
+ _actionItem.setAction(&_action7);
+}
+
+int Scene1337::getRandomCardFromHand(int playerId) {
+ if ( (_gameBoardSide[playerId]._handCard[0]._cardId == 0)
+ && (_gameBoardSide[playerId]._handCard[1]._cardId == 0)
+ && (_gameBoardSide[playerId]._handCard[2]._cardId == 0)
+ && (_gameBoardSide[playerId]._handCard[3]._cardId == 0))
+ return -1;
+
+ int randIndx;
+ for (;;) {
+ randIndx = R2_GLOBALS._randomSource.getRandomNumber(3);
+ if (_gameBoardSide[playerId]._handCard[randIndx]._cardId != 0)
+ break;
+ }
+
+ return randIndx;
+}
+
+void Scene1337::playPlatformCard(Card *card, Card *dest) {
+ _actionCard1 = card;
+ _actionCard2 = dest;
+
+ _actionItem.setAction(&_action6);
+}
+
+void Scene1337::playDelayCard(Card *card, Card *dest) {
+ _actionCard1 = card;
+ _actionCard2 = dest;
+
+ _actionItem.setAction(&_action9);
+}
+
+void Scene1337::playAntiDelayCard(Card *card, Card *dest) {
+ _actionCard1 = card;
+ _actionCard2 = dest;
+
+ _actionItem.setAction(&_action8);
+
+ // WORKAROUND: Restore the default cursor and for a call to signal.
+ // This works around the cursor caching we got rid of, and avoid
+ // the game ends in an eternal loop when a player reacts to another player
+ // attack.
+ setCursorData(5, 1, 4);
+ signal();
+}
+
+
+Scene1337::Card *Scene1337::getStationCard(int playerId) {
+ for (int i = 0; i <= 7; i++) {
+ if ((_gameBoardSide[playerId]._outpostStation[i]._cardId >= 1) && (_gameBoardSide[playerId]._outpostStation[i]._cardId <= 9))
+ return &_gameBoardSide[playerId]._outpostStation[i];
+ }
+
+ return nullptr;
+}
+
+void Scene1337::playCentralOutpostCard(Card *card, int playerId) {
+ _actionCard1 = card;
+ _actionCard2 = getStationCard(playerId);
+ _actionCard3 = &_gameBoardSide[playerId]._emptyStationPos;
+ _actionPlayerIdx = playerId;
+ _actionItem.setAction(&_action10);
+}
+
+void Scene1337::discardCard(Card *card) {
+ _actionCard1 = card;
+
+ _actionItem.setAction(&_action5);
+}
+
+void Scene1337::subC4CD2() {
+ if (R2_GLOBALS._v57709 > 0) {
+ subD1917();
+ subD1940(false); // _v5780C--
+ }
+}
+
+void Scene1337::subC4CEC() {
+ if (R2_GLOBALS._v57709 == 0) {
+ subD18F5();
+ subD1940(true); // _v5780C++
+ }
+}
+
+// Play Interceptor card
+void Scene1337::playInterceptorCard(Card *subObj1, Card *subObj2) {
+ _actionCard1 = subObj1;
+ _actionCard2 = subObj2;
+
+ _actionItem.setAction(&_action13);
+}
+
+void Scene1337::displayDialog(int dialogNumb) {
+ switch (dialogNumb - 1) {
+ case 0:
+ actionDisplay(1330, 53, 159, 10, 1, 200, 0, 7, 0, 154, 154);
+ break;
+ case 1:
+ actionDisplay(1330, 57, 159, 10, 1, 200, 0, 7, 0, 154, 154);
+ break;
+ case 2:
+ actionDisplay(1330, 58, 159, 10, 1, 200, 0, 7, 0, 154, 154);
+ break;
+ case 3:
+ actionDisplay(1330, 59, 159, 10, 1, 200, 0, 7, 0, 154, 154);
+ break;
+ case 4:
+ actionDisplay(1330, 60, 159, 10, 1, 200, 0, 7, 0, 154, 154);
+ break;
+ case 5:
+ actionDisplay(1330, 61, 159, 10, 1, 200, 0, 7, 0, 154, 154);
+ break;
+ case 6:
+ actionDisplay(1330, 62, 159, 10, 1, 200, 0, 7, 0, 154, 154);
+ break;
+ case 7:
+ actionDisplay(1330, 63, 159, 10, 1, 200, 0, 7, 0, 154, 154);
+ break;
+ case 8:
+ actionDisplay(1330, 64, 159, 10, 1, 200, 0, 7, 0, 154, 154);
+ break;
+ case 9:
+ actionDisplay(1330, 65, 159, 10, 1, 200, 0, 7, 0, 154, 154);
+ break;
+ case 10:
+ actionDisplay(1330, 67, 159, 10, 1, 200, 0, 7, 0, 154, 154);
+ break;
+ case 11:
+ actionDisplay(1330, 69, 159, 10, 1, 200, 0, 7, 0, 154, 154);
+ break;
+ case 12:
+ actionDisplay(1330, 71, 159, 10, 1, 200, 0, 7, 0, 154, 154);
+ actionDisplay(1330, 72, 159, 10, 1, 200, 0, 7, 0, 154, 154);
+ actionDisplay(1330, 73, 159, 10, 1, 200, 0, 7, 0, 154, 154);
+ break;
+ case 13:
+ actionDisplay(1330, 79, 159, 10, 1, 200, 0, 7, 0, 154, 154);
+ break;
+ case 14:
+ actionDisplay(1330, 81, 159, 10, 1, 200, 0, 7, 0, 154, 154);
+ break;
+ case 15:
+ actionDisplay(1330, 83, 159, 10, 1, 200, 0, 7, 0, 154, 154);
+ break;
+ case 16:
+ actionDisplay(1330, 85, 159, 10, 1, 200, 0, 7, 0, 154, 154);
+ break;
+ case 17:
+ actionDisplay(1330, 87, 159, 10, 1, 200, 0, 7, 0, 154, 154);
+ break;
+ case 18:
+ actionDisplay(1330, 89, 159, 10, 1, 200, 0, 7, 0, 154, 154);
+ break;
+ case 19:
+ actionDisplay(1330, 91, 159, 10, 1, 200, 0, 7, 0, 154, 154);
+ break;
+ case 20:
+ actionDisplay(1330, 93, 159, 10, 1, 200, 0, 7, 0, 154, 154);
+ break;
+ case 23:
+ actionDisplay(1330, 95, 159, 10, 1, 200, 0, 7, 0, 154, 154);
+ break;
+ case 24:
+ actionDisplay(1330, 97, 159, 10, 1, 200, 0, 7, 0, 154, 154);
+ break;
+ case 25:
+ actionDisplay(1330, 104, 159, 10, 1, 200, 0, 7, 0, 154, 154);
+ break;
+ case 26:
+ actionDisplay(1330, 105, 159, 10, 1, 200, 0, 7, 0, 154, 154);
+ actionDisplay(1330, 106, 159, 10, 1, 200, 0, 7, 0, 154, 154);
+ break;
+ case 27:
+ actionDisplay(1330, 110, 159, 10, 1, 200, 0, 7, 0, 154, 154);
+ break;
+ case 28:
+ actionDisplay(1330, 108, 159, 10, 1, 200, 0, 7, 0, 154, 154);
+ actionDisplay(1330, 109, 159, 10, 1, 200, 0, 7, 0, 154, 154);
+ break;
+ case 29:
+ actionDisplay(1330, 111, 159, 10, 1, 200, 0, 7, 0, 154, 154);
+ break;
+ case 31:
+ actionDisplay(1330, 112, 159, 10, 1, 200, 0, 7, 0, 154, 154);
+ break;
+ default:
+ break;
+ }
+}
+
+void Scene1337::subPostInit() {
+ R2_GLOBALS._v57709 = 0;
+ R2_GLOBALS._v5780C = 0;
+ updateCursorId(1, false);
+ subD1940(true); // _v5780C++
+ subD18F5();
+
+// loadScene(1330);
+// SceneExt::postInit();
+
+ R2_GLOBALS._scenePalette.addRotation(224, 235, 1);
+
+ _availableCardsPile[0] = 1;
+ _availableCardsPile[1] = 1;
+ _availableCardsPile[2] = 1;
+ _availableCardsPile[3] = 1;
+ _availableCardsPile[4] = 1;
+ _availableCardsPile[5] = 1;
+ _availableCardsPile[6] = 1;
+ _availableCardsPile[7] = 1;
+ _availableCardsPile[8] = 26;
+ _availableCardsPile[9] = 2;
+ _availableCardsPile[10] = 2;
+ _availableCardsPile[11] = 2;
+ _availableCardsPile[12] = 2;
+ _availableCardsPile[13] = 2;
+ _availableCardsPile[14] = 26;
+ _availableCardsPile[15] = 3;
+ _availableCardsPile[16] = 3;
+ _availableCardsPile[17] = 3;
+ _availableCardsPile[18] = 3;
+ _availableCardsPile[19] = 3;
+ _availableCardsPile[20] = 28;
+ _availableCardsPile[21] = 4;
+ _availableCardsPile[22] = 4;
+ _availableCardsPile[23] = 4;
+ _availableCardsPile[24] = 4;
+ _availableCardsPile[25] = 4;
+ _availableCardsPile[26] = 28;
+ _availableCardsPile[27] = 5;
+ _availableCardsPile[28] = 5;
+ _availableCardsPile[29] = 5;
+ _availableCardsPile[30] = 5;
+ _availableCardsPile[31] = 5;
+ _availableCardsPile[32] = 30;
+ _availableCardsPile[33] = 6;
+ _availableCardsPile[34] = 6;
+ _availableCardsPile[35] = 6;
+ _availableCardsPile[36] = 6;
+ _availableCardsPile[37] = 6;
+ _availableCardsPile[38] = 30;
+ _availableCardsPile[39] = 7;
+ _availableCardsPile[40] = 7;
+ _availableCardsPile[41] = 7;
+ _availableCardsPile[42] = 7;
+ _availableCardsPile[43] = 7;
+ _availableCardsPile[44] = 32;
+ _availableCardsPile[45] = 8;
+ _availableCardsPile[46] = 8;
+ _availableCardsPile[47] = 8;
+ _availableCardsPile[48] = 8;
+ _availableCardsPile[49] = 8;
+ _availableCardsPile[50] = 32;
+ _availableCardsPile[51] = 9;
+ _availableCardsPile[52] = 9;
+ _availableCardsPile[53] = 9;
+ _availableCardsPile[54] = 9;
+ _availableCardsPile[55] = 9;
+ _availableCardsPile[56] = 10;
+ _availableCardsPile[57] = 11;
+ _availableCardsPile[58] = 12;
+ _availableCardsPile[59] = 13;
+ _availableCardsPile[60] = 13;
+ _availableCardsPile[61] = 14;
+ _availableCardsPile[62] = 15;
+ _availableCardsPile[63] = 16;
+ _availableCardsPile[64] = 17;
+ _availableCardsPile[65] = 18;
+ _availableCardsPile[66] = 19;
+ _availableCardsPile[67] = 20;
+ _availableCardsPile[68] = 21;
+ _availableCardsPile[69] = 26;
+ _availableCardsPile[70] = 28;
+ _availableCardsPile[71] = 24;
+ _availableCardsPile[72] = 25;
+ _availableCardsPile[73] = 25;
+ _availableCardsPile[74] = 25;
+ _availableCardsPile[75] = 25;
+ _availableCardsPile[76] = 26;
+ _availableCardsPile[77] = 26;
+ _availableCardsPile[78] = 26;
+ _availableCardsPile[79] = 27;
+ _availableCardsPile[80] = 27;
+ _availableCardsPile[81] = 28;
+ _availableCardsPile[82] = 28;
+ _availableCardsPile[83] = 28;
+ _availableCardsPile[84] = 29;
+ _availableCardsPile[85] = 29;
+ _availableCardsPile[86] = 29;
+ _availableCardsPile[87] = 30;
+ _availableCardsPile[88] = 30;
+ _availableCardsPile[89] = 30;
+ _availableCardsPile[90] = 30;
+ _availableCardsPile[91] = 32;
+ _availableCardsPile[92] = 1;
+ _availableCardsPile[93] = 32;
+ _availableCardsPile[94] = 32;
+ _availableCardsPile[95] = 32;
+ _availableCardsPile[96] = 1;
+ _availableCardsPile[97] = 1;
+ _availableCardsPile[98] = 1;
+ _availableCardsPile[99] = 0;
+
+ _cardsAvailableNumb = 98;
+ _currentDiscardIndex = 98; // CHECKME: Would make more sense at pos 99
+
+ _discardPile._cardId = 0;
+ _discardPile._stationPos = Common::Point(128, 95);
+
+ _stockCard._cardId = 0;
+ _stockCard._stationPos = Common::Point(162, 95);
+
+ _selectedCard._cardId = 0;
+
+ _animatedCard._card.postInit();
+ _animatedCard._card.setVisage(1332);
+ _animatedCard._card.setStrip(5);
+ _animatedCard._card.setFrame(1);
+ _animatedCard._card._moveDiff = Common::Point(10, 10);
+ _animatedCard._card.fixPriority(400);
+ _animatedCard._card.setPosition(Common::Point(128, 95), 0);
+ _animatedCard._card.animate(ANIM_MODE_2, NULL);
+ _animatedCard._card.hide();
+
+ _currentPlayerArrow.postInit();
+ _currentPlayerArrow.setVisage(1334);
+ _currentPlayerArrow.setStrip(1);
+ _currentPlayerArrow.setFrame(1);
+ _currentPlayerArrow._numFrames = 12;
+ _currentPlayerArrow.fixPriority(500);
+ _currentPlayerArrow.setPosition(Common::Point(174, 107), 0);
+ _currentPlayerArrow.animate(ANIM_MODE_2, NULL);
+ _currentPlayerArrow.hide();
+
+ _showPlayerTurn = true;
+ _displayHelpFl = false;
+ _winnerId = -1;
+
+ _helpIcon.postInit();
+ _helpIcon.setup(9531, 1, 1);
+ _helpIcon.setPosition(Common::Point(249, 168));
+ _helpIcon.setPriority(155);
+ _helpIcon._effect = EFFECT_NONE;
+ _helpIcon.show();
+
+ _autoplay = false;
+ _instructionsDisplayedFl = false;
+ _instructionsWaitCount = 0;
+}
+
+void Scene1337::suggestInstructions() {
+ if (R2_GLOBALS._v57709 > 0)
+ subD1917();
+
+ if (MessageDialog::show(NEED_INSTRUCTIONS, NO_MSG, YES_MSG) == 0) {
+ if (R2_GLOBALS._v57709 == 0)
+ subD18F5();
+ dealCards();
+ } else {
+ if (R2_GLOBALS._v57709 == 0)
+ subD18F5();
+ displayInstructions();
+ }
+}
+
+void Scene1337::displayInstructions() {
+ _actionItem.setAction(&_action1);
+}
+
+void Scene1337::shuffleCards() {
+ R2_GLOBALS._sceneObjects->draw();
+
+ // Remove holes in card pile
+ for (int i = 0; i <= 98; i++) {
+ if (_availableCardsPile[i] == 0) {
+ for (int j = i + 1; j <= 98; j ++) {
+ if (_availableCardsPile[j] != 0) {
+ _availableCardsPile[i] = _availableCardsPile[j];
+ _availableCardsPile[j] = 0;
+ break;
+ }
+ }
+ }
+ }
+
+ // Compute the number of available cards
+ for (int i = 0; i <= 99; i ++) {
+ if (_availableCardsPile[i] == 0) {
+ // CHECKME: This will fail if i == 0, which shouldn't happen
+ // as we don't shuffle cards when no card is available.
+ _cardsAvailableNumb = i - 1;
+ _currentDiscardIndex = 98; // CHECKME: Would make more sense at pos 99
+ break;
+ }
+ }
+
+ for (int i = 0; i < 2000; i ++) {
+ int randIndx = R2_GLOBALS._randomSource.getRandomNumber(_cardsAvailableNumb);
+ int swap = _availableCardsPile[0];
+ _availableCardsPile[0] = _availableCardsPile[randIndx];
+ _availableCardsPile[randIndx] = swap;
+ }
+
+ _shuffleEndedFl = false;
+
+ // Shuffle cards
+ _animatedCard._card.setAction(&_action2);
+
+ while(!_shuffleEndedFl && !g_vm->shouldQuit()) {
+ g_globals->_sceneObjects->recurse(SceneHandler::dispatchObject);
+ g_globals->_scenePalette.signalListeners();
+ R2_GLOBALS._sceneObjects->draw();
+ g_globals->_events.delay(g_globals->_sceneHandler->_delayTicks);
+ }
+}
+
+void Scene1337::dealCards() {
+ _animatedCard._card._moveDiff = Common::Point(30, 30);
+ shuffleCards();
+
+ // Deal cards
+ _actionItem.setAction(&_action3);
+}
+
+void Scene1337::showOptionsDialog() {
+ // Display menu with "Auto Play", "New Game", "Quit" and "Continue"
+ OptionsDialog::show();
+}
+
+void Scene1337::handleClick(int arg1, Common::Point pt) {
+ int curReg = R2_GLOBALS._sceneRegions.indexOf(g_globals->_events._mousePos);
+
+ if (arg1 == 3) {
+ bool found = false;
+ int i;
+ for (i = 0; i <= 7; i++) {
+ if ( _gameBoardSide[2]._outpostStation[i].isIn(pt)
+ || _gameBoardSide[0]._outpostStation[i].isIn(pt)
+ || _gameBoardSide[1]._outpostStation[i].isIn(pt)
+ || _gameBoardSide[3]._outpostStation[i].isIn(pt) ) {
+ found = true;
+ break;
+ }
+ }
+
+ if (found) {
+ switch (curReg) {
+ case 5:
+ if (_gameBoardSide[2]._outpostStation[i]._cardId != 0)
+ displayDialog(_gameBoardSide[2]._outpostStation[i]._cardId);
+ else
+ actionDisplay(1330, 20, 159, 10, 1, 200, 0, 7, 0, 154, 154);
+ break;
+ case 10:
+ if (_gameBoardSide[3]._outpostStation[i]._cardId != 0)
+ displayDialog(_gameBoardSide[3]._outpostStation[i]._cardId);
+ else
+ actionDisplay(1330, 22, 159, 10, 1, 200, 0, 7, 0, 154, 154);
+ break;
+ case 15:
+ if (_gameBoardSide[0]._outpostStation[i]._cardId != 0)
+ displayDialog(_gameBoardSide[0]._outpostStation[i]._cardId);
+ else
+ actionDisplay(1330, 21, 159, 10, 1, 200, 0, 7, 0, 154, 154);
+ break;
+ case 20:
+ if (_gameBoardSide[1]._outpostStation[i]._cardId != 0)
+ displayDialog(_gameBoardSide[1]._outpostStation[i]._cardId);
+ else
+ actionDisplay(1330, 23, 159, 10, 1, 200, 0, 7, 0, 154, 154);
+ break;
+ default:
+ break;
+ }
+ } else if ( _gameBoardSide[2]._delayCard.isIn(pt)
+ || _gameBoardSide[0]._delayCard.isIn(pt)
+ || _gameBoardSide[1]._delayCard.isIn(pt)
+ || _gameBoardSide[3]._delayCard.isIn(pt) ) {
+ switch (curReg) {
+ case 5:
+ if (_gameBoardSide[2]._delayCard._cardId != 0)
+ displayDialog(_gameBoardSide[2]._delayCard._cardId);
+ else
+ actionDisplay(1330, 10, 159, 10, 1, 200, 0, 7, 0, 154, 154);
+ break;
+ case 10:
+ if (_gameBoardSide[3]._delayCard._cardId != 0)
+ displayDialog(_gameBoardSide[3]._delayCard._cardId);
+ else
+ actionDisplay(1330, 16, 159, 10, 1, 200, 0, 7, 0, 154, 154);
+ break;
+ case 15:
+ if (_gameBoardSide[0]._delayCard._cardId != 0)
+ displayDialog(_gameBoardSide[0]._delayCard._cardId);
+ else
+ actionDisplay(1330, 13, 159, 10, 1, 200, 0, 7, 0, 154, 154);
+ break;
+ case 20:
+ if (_gameBoardSide[1]._delayCard._cardId != 0)
+ displayDialog(_gameBoardSide[1]._delayCard._cardId);
+ else
+ actionDisplay(1330, 18, 159, 10, 1, 200, 0, 7, 0, 154, 154);
+ break;
+ default:
+ break;
+ }
+ } else if (_discardPile.isIn(pt)) {
+ if (_discardPile._cardId != 0)
+ displayDialog(_discardPile._cardId);
+ else
+ actionDisplay(1330, 7, 159, 10, 1, 200, 0, 7, 0, 154, 154);
+ } else if (_helpIcon._bounds.contains(pt))
+ actionDisplay(1330, 43, 159, 10, 1, 200, 0, 7, 0, 154, 154);
+ else if (_stockCard.isIn(pt))
+ actionDisplay(1330, 4, 159, 10, 1, 200, 0, 7, 0, 154, 154);
+ else if ( (_gameBoardSide[2]._emptyStationPos.isIn(pt))
+ || (_gameBoardSide[3]._emptyStationPos.isIn(pt))
+ || (_gameBoardSide[0]._emptyStationPos.isIn(pt))
+ || (_gameBoardSide[1]._emptyStationPos.isIn(pt)) )
+ actionDisplay(1330, 32, 159, 10, 1, 200, 0, 7, 0, 154, 154);
+ else if (_gameBoardSide[2]._handCard[0].isIn(pt))
+ displayDialog(_gameBoardSide[2]._handCard[0]._cardId);
+ else if (_gameBoardSide[2]._handCard[1].isIn(pt))
+ displayDialog(_gameBoardSide[2]._handCard[1]._cardId);
+ else if (_gameBoardSide[2]._handCard[2].isIn(pt))
+ displayDialog(_gameBoardSide[2]._handCard[2]._cardId);
+ else if (_gameBoardSide[2]._handCard[3].isIn(pt))
+ displayDialog(_gameBoardSide[2]._handCard[3]._cardId);
+ else if ((curReg >= 6) && (curReg <= 9))
+ actionDisplay(1330, 29, 159, 10, 1, 200, 0, 7, 0, 154, 154);
+ else if ((curReg >= 11) && (curReg <= 14))
+ actionDisplay(1330, 31, 159, 10, 1, 200, 0, 7, 0, 154, 154);
+ else if ((curReg >= 16) && (curReg <= 19))
+ actionDisplay(1330, 30, 159, 10, 1, 200, 0, 7, 0, 154, 154);
+ else {
+ switch (curReg) {
+ case 0:
+ actionDisplay(1330, 2, 159, 134, 1, 200, 0, 7, 0, 105, 105);
+ break;
+ case 5:
+ actionDisplay(1330, 25, 159, 10, 1, 200, 0, 7, 0, 154, 154);
+ break;
+ case 10:
+ actionDisplay(1330, 27, 159, 10, 1, 200, 0, 7, 0, 154, 154);
+ break;
+ case 15:
+ actionDisplay(1330, 26, 159, 10, 1, 200, 0, 7, 0, 154, 154);
+ break;
+ case 20:
+ actionDisplay(1330, 28, 159, 10, 1, 200, 0, 7, 0, 154, 154);
+ break;
+ case 21:
+ actionDisplay(1330, 24, 159, 10, 1, 200, 0, 7, 0, 154, 154);
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+ if (arg1 != 1)
+ return;
+
+ for (int i = 0; i <= 7; i++) {
+ if (_gameBoardSide[2]._outpostStation[i].isIn(pt)) {
+ switch (_gameBoardSide[2]._outpostStation[i]._cardId) {
+ case 0:
+ actionDisplay(1330, 11, 159, 10, 1, 200, 0, 7, 0, 154, 154);
+ break;
+ case 1:
+ actionDisplay(1330, 54, 159, 10, 1, 200, 0, 7, 0, 154, 154);
+ break;
+ default:
+ actionDisplay(1330, 34, 159, 10, 1, 200, 0, 7, 0, 154, 154);
+ break;
+ }
+ return;
+ }
+ if (_gameBoardSide[0]._outpostStation[i].isIn(pt)) {
+ switch (_gameBoardSide[0]._outpostStation[i]._cardId) {
+ case 0:
+ actionDisplay(1330, 11, 159, 10, 1, 200, 0, 7, 0, 154, 154);
+ break;
+ default:
+ actionDisplay(1330, 1, 159, 10, 1, 200, 0, 7, 0, 154, 154);
+ break;
+ }
+ return;
+ }
+ if (_gameBoardSide[1]._outpostStation[i].isIn(pt)) {
+ switch (_gameBoardSide[1]._outpostStation[i]._cardId) {
+ case 0:
+ actionDisplay(1330, 146, 300, 99, 1, 136, 0, 7, 0, 117, 117);
+ break;
+ default:
+ actionDisplay(1330, 144, 300, 99, 1, 136, 0, 7, 0, 117, 117);
+ break;
+ }
+ return;
+ }
+ if (_gameBoardSide[3]._outpostStation[i].isIn(pt)) {
+ switch (_gameBoardSide[3]._outpostStation[i]._cardId) {
+ case 0:
+ actionDisplay(1330, 147, 20, 99, 1, 136, 0, 7, 0, 172, 172);
+ break;
+ default:
+ actionDisplay(1330, 145, 20, 99, 1, 136, 0, 7, 0, 172, 172);
+ break;
+ }
+ return;
+ }
+ }
+
+ if (_gameBoardSide[2]._delayCard.isIn(pt)) {
+ // The original uses _gameBoardSide[0], which is obviously a bug.
+ if (_gameBoardSide[2]._delayCard._cardId != 0)
+ actionDisplay(1330, 39, 159, 10, 1, 200, 0, 7, 0, 154, 154);
+ else
+ actionDisplay(1330, 11, 159, 10, 1, 200, 0, 7, 0, 154, 154);
+
+ return;
+ }
+ if (_gameBoardSide[3]._delayCard.isIn(pt)) {
+ if (_gameBoardSide[3]._delayCard._cardId != 0)
+ actionDisplay(1330, 145, 20, 99, 1, 136, 0, 7, 0, 172, 172);
+ else
+ actionDisplay(1330, 147, 20, 99, 1, 136, 0, 7, 0, 172, 172);
+
+ return;
+ }
+ if (_gameBoardSide[1]._delayCard.isIn(pt)) {
+ if (_gameBoardSide[1]._delayCard._cardId != 0)
+ actionDisplay(1330, 144, 300, 99, 1, 136, 0, 7, 0, 117, 117);
+ else
+ actionDisplay(1330, 146, 300, 99, 1, 136, 0, 7, 0, 117, 117);
+
+ return;
+ }
+ if (_gameBoardSide[0]._delayCard.isIn(pt)) {
+ if (_gameBoardSide[0]._delayCard._cardId != 0)
+ actionDisplay(1330, 1, 159, 10, 1, 200, 0, 7, 0, 154, 154);
+ else
+ actionDisplay(1330, 11, 159, 10, 1, 200, 0, 7, 0, 154, 154);
+
+ return;
+ }
+ if (_gameBoardSide[3]._emptyStationPos.isIn(pt)) {
+ actionDisplay(1330, 147, 20, 99, 1, 136, 0, 7, 0, 172, 172);
+ return;
+ }
+ if (_gameBoardSide[1]._emptyStationPos.isIn(pt)) {
+ actionDisplay(1330, 146, 300, 99, 1, 136, 0, 7, 0, 117, 117);
+ return;
+ }
+ if (_gameBoardSide[0]._emptyStationPos.isIn(pt)) {
+ actionDisplay(1330, 11, 159, 10, 1, 200, 0, 7, 0, 154, 154);
+ return;
+ }
+
+ if (_helpIcon._bounds.contains(pt)) {
+ showOptionsDialog();
+ return;
+ }
+
+ if (_discardPile.isIn(pt))
+ actionDisplay(1330, 9, 159, 10, 1, 200, 0, 7, 0, 154, 154);
+ else if (_stockCard.isIn(pt))
+ actionDisplay(1330, 5, 159, 10, 1, 200, 0, 7, 0, 154, 154);
+ else {
+ switch (curReg) {
+ case 0:
+ actionDisplay(1330, 3, 159, 10, 1, 200, 0, 7, 0, 154, 154);
+ break;
+ case 6:
+ // no break on purpose
+ case 7:
+ // no break on purpose
+ case 8:
+ // no break on purpose
+ case 9:
+ actionDisplay(1330, 145, 20, 99, 1, 136, 0, 7, 0, 172, 172);
+ break;
+ case 10:
+ actionDisplay(1330, 147, 20, 99, 1, 136, 0, 7, 0, 172, 172);
+ break;
+ case 11:
+ // no break on purpose
+ case 12:
+ // no break on purpose
+ case 13:
+ // no break on purpose
+ case 14:
+ actionDisplay(1330, 1, 159, 10, 1, 200, 0, 7, 0, 154, 154);
+ break;
+ case 16:
+ // no break on purpose
+ case 17:
+ // no break on purpose
+ case 18:
+ // no break on purpose
+ case 19:
+ actionDisplay(1330, 144, 300, 99, 1, 136, 0, 7, 0, 117, 117);
+ break;
+ case 20:
+ actionDisplay(1330, 146, 300, 99, 1, 136, 0, 7, 0, 117, 117);
+ break;
+ default:
+ actionDisplay(1330, 11, 159, 10, 1, 200, 0, 7, 0, 154, 154);
+ break;
+ }
+ }
+}
+
+void Scene1337::handlePlayer0() {
+ if (_gameBoardSide[0]._delayCard._cardId != 0) {
+ switch (_gameBoardSide[0]._delayCard._cardId) {
+ case 10:
+ //No break on purpose
+ case 12:
+ //No break on purpose
+ case 15:
+ //No break on purpose
+ case 17:
+ //No break on purpose
+ case 18:
+ //No break on purpose
+ case 19:
+ //No break on purpose
+ case 20:
+ //No break on purpose
+ case 21:
+ discardCard(&_gameBoardSide[0]._delayCard);
+ return;
+ default:
+ for (int i = 0; i <= 3; i++) {
+ if (checkAntiDelayCard(_gameBoardSide[0]._delayCard._cardId, _gameBoardSide[0]._handCard[i]._cardId)) {
+ playAntiDelayCard(&_gameBoardSide[0]._handCard[i], &_gameBoardSide[0]._delayCard);
+ return;
+ }
+ }
+
+ break;
+ }
+ }
+
+ for (int i = 0; i <= 3; i++) {
+ int tmpVal = getStationId(0, i);
+
+ if (tmpVal != -1) {
+ bool stationAlreadyPresentFl = false;
+ for (int j = 0; j <= 7; j++) {
+ if (_gameBoardSide[0]._outpostStation[j]._cardId == _gameBoardSide[0]._handCard[tmpVal]._cardId) {
+ stationAlreadyPresentFl = true;
+ break;
+ }
+ }
+
+ if (!stationAlreadyPresentFl) {
+ for (int j = 0; j <= 7; j++) {
+ if ((_gameBoardSide[0]._outpostStation[j]._cardId == 1) && !isStopConstructionCard(_gameBoardSide[0]._delayCard._cardId)) {
+ int stationCount = 0;
+ for (int k = 0; k <= 7; k++) {
+ if ((_gameBoardSide[0]._outpostStation[k]._cardId > 1) && (_gameBoardSide[0]._outpostStation[k]._cardId <= 9)) {
+ ++stationCount;
+ }
+ }
+
+ if (stationCount == 7)
+ _winnerId = 0;
+
+ playStationCard(&_gameBoardSide[0]._handCard[tmpVal], &_gameBoardSide[0]._outpostStation[j]);
+ return;
+ }
+ }
+ }
+ }
+ }
+
+ int tmpVal = findPlatformCardInHand(0);
+
+ if (tmpVal != -1) {
+ for (int i = 0; i <= 7; i++) {
+ if ((_gameBoardSide[0]._outpostStation[i]._cardId == 0) && !isStopConstructionCard(_gameBoardSide[0]._delayCard._cardId)) {
+ playPlatformCard(&_gameBoardSide[0]._handCard[tmpVal], &_gameBoardSide[0]._outpostStation[i]);
+ return;
+ }
+ }
+ }
+
+ int meteorCardId = findMeteorCardInHand(0);
+ if (meteorCardId != -1) {
+ for (int i = 0; i <= 7; i++) {
+ if (_gameBoardSide[2]._outpostStation[i]._cardId != 0) {
+ playCentralOutpostCard(&_gameBoardSide[0]._handCard[meteorCardId], 2);
+ return;
+ }
+ }
+ }
+
+ int thieftId = findThieftCardInHand(0);
+ if (thieftId != -1) {
+ if ( (_gameBoardSide[2]._handCard[0]._cardId != 0)
+ || (_gameBoardSide[2]._handCard[1]._cardId != 0)
+ || (_gameBoardSide[2]._handCard[2]._cardId != 0)
+ || (_gameBoardSide[2]._handCard[3]._cardId != 0) ) {
+ playThieftCard(0, &_gameBoardSide[0]._handCard[thieftId], 2);
+ return;
+ }
+ }
+
+ for (int i = 0; i <= 3; i++) {
+ if ((isDelayCard(_gameBoardSide[0]._handCard[i]._cardId) != -1)
+ && (_gameBoardSide[2]._delayCard._cardId == 0)
+ && isAttackPossible(2, _gameBoardSide[0]._handCard[i]._cardId)) {
+ playDelayCard(&_gameBoardSide[0]._handCard[i], &_gameBoardSide[2]._delayCard);
+ return;
+ }
+ }
+
+ for (int i = 0; i <= 3; i++) {
+ if ((getStationCardId(_gameBoardSide[0]._handCard[i]._cardId) != -1)
+ && (_gameBoardSide[2]._delayCard._cardId == 0)
+ && isAttackPossible(2, _gameBoardSide[0]._handCard[i]._cardId)) {
+ playDelayCard(&_gameBoardSide[0]._handCard[i], &_gameBoardSide[2]._delayCard);
+ return;
+ }
+ }
+
+ meteorCardId = findMeteorCardInHand(0);
+ int victimId = getPlayerWithOutpost(0);
+
+ if ((meteorCardId != -1) && (victimId != -1)) {
+ playCentralOutpostCard(&_gameBoardSide[0]._handCard[meteorCardId], victimId);
+ return;
+ }
+
+ thieftId = findThieftCardInHand(0);
+ if (thieftId != -1) {
+ if ( (_gameBoardSide[1]._handCard[0]._cardId != 0)
+ || (_gameBoardSide[1]._handCard[1]._cardId != 0)
+ || (_gameBoardSide[1]._handCard[2]._cardId != 0)
+ || (_gameBoardSide[1]._handCard[3]._cardId != 0) ) {
+ playThieftCard(0, &_gameBoardSide[0]._handCard[thieftId], 1);
+ return;
+ }
+ }
+
+ for (int i = 0; i <= 3; i++) {
+ if (getStationCardId(_gameBoardSide[0]._handCard[i]._cardId) != -1) {
+ if ((_gameBoardSide[1]._delayCard._cardId == 0) && isAttackPossible(1, _gameBoardSide[0]._handCard[i]._cardId)) {
+ playDelayCard(&_gameBoardSide[0]._handCard[i], &_gameBoardSide[1]._delayCard);
+ return;
+ }
+
+ if ((_gameBoardSide[3]._delayCard._cardId == 0) && isAttackPossible(3, _gameBoardSide[0]._handCard[i]._cardId)) {
+ playDelayCard(&_gameBoardSide[0]._handCard[i], &_gameBoardSide[3]._delayCard);
+ return;
+ }
+ }
+ }
+
+ for (int i = 0; i <= 3; i++) {
+ tmpVal = isDelayCard(_gameBoardSide[0]._handCard[i]._cardId);
+ if (tmpVal != -1) {
+ if ((_gameBoardSide[1]._delayCard._cardId == 0) && isAttackPossible(1, _gameBoardSide[0]._handCard[i]._cardId)) {
+ playDelayCard(&_gameBoardSide[0]._handCard[i], &_gameBoardSide[1]._delayCard);
+ return;
+ }
+
+ if ((_gameBoardSide[3]._delayCard._cardId == 0) && isAttackPossible(3, _gameBoardSide[0]._handCard[i]._cardId)) {
+ playDelayCard(&_gameBoardSide[0]._handCard[i], &_gameBoardSide[3]._delayCard);
+ return;
+ }
+ }
+ }
+
+ handlePlayer01Discard(0);
+}
+
+void Scene1337::handlePlayer1() {
+ if (this->_gameBoardSide[1]._delayCard._cardId != 0) {
+ switch (_gameBoardSide[1]._delayCard._cardId) {
+ case 10:
+ // No break on purpose
+ case 12:
+ // No break on purpose
+ case 15:
+ // No break on purpose
+ case 17:
+ // No break on purpose
+ case 18:
+ // No break on purpose
+ case 19:
+ // No break on purpose
+ case 20:
+ // No break on purpose
+ case 21:
+ discardCard(&_gameBoardSide[1]._delayCard);
+ return;
+ default:
+ for (int i = 0; i <= 3; i++) {
+ if (checkAntiDelayCard(_gameBoardSide[1]._delayCard._cardId, _gameBoardSide[1]._handCard[i]._cardId)) {
+ playAntiDelayCard(&_gameBoardSide[1]._handCard[i], &_gameBoardSide[1]._delayCard);
+ return;
+ }
+ }
+ break;
+ }
+ }
+
+ for (int i = 0; i <= 3; i++) {
+ int tmpIndx = getStationId(1, i);
+ if (tmpIndx == -1)
+ break;
+
+ int tmpVal = 0;
+ for (int j = 0; j <= 7; j++) {
+ if (_gameBoardSide[1]._outpostStation[j]._cardId == _gameBoardSide[1]._handCard[tmpIndx]._cardId) {
+ tmpVal = 1;
+ break;
+ }
+ }
+
+ if (tmpVal == 0)
+ break;
+
+ for (int j = 0; j <= 7; j++) {
+ if ((_gameBoardSide[1]._outpostStation[j]._cardId == 1) && !isStopConstructionCard(_gameBoardSide[1]._delayCard._cardId)) {
+ int stationCount = 0;
+ for (int k = 0; k <= 7; k++) {
+ if ((_gameBoardSide[1]._outpostStation[k]._cardId > 1) && (_gameBoardSide[1]._outpostStation[k]._cardId <= 9))
+ ++stationCount;
+ }
+
+ if (stationCount == 7)
+ _winnerId = 1;
+
+ playStationCard(&_gameBoardSide[1]._handCard[tmpIndx], &_gameBoardSide[1]._outpostStation[j]);
+ return;
+ }
+ }
+ }
+
+ int normalCardId = findPlatformCardInHand(1);
+ if (normalCardId != -1) {
+ for (int i = 0; i <= 7; i++) {
+ if ((_gameBoardSide[1]._outpostStation[i]._cardId == 0) && !isStopConstructionCard(_gameBoardSide[1]._delayCard._cardId)) {
+ playPlatformCard(&_gameBoardSide[1]._handCard[normalCardId], &_gameBoardSide[1]._outpostStation[i]);
+ return;
+ }
+ }
+ }
+
+ int meterorCardId = findMeteorCardInHand(1);
+ int victimId = getPlayerWithOutpost(1);
+
+ if ((meterorCardId != -1) && (victimId != -1)) {
+ playCentralOutpostCard(&_gameBoardSide[1]._handCard[meterorCardId], victimId);
+ return;
+ }
+
+ int thieftId = findThieftCardInHand(1);
+ if (thieftId != -1) {
+ int playerIdFound = -1;
+ int rndVal = R2_GLOBALS._randomSource.getRandomNumber(3);
+ for (int i = 0; i <= 3; i++) {
+ if (rndVal != 1) {
+ if ( (_gameBoardSide[rndVal]._handCard[0]._cardId != 0)
+ || (_gameBoardSide[rndVal]._handCard[1]._cardId != 0)
+ || (_gameBoardSide[rndVal]._handCard[2]._cardId != 0)
+ || (_gameBoardSide[rndVal]._handCard[3]._cardId != 0)) {
+ playerIdFound = rndVal;
+ break;
+ }
+ }
+ // The original was only updating in the rndVal block,
+ // which was a bug as the checks were stopping at this point
+ rndVal--;
+ if (rndVal < 0)
+ rndVal = 3;
+ }
+
+ if (playerIdFound != -1) {
+ playThieftCard(1, &_gameBoardSide[1]._handCard[thieftId], playerIdFound);
+ return;
+ }
+ }
+
+ for (int i = 0; i <= 3; i++) {
+ int tmpVal = isDelayCard(_gameBoardSide[1]._handCard[i]._cardId);
+ if (tmpVal != -1) {
+ victimId = -1;
+ int rndVal = R2_GLOBALS._randomSource.getRandomNumber(3);
+
+ for (int j = 0; j <= 3; j++) {
+ if (rndVal != 1) {
+ if ((_gameBoardSide[rndVal]._delayCard._cardId == 0) && isAttackPossible(rndVal, _gameBoardSide[1]._handCard[i]._cardId))
+ victimId = rndVal;
+ }
+
+ if (victimId != -1) {
+ playDelayCard(&_gameBoardSide[1]._handCard[i], &_gameBoardSide[victimId]._delayCard);
+ return;
+ } else {
+ rndVal--;
+ if (rndVal < 0)
+ rndVal = 3;
+ }
+ }
+ }
+ }
+
+ for (int j = 0; j <= 3; j++) {
+ if (getStationCardId(_gameBoardSide[1]._handCard[j]._cardId) != -1) {
+ victimId = -1;
+ int rndVal = R2_GLOBALS._randomSource.getRandomNumber(3);
+ for (int l = 0; l <= 3; l++) {
+ if (rndVal != 1) {
+ if ((_gameBoardSide[rndVal]._delayCard._cardId == 0) && (_gameBoardSide[1]._handCard[j]._cardId == 1))
+ victimId = rndVal;
+ }
+ if (victimId != -1) {
+ playDelayCard(&_gameBoardSide[1]._handCard[j], &_gameBoardSide[victimId]._delayCard);
+ return;
+ } else {
+ rndVal--;
+ if (rndVal < 0)
+ rndVal = 3;
+ }
+ }
+ }
+ }
+
+ handlePlayer01Discard(1);
+}
+
+void Scene1337::handlePlayer3() {
+ if (_gameBoardSide[3]._delayCard._cardId != 0) {
+ switch (_gameBoardSide[3]._delayCard._cardId) {
+ case 10:
+ // No break on purpose
+ case 12:
+ // No break on purpose
+ case 15:
+ // No break on purpose
+ case 17:
+ // No break on purpose
+ case 18:
+ // No break on purpose
+ case 19:
+ // No break on purpose
+ case 20:
+ // No break on purpose
+ case 21:
+ discardCard(&_gameBoardSide[3]._delayCard);
+ return;
+ default:
+ for (int i = 0; i <= 3; i++) {
+ if (checkAntiDelayCard(_gameBoardSide[3]._delayCard._cardId, _gameBoardSide[3]._handCard[i]._cardId)) {
+ playAntiDelayCard(&_gameBoardSide[3]._handCard[i], &_gameBoardSide[3]._delayCard);
+ return;
+ }
+ }
+ break;
+ }
+ }
+
+ int randIndx = R2_GLOBALS._randomSource.getRandomNumber(3);
+ if (_gameBoardSide[3]._handCard[randIndx]._cardId == 1) {
+ // Station Card
+ for (int i = 0; i <= 7; i++) {
+ if ((_gameBoardSide[3]._outpostStation[i]._cardId == 0) && !isStopConstructionCard(_gameBoardSide[3]._delayCard._cardId)) {
+ playPlatformCard(&_gameBoardSide[3]._handCard[randIndx], &_gameBoardSide[3]._outpostStation[i]);
+ return;
+ }
+ }
+ } else if (_gameBoardSide[3]._handCard[randIndx]._cardId <= 9) {
+ // Outpost Card
+ for (int i = 0; i <= 7; i++) {
+ if (_gameBoardSide[3]._outpostStation[i]._cardId == _gameBoardSide[3]._handCard[randIndx]._cardId) {
+ discardCard(&_gameBoardSide[3]._handCard[randIndx]);
+ return;
+ }
+ }
+
+ for (int i = 0; i <= 7; i++) {
+ if ((_gameBoardSide[3]._outpostStation[i]._cardId == 1) && !isStopConstructionCard(_gameBoardSide[3]._delayCard._cardId)) {
+ int stationCount = 0;
+ for (int j = 0; j <= 7; j++) {
+ if ((_gameBoardSide[3]._outpostStation[j]._cardId > 1) && (_gameBoardSide[3]._outpostStation[j]._cardId <= 9))
+ ++stationCount;
+ }
+
+ if (stationCount == 7)
+ _winnerId = 3;
+
+ playStationCard(&_gameBoardSide[3]._handCard[randIndx], &_gameBoardSide[3]._outpostStation[i]);
+ return;
+ }
+ }
+ } else if (_gameBoardSide[3]._handCard[randIndx]._cardId == 13) {
+ // Meteor Card
+ int victimId = getPlayerWithOutpost(3);
+
+ if (victimId != -1) {
+ playCentralOutpostCard(&_gameBoardSide[3]._handCard[randIndx], victimId);
+ return;
+ }
+ } else if (_gameBoardSide[3]._handCard[randIndx]._cardId == 25) {
+ // Thief card
+ int victimId = -1;
+ int tmpRandIndx = R2_GLOBALS._randomSource.getRandomNumber(3);
+
+ for (int i = 0; i <= 3; i++) {
+ if ( (tmpRandIndx != 3)
+ && ( (_gameBoardSide[tmpRandIndx]._handCard[0]._cardId != 0)
+ || (_gameBoardSide[tmpRandIndx]._handCard[1]._cardId != 0)
+ || (_gameBoardSide[tmpRandIndx]._handCard[2]._cardId != 0)
+ || (_gameBoardSide[tmpRandIndx]._handCard[3]._cardId != 0) )) {
+ victimId = tmpRandIndx;
+ break;
+ }
+
+ ++tmpRandIndx;
+ if (tmpRandIndx > 3)
+ tmpRandIndx = 0;
+ }
+
+ if (victimId != -1) {
+ playThieftCard(3, &_gameBoardSide[3]._handCard[randIndx], victimId);
+ return;
+ }
+ } else {
+ switch (_gameBoardSide[3]._handCard[randIndx]._cardId) {
+ case 10:
+ // No break on purpose
+ case 11:
+ // No break on purpose
+ case 12:
+ // No break on purpose
+ case 14:
+ // No break on purpose
+ case 15:
+ // No break on purpose
+ case 16:
+ // No break on purpose
+ case 17:
+ // No break on purpose
+ case 18:
+ // No break on purpose
+ case 19:
+ // No break on purpose
+ case 20:
+ // No break on purpose
+ case 21:
+ // No break on purpose
+ case 24: {
+ int victimId = -1;
+ int tmpRandIndx = R2_GLOBALS._randomSource.getRandomNumber(3);
+
+ for (int i = 0; i <= 3; i++) {
+ if (tmpRandIndx != 3) {
+ if ((_gameBoardSide[tmpRandIndx]._delayCard._cardId == 0)
+ && isAttackPossible(tmpRandIndx, _gameBoardSide[3]._handCard[randIndx]._cardId))
+ victimId = tmpRandIndx;
+ }
+
+ ++tmpRandIndx;
+ if (tmpRandIndx > 3)
+ tmpRandIndx = 0;
+
+ if (victimId != -1)
+ break;
+ }
+
+ if (victimId != -1) {
+ // Useless second identical check skipped
+ playDelayCard(&_gameBoardSide[3]._handCard[randIndx], &_gameBoardSide[victimId]._delayCard);
+ return;
+ }
+ }
+ default:
+ break;
+ }
+ }
+
+ discardCard(&_gameBoardSide[3]._handCard[randIndx]);
+}
+
+void Scene1337::handleAutoplayPlayer2() {
+ if (getStationCardId(this->_gameBoardSide[2]._delayCard._cardId) == -1)
+ _delayedFunction = &Scene1337::handlePlayer2;
+ else
+ discardCard(&_gameBoardSide[2]._delayCard);
+}
+
+void Scene1337::handlePlayer2() {
+ _selectedCard._stationPos = g_globals->_events._mousePos;
+
+ if (R2_GLOBALS._v57810 == 200) {
+ // Hand
+ int i;
+ for (i = 0; i < 4; i++) {
+ if ((_gameBoardSide[2]._handCard[i].isIn(_selectedCard._stationPos)) && (_gameBoardSide[2]._handCard[i]._cardId != 0)) {
+ Card *handcard = &_gameBoardSide[2]._handCard[i];
+ _selectedCard._cardId = handcard->_cardId;
+ _selectedCard._stationPos = handcard->_stationPos;
+ //warning("_selectedCard._actorName = handcard->_actorName;");
+ //warning("_selectedCard._fieldE = handcard->_fieldE;");
+ //warning("_selectedCard._field10 = handcard->_field10;");
+ //warning("_selectedCard._field12 = handcard->_field12;");
+ //warning("_selectedCard._field14 = handcard->_field14;");
+ //warning("_selectedCard._field16 = handcard->_field16;");
+ _selectedCard._sceneRegionId = handcard->_sceneRegionId;
+ _selectedCard._position = handcard->_position;
+ _selectedCard._yDiff = handcard->_yDiff;
+ _selectedCard._bounds = handcard->_bounds;
+ _selectedCard._resNum = handcard->_resNum;
+ _selectedCard._lookLineNum = handcard->_lookLineNum;
+ _selectedCard._talkLineNum = handcard->_talkLineNum;
+ _selectedCard._useLineNum = handcard->_useLineNum;
+ _selectedCard._action = handcard->_action;
+ //warning("_selectedCard._field0 = handcard->_field0;");
+ _selectedCard._card._updateStartFrame = handcard->_card._updateStartFrame;
+ _selectedCard._card._walkStartFrame = handcard->_card._walkStartFrame;
+ _selectedCard._card._oldPosition = handcard->_card._oldPosition;
+ _selectedCard._card._percent = handcard->_card._percent;
+ _selectedCard._card._priority = handcard->_card._priority;
+ _selectedCard._card._angle = handcard->_card._angle;
+ _selectedCard._card._flags = handcard->_card._flags;
+ _selectedCard._card._xe = handcard->_card._xe;
+ _selectedCard._card._xs = handcard->_card._xs;
+ _selectedCard._card._paneRects[0] = handcard->_card._paneRects[0];
+ _selectedCard._card._paneRects[1] = handcard->_card._paneRects[1];
+ _selectedCard._card._visage = handcard->_card._visage;
+ _selectedCard._card._objectWrapper = handcard->_card._objectWrapper;
+ _selectedCard._card._strip = handcard->_card._strip;
+ _selectedCard._card._animateMode = handcard->_card._animateMode;
+ _selectedCard._card._frame = handcard->_card._frame;
+ _selectedCard._card._endFrame = handcard->_card._endFrame;
+ _selectedCard._card._loopCount = handcard->_card._loopCount;
+ _selectedCard._card._frameChange = handcard->_card._frameChange;
+ _selectedCard._card._numFrames = handcard->_card._numFrames;
+ _selectedCard._card._regionIndex = handcard->_card._regionIndex;
+ _selectedCard._card._mover = handcard->_card._mover;
+ _selectedCard._card._moveDiff = handcard->_card._moveDiff;
+ _selectedCard._card._moveRate = handcard->_card._moveRate;
+ _selectedCard._card._actorDestPos = handcard->_card._actorDestPos;
+ _selectedCard._card._endAction = handcard->_card._endAction;
+ _selectedCard._card._regionBitList = handcard->_card._regionBitList;
+ // _selectedCard._object1._actorName = handcard->_object1._actorName;
+ //warning("_selectedCard._card._fieldE = handcard->_card._fieldE;");
+ //warning("_selectedCard._card._field10 = handcard->_card._field10;");
+ //warning("_selectedCard._card._field12 = handcard->_card._field12;");
+ //warning("_selectedCard._card._field14 = handcard->_card._field14;");
+ //warning("_selectedCard._card._field16 = handcard->_card._field16;");
+
+ _gameBoardSide[2]._handCard[i]._cardId = 0;
+ _gameBoardSide[2]._handCard[i]._card.remove();
+ break;
+ }
+ }
+
+ if (i == 4) {
+ handleClick(1, _selectedCard._stationPos);
+ handleAutoplayPlayer2();
+ return;
+ } else {
+ setCursorData(1332, _selectedCard._card._strip, _selectedCard._card._frame);
+ R2_GLOBALS._sceneObjects->draw();
+ }
+ } else if (R2_GLOBALS._v57810 == 300) {
+ // Eye
+ handleClick(3, _selectedCard._stationPos);
+ handleAutoplayPlayer2();
+ return;
+ } else {
+ // The original code is calling a function full of dead code.
+ // Only this message remains after a cleanup.
+ MessageDialog::show(WRONG_ANSWER_MSG, OK_BTN_STRING);
+ //
+ handleAutoplayPlayer2();
+ return;
+ }
+
+ Event event;
+ bool found;
+ for (;;) {
+ if ( ((g_globals->_events.getEvent(event, EVENT_BUTTON_DOWN)) && (event.btnState == BTNSHIFT_RIGHT))
+ || (g_globals->_events.getEvent(event, EVENT_KEYPRESS)) ){
+ _selectedCard._stationPos = g_globals->_events._mousePos;
+ found = false;
+
+ for (int i = 0; i <= 3; i ++) {
+ if (_gameBoardSide[2]._handCard[i].isIn(Common::Point(_selectedCard._stationPos.x + 12, _selectedCard._stationPos.y + 12))) {
+ if (_gameBoardSide[2]._handCard[i]._cardId == 0) {
+ _gameBoardSide[2]._handCard[i]._cardId = _selectedCard._cardId;
+ _gameBoardSide[2]._handCard[i]._card.postInit();
+ _gameBoardSide[2]._handCard[i]._card.hide();
+ _gameBoardSide[2]._handCard[i]._card.setVisage(1332);
+ _gameBoardSide[2]._handCard[i]._card.setPosition(_gameBoardSide[2]._handCard[i]._stationPos, 0);
+ _gameBoardSide[2]._handCard[i]._card.fixPriority(170);
+ setAnimationInfo(&_gameBoardSide[2]._handCard[i]);
+ setCursorData(5, 1, 4);
+ _currentPlayerNumb--;
+ _showPlayerTurn = false;
+ handleNextTurn();
+ return;
+ } else {
+ actionDisplay(1330, 127, 159, 10, 1, 200, 0, 7, 0, 154, 154);
+ found = true;
+ }
+ break;
+ }
+ }
+
+ if (!found) {
+ if (_discardPile.isIn(Common::Point(_selectedCard._stationPos.x + 12, _selectedCard._stationPos.y + 12))) {
+ discardCard(&_selectedCard);
+ return;
+ } else if (_selectedCard._cardId == 1) {
+ bool isInCardFl = false;
+ int i;
+ for (i = 0; i <= 7; i++) {
+ if (_gameBoardSide[2]._outpostStation[i].isIn(Common::Point(_selectedCard._stationPos.x + 12, _selectedCard._stationPos.y + 12))) {
+ isInCardFl = true;
+ break;
+ }
+ }
+
+ if ((isInCardFl) && (_gameBoardSide[2]._outpostStation[i]._cardId == 0)) {
+ if (isDelayCard(_gameBoardSide[2]._delayCard._cardId) != -1) {
+ actionDisplay(1330, 55, 159, 10, 1, 200, 0, 7, 0, 154, 154);
+ } else {
+ playPlatformCard(&_selectedCard, &_gameBoardSide[2]._outpostStation[i]);
+ return;
+ }
+ } else {
+ actionDisplay(1330, 56, 159, 10, 1, 200, 0, 7, 0, 154, 154);
+ }
+ } else if (_selectedCard._cardId <= 9) {
+ bool isInCardFl = false;
+ int i;
+ for (i = 0; i <= 7; i++) {
+ if (_gameBoardSide[2]._outpostStation[i].isIn(Common::Point(_selectedCard._stationPos.x + 12, _selectedCard._stationPos.y + 12))) {
+ isInCardFl = true;
+ break;
+ }
+ }
+ if ((isInCardFl) && (_gameBoardSide[2]._outpostStation[i]._cardId == 1)) {
+ isInCardFl = false;
+ for (int j = 0; j <= 7; j++) {
+ if (_selectedCard._cardId == _gameBoardSide[2]._outpostStation[j]._cardId) {
+ isInCardFl = true;
+ break;
+ }
+ }
+ if (isInCardFl) {
+ // This station is already in place
+ actionDisplay(1330, 34, 159, 10, 1, 200, 0, 7, 0, 154, 154);
+ } else if (isDelayCard(_gameBoardSide[2]._delayCard._cardId) != -1) {
+ // You must eliminate your delay before you can play a station
+ actionDisplay(1330, 35, 159, 10, 1, 200, 0, 7, 0, 154, 154);
+ } else {
+ int stationCount = 0;
+ for (int k = 0; k <= 7; k++) {
+ if ((_gameBoardSide[2]._outpostStation[k]._cardId > 1) && (_gameBoardSide[2]._outpostStation[k]._cardId <= 9))
+ ++stationCount;
+ }
+
+ if (stationCount == 7)
+ _winnerId = 2;
+
+ playStationCard(&_selectedCard, &_gameBoardSide[2]._outpostStation[i]);
+ return;
+ }
+ } else {
+ actionDisplay(1330, 37, 159, 10, 1, 200, 0, 7, 0, 154, 154);
+ }
+ } else if ((_selectedCard._cardId == 26) || (_selectedCard._cardId == 30) ||(_selectedCard._cardId == 32) || (_selectedCard._cardId == 28)) {
+ // Check anti-delay card (26 = Diplomacy, 28 = Innovation, 30 = Cure, 32 = Agreement)
+ if (_gameBoardSide[2]._delayCard.isIn(Common::Point(_selectedCard._stationPos.x + 12, _selectedCard._stationPos.y + 12))) {
+ actionDisplay(1330, 42, 159, 10, 1, 200, 0, 7, 0, 154, 154);
+ } else if (checkAntiDelayCard(_gameBoardSide[2]._delayCard._cardId, _selectedCard._cardId)) {
+ playAntiDelayCard(&_selectedCard, &_gameBoardSide[2]._delayCard);
+ return;
+ } else {
+ if (_gameBoardSide[2]._delayCard._cardId != 0) {
+ switch (_gameBoardSide[2]._delayCard._cardId) {
+ case 11:
+ actionDisplay(1330, 68, 159, 10, 1, 200, 0, 7, 0, 154, 154);
+ break;
+ case 14:
+ actionDisplay(1330, 80, 159, 10, 1, 200, 0, 7, 0, 154, 154);
+ break;
+ case 16:
+ actionDisplay(1330, 84, 159, 10, 1, 200, 0, 7, 0, 154, 154);
+ break;
+ case 24:
+ actionDisplay(1330, 96, 159, 10, 1, 200, 0, 7, 0, 154, 154);
+ break;
+ default:
+ break;
+ }
+ } else {
+ actionDisplay(1330, 41, 159, 10, 1, 200, 0, 7, 0, 154, 154);
+ }
+ }
+ } else if ((getStationCardId(_selectedCard._cardId) == -1) && (isDelayCard(_selectedCard._cardId) == -1)) {
+ if (_selectedCard._cardId == 13) {
+ // Meteor Card
+ if (_gameBoardSide[0]._emptyStationPos.isIn(Common::Point(_selectedCard._stationPos.x + 12, _selectedCard._stationPos.y + 12))) {
+ for (int k = 0; k <= 7; k++) {
+ if (_gameBoardSide[0]._outpostStation[k]._cardId != 0) {
+ playCentralOutpostCard(&_selectedCard, 0);
+ return;
+ }
+ }
+ actionDisplay(1330, 74, 159, 10, 1, 200, 0, 7, 0, 154, 154);
+ } else if (_gameBoardSide[3]._emptyStationPos.isIn(Common::Point(_selectedCard._stationPos.x + 12, _selectedCard._stationPos.y + 12))) {
+ for (int k = 0; k <= 7; k++) {
+ if (_gameBoardSide[3]._outpostStation[k]._cardId != 0) {
+ playCentralOutpostCard(&_selectedCard, 3);
+ return;
+ }
+ }
+ actionDisplay(1330, 74, 159, 10, 1, 200, 0, 7, 0, 154, 154);
+ } else if (_gameBoardSide[1]._emptyStationPos.isIn(Common::Point(_selectedCard._stationPos.x + 12, _selectedCard._stationPos.y + 12))) {
+ for (int k = 0; k <= 7; k++) {
+ if (_gameBoardSide[1]._outpostStation[k]._cardId == 0) {
+ playCentralOutpostCard(&_selectedCard, 1);
+ return;
+ }
+ }
+ actionDisplay(1330, 74, 159, 10, 1, 200, 0, 7, 0, 154, 154);
+ } else {
+ actionDisplay(1330, 128, 159, 10, 1, 200, 0, 7, 0, 154, 154);
+ }
+ } else if (_selectedCard._cardId == 25) {
+ // Thief card
+ if (_gameBoardSide[0]._emptyStationPos.isIn(Common::Point(_selectedCard._stationPos.x + 12, _selectedCard._stationPos.y + 12))) {
+ if ( (_gameBoardSide[0]._handCard[0]._cardId != 0)
+ || (_gameBoardSide[0]._handCard[1]._cardId != 0)
+ || (_gameBoardSide[0]._handCard[2]._cardId != 0)
+ || (_gameBoardSide[0]._handCard[3]._cardId != 0) ) {
+ int k;
+ for (k = 0; k <= 3; k++){
+ if (_gameBoardSide[2]._handCard[k]._cardId == 0)
+ break;
+ }
+ playThieftCard(2, &_gameBoardSide[2]._handCard[k], 0);
+ return;
+ } else {
+ actionDisplay(1330, 99, 159, 10, 1, 200, 0, 7, 0, 154, 154);
+ }
+ } else if (_gameBoardSide[1]._emptyStationPos.isIn(Common::Point(_selectedCard._stationPos.x + 12, _selectedCard._stationPos.y + 12))) {
+ if ( (_gameBoardSide[1]._handCard[0]._cardId != 0)
+ || (_gameBoardSide[1]._handCard[1]._cardId != 0)
+ || (_gameBoardSide[1]._handCard[2]._cardId != 0)
+ || (_gameBoardSide[1]._handCard[3]._cardId != 0) ) {
+ int k;
+ for (k = 0; k <= 3; k++){
+ if (_gameBoardSide[2]._handCard[k]._cardId == 0)
+ break;
+ }
+ playThieftCard(2, &_gameBoardSide[2]._handCard[k], 1);
+ return;
+ } else {
+ actionDisplay(1330, 99, 159, 10, 1, 200, 0, 7, 0, 154, 154);
+ }
+ }
+
+ if (_gameBoardSide[3]._emptyStationPos.isIn(Common::Point(_selectedCard._stationPos.x + 12, _selectedCard._stationPos.y + 12))) {
+ if ( (_gameBoardSide[3]._handCard[0]._cardId != 0)
+ || (_gameBoardSide[3]._handCard[1]._cardId != 0)
+ || (_gameBoardSide[3]._handCard[2]._cardId != 0)
+ || (_gameBoardSide[3]._handCard[3]._cardId != 0) ) {
+ int k;
+ for (k = 0; k <= 3; k++){
+ if (_gameBoardSide[2]._handCard[k]._cardId == 0)
+ break;
+ }
+ playThieftCard(2, &_gameBoardSide[2]._handCard[k], 3);
+ return;
+ } else {
+ actionDisplay(1330, 99, 159, 10, 1, 200, 0, 7, 0, 154, 154);
+ }
+ } else {
+ actionDisplay(1330, 129, 159, 10, 1, 200, 0, 7, 0, 154, 154);
+ }
+ } else if (_selectedCard._cardId == 29) {
+ // Interceptor cards are used to prevent collision
+ actionDisplay(1330, 136, 159, 10, 1, 200, 0, 7, 0, 154, 154);
+ } else if (_selectedCard._cardId == 27) {
+ actionDisplay(1330, 137, 159, 10, 1, 200, 0, 7, 0, 154, 154);
+ }
+ } else if (_gameBoardSide[0]._delayCard.isIn(Common::Point(_selectedCard._stationPos.x + 12, _selectedCard._stationPos.y + 12))) {
+ if (_gameBoardSide[0]._delayCard._cardId != 0) {
+ actionDisplay(1330, 15, 159, 10, 1, 200, 0, 7, 0, 154, 154);
+ } else if (!isAttackPossible(0, _selectedCard._cardId)) {
+ switch (_selectedCard._cardId) {
+ case 10:
+ actionDisplay(1330, 66, 159, 10, 1, 200, 0, 7, 0, 154, 154);
+ break;
+ case 12:
+ actionDisplay(1330, 70, 159, 10, 1, 200, 0, 7, 0, 154, 154);
+ break;
+ case 15:
+ actionDisplay(1330, 82, 159, 10, 1, 200, 0, 7, 0, 154, 154);
+ break;
+ case 17:
+ actionDisplay(1330, 86, 159, 10, 1, 200, 0, 7, 0, 154, 154);
+ break;
+ case 18:
+ actionDisplay(1330, 88, 159, 10, 1, 200, 0, 7, 0, 154, 154);
+ break;
+ case 19:
+ actionDisplay(1330, 90, 159, 10, 1, 200, 0, 7, 0, 154, 154);
+ break;
+ case 20:
+ actionDisplay(1330, 92, 159, 10, 1, 200, 0, 7, 0, 154, 154);
+ break;
+ case 21:
+ actionDisplay(1330, 94, 159, 10, 1, 200, 0, 7, 0, 154, 154);
+ break;
+ default:
+ break;
+ }
+ } else {
+ playDelayCard(&_selectedCard, &_gameBoardSide[0]._delayCard);
+ return;
+ }
+ } else if (_gameBoardSide[3]._delayCard.isIn(Common::Point(_selectedCard._stationPos.x + 12, _selectedCard._stationPos.y + 12))) {
+ if (_gameBoardSide[3]._delayCard._cardId != 0) {
+ actionDisplay(1330, 17, 159, 10, 1, 200, 0, 7, 0, 154, 154);
+ } else if (!isAttackPossible(3, _selectedCard._cardId)) {
+ switch (_selectedCard._cardId) {
+ case 10:
+ actionDisplay(1330, 66, 159, 10, 1, 200, 0, 7, 0, 154, 154);
+ break;
+ case 12:
+ actionDisplay(1330, 70, 159, 10, 1, 200, 0, 7, 0, 154, 154);
+ break;
+ case 15:
+ actionDisplay(1330, 82, 159, 10, 1, 200, 0, 7, 0, 154, 154);
+ break;
+ case 17:
+ actionDisplay(1330, 86, 159, 10, 1, 200, 0, 7, 0, 154, 154);
+ break;
+ case 18:
+ actionDisplay(1330, 88, 159, 10, 1, 200, 0, 7, 0, 154, 154);
+ break;
+ case 19:
+ actionDisplay(1330, 90, 159, 10, 1, 200, 0, 7, 0, 154, 154);
+ break;
+ case 20:
+ actionDisplay(1330, 92, 159, 10, 1, 200, 0, 7, 0, 154, 154);
+ break;
+ case 21:
+ actionDisplay(1330, 94, 159, 10, 1, 200, 0, 7, 0, 154, 154);
+ break;
+ default:
+ break;
+ }
+ } else {
+ playDelayCard(&_selectedCard, &_gameBoardSide[3]._delayCard);
+ return;
+ }
+ } else if (_gameBoardSide[1]._delayCard.isIn(Common::Point(_selectedCard._stationPos.x + 12, _selectedCard._stationPos.y + 12))) {
+ if (_gameBoardSide[1]._delayCard._cardId != 0) {
+ actionDisplay(1330, 19, 159, 10, 1, 200, 0, 7, 0, 154, 154);
+ } else if (!isAttackPossible(1, _selectedCard._cardId)) {
+ switch (_selectedCard._cardId) {
+ case 10:
+ actionDisplay(1330, 66, 159, 10, 1, 200, 0, 7, 0, 154, 154);
+ break;
+ case 12:
+ actionDisplay(1330, 70, 159, 10, 1, 200, 0, 7, 0, 154, 154);
+ break;
+ case 15:
+ actionDisplay(1330, 82, 159, 10, 1, 200, 0, 7, 0, 154, 154);
+ break;
+ case 17:
+ actionDisplay(1330, 86, 159, 10, 1, 200, 0, 7, 0, 154, 154);
+ break;
+ case 18:
+ actionDisplay(1330, 88, 159, 10, 1, 200, 0, 7, 0, 154, 154);
+ break;
+ case 19:
+ actionDisplay(1330, 90, 159, 10, 1, 200, 0, 7, 0, 154, 154);
+ break;
+ case 20:
+ actionDisplay(1330, 92, 159, 10, 1, 200, 0, 7, 0, 154, 154);
+ break;
+ case 21:
+ actionDisplay(1330, 94, 159, 10, 1, 200, 0, 7, 0, 154, 154);
+ break;
+ default:
+ break;
+ }
+ } else {
+ playDelayCard(&_selectedCard, &_gameBoardSide[1]._delayCard);
+ return;
+ }
+ } else {
+ actionDisplay(1330, 38, 159, 10, 1, 200, 0, 7, 0, 154, 154);
+ }
+ }
+ } else {
+ g_globals->_scenePalette.signalListeners();
+ R2_GLOBALS._sceneObjects->draw();
+ g_globals->_events.delay(g_globals->_sceneHandler->_delayTicks);
+ }
+
+ g_globals->_sceneObjects->recurse(SceneHandler::dispatchObject);
+ }
+}
+
+void Scene1337::updateCursorId(int cursorId, bool updateFl) {
+ if ((R2_GLOBALS._v57709 != 0) || (R2_GLOBALS._v5780C != 0))
+ return;
+
+ R2_GLOBALS._mouseCursorId = cursorId;
+
+ if (updateFl) {
+ R2_GLOBALS._mouseCursorId++;
+
+ if (R2_GLOBALS._mouseCursorId < 1)
+ R2_GLOBALS._mouseCursorId = 2;
+
+ if (R2_GLOBALS._mouseCursorId > 2)
+ R2_GLOBALS._mouseCursorId = 1;
+ }
+
+ // The original was using an intermediate function to call setCursorData.
+ // It has been removed to improve readability
+ if (R2_GLOBALS._mouseCursorId == 1) {
+ R2_GLOBALS._v57810 = 200;
+ setCursorData(5, 1, 4);
+ } else if (R2_GLOBALS._mouseCursorId == 2) {
+ R2_GLOBALS._v57810 = 300;
+ setCursorData(5, 1, 5);
+ } else {
+ R2_GLOBALS._v57810 = 0;
+ setCursorData(5, 0, 0);
+ }
+}
+
+void Scene1337::setCursorData(int resNum, int rlbNum, int frameNum) {
+ _cursorCurRes = resNum;
+ _cursorCurStrip = rlbNum;
+ _cursorCurFrame = frameNum;
+
+ if (!frameNum) {
+ // Should be a hardcoded cursor displaying only a dot.
+ // FIXME: Use another cursor when possible
+ R2_GLOBALS._events.setCursor(CURSOR_CROSSHAIRS);
+ } else {
+ // TODO: The original was using some resource caching, which was useless and complex
+ // and which has been removed. This cursor behavior clearly made intensive use of this caching...
+ // We now have to find a way to cache these cursor pointers and avoid loading them multiple times per seconds
+ uint size;
+ byte *cursor = g_resourceManager->getSubResource(resNum, rlbNum, frameNum, &size);
+ // Decode the cursor
+ GfxSurface s = surfaceFromRes(cursor);
+
+ Graphics::Surface surface = s.lockSurface();
+ const byte *cursorData = (const byte *)surface.getPixels();
+ CursorMan.replaceCursor(cursorData, surface.w, surface.h, s._centroid.x, s._centroid.y, s._transColor);
+ s.unlockSurface();
+
+ DEALLOCATE(cursor);
+ }
+}
+
+void Scene1337::subD18F5() {
+ if (R2_GLOBALS._v57709 == 0)
+ // The original restores a copy of the default cursor (the hand), which isn't possible with our implementation
+ // We reload that cursor instead.
+ setCursorData(5, 1, 4);
+
+ ++R2_GLOBALS._v57709;
+}
+
+void Scene1337::subD1917() {
+ if (R2_GLOBALS._v57709 != 0) {
+ R2_GLOBALS._v57709--;
+ if (R2_GLOBALS._v57709 == 0) {
+ // The original was using an intermediate function to call setCursorData.
+ // It has been removed to improve readability
+ setCursorData(5, _cursorCurStrip, _cursorCurFrame);
+ }
+ }
+}
+
+void Scene1337::subD1940(bool flag) {
+ if (flag)
+ ++R2_GLOBALS._v5780C;
+ else if (R2_GLOBALS._v5780C != 0)
+ --R2_GLOBALS._v5780C;
+}
+
+void Scene1337::subD1975(int arg1, int arg2) {
+ // No implementation required in ScummVM: Mouse handling with tons of caching
+}
+
+void Scene1337::OptionsDialog::show() {
+ OptionsDialog *dlg = new OptionsDialog();
+ dlg->draw();
+
+ // Show the dialog
+ GfxButton *btn = dlg->execute(NULL);
+
+ // Figure out the new selected character
+ if (btn == &dlg->_quitGame)
+ R2_GLOBALS._sceneManager.changeScene(125);
+ else if (btn == &dlg->_restartGame)
+ R2_GLOBALS._sceneManager.changeScene(1330);
+
+ // Remove the dialog
+ dlg->remove();
+ delete dlg;
+}
+
+Scene1337::OptionsDialog::OptionsDialog() {
+ // Set the elements text
+ Scene1337 *scene = (Scene1337 *)R2_GLOBALS._sceneManager._scene;
+ _autoplay.setText(scene->_autoplay ? AUTO_PLAY_ON : AUTO_PLAY_OFF);
+ _restartGame.setText(START_NEW_CARD_GAME);
+ _quitGame.setText(QUIT_CARD_GAME);
+ _continueGame.setText(CONTINUE_CARD_GAME);
+
+ // Set position of the elements
+ _autoplay._bounds.moveTo(5, 2);
+ _restartGame._bounds.moveTo(5, _autoplay._bounds.bottom + 2);
+ _quitGame._bounds.moveTo(5, _restartGame._bounds.bottom + 2);
+ _continueGame._bounds.moveTo(5, _quitGame._bounds.bottom + 2);
+
+ // Add the items to the dialog
+ addElements(&_autoplay, &_restartGame, &_quitGame, &_continueGame, NULL);
+
+ // Set the dialog size and position
+ frame();
+ _bounds.collapse(-6, -6);
+ setCenter(160, 100);
+}
+
+GfxButton *Scene1337::OptionsDialog::execute(GfxButton *defaultButton) {
+ _gfxManager.activate();
+
+ // Event loop
+ GfxButton *selectedButton = NULL;
+
+ bool breakFlag = false;
+ while (!g_vm->shouldQuit() && !breakFlag) {
+ Event event;
+ while (g_globals->_events.getEvent(event) && !breakFlag) {
+ // Adjust mouse positions to be relative within the dialog
+ event.mousePos.x -= _gfxManager._bounds.left;
+ event.mousePos.y -= _gfxManager._bounds.top;
+
+ for (GfxElementList::iterator i = _elements.begin(); i != _elements.end(); ++i) {
+ if ((*i)->process(event))
+ selectedButton = static_cast<GfxButton *>(*i);
+ }
+
+ if (selectedButton == &_autoplay) {
+ // Toggle Autoplay
+ selectedButton = NULL;
+ Scene1337 *scene = (Scene1337 *)R2_GLOBALS._sceneManager._scene;
+ scene->_autoplay = !scene->_autoplay;
+
+ _autoplay.setText(scene->_autoplay ? AUTO_PLAY_ON : AUTO_PLAY_OFF);
+ _autoplay.draw();
+ } else if (selectedButton) {
+ breakFlag = true;
+ break;
+ } else if (!event.handled) {
+ if ((event.eventType == EVENT_KEYPRESS) && (event.kbd.keycode == Common::KEYCODE_ESCAPE)) {
+ selectedButton = NULL;
+ breakFlag = true;
+ break;
+ }
+ }
+ }
+
+ g_system->delayMillis(10);
+ GLOBALS._screenSurface.updateScreen();
+ }
+
+ _gfxManager.deactivate();
+ return selectedButton;
+}
+
+} // End of namespace Ringworld2
+} // End of namespace TsAGE
diff --git a/engines/tsage/ringworld2/ringworld2_outpost.h b/engines/tsage/ringworld2/ringworld2_outpost.h
new file mode 100644
index 0000000000..6c6952c196
--- /dev/null
+++ b/engines/tsage/ringworld2/ringworld2_outpost.h
@@ -0,0 +1,259 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef TSAGE_RINGWORLD2_OUTPOST_H
+#define TSAGE_RINGWORLD2_OUTPOST_H
+
+#include "tsage/events.h"
+#include "tsage/core.h"
+#include "tsage/scenes.h"
+#include "tsage/globals.h"
+#include "tsage/sound.h"
+#include "tsage/ringworld2/ringworld2_logic.h"
+
+namespace TsAGE {
+
+namespace Ringworld2 {
+
+using namespace TsAGE;
+
+class Scene1337 : public SceneExt {
+ class OptionsDialog: public GfxDialog {
+ private:
+ GfxButton _autoplay;
+ GfxButton _restartGame;
+ GfxButton _quitGame;
+ GfxButton _continueGame;
+
+ OptionsDialog();
+ virtual ~OptionsDialog() {}
+ virtual GfxButton *execute(GfxButton *defaultButton);
+ public:
+ static void show();
+ };
+
+ class Card: public SceneHotspot {
+ public:
+ SceneObject _card;
+
+ int _cardId;
+ Common::Point _stationPos;
+
+ Card();
+ void synchronize(Serializer &s);
+ bool isIn(Common::Point pt);
+ };
+
+ class GameBoardSide: public SceneHotspot {
+ public:
+ Card _handCard[4];
+ Card _outpostStation[8];
+ Card _delayCard;
+ Card _emptyStationPos;
+
+ Common::Point _card1Pos;
+ Common::Point _card2Pos;
+ Common::Point _card3Pos;
+ Common::Point _card4Pos;
+ int _frameNum;
+
+ GameBoardSide();
+ void synchronize(Serializer &s);
+ };
+
+ class Action1337: public Action {
+ public:
+ void waitFrames(int32 frameCount);
+ };
+
+ class Action1: public Action1337 {
+ public:
+ void signal();
+ };
+ class Action2: public Action1337 {
+ public:
+ void signal();
+ };
+ class Action3: public Action1337 {
+ public:
+ void signal();
+ };
+ class Action4: public Action1337 {
+ public:
+ void signal();
+ };
+ class Action5: public Action1337 {
+ public:
+ void signal();
+ };
+ class Action6: public Action1337 {
+ public:
+ void signal();
+ };
+ class Action7: public Action1337 {
+ public:
+ void signal();
+ };
+ class Action8: public Action1337 {
+ public:
+ void signal();
+ };
+ class Action9: public Action1337 {
+ public:
+ void signal();
+ };
+ class Action10: public Action1337 {
+ public:
+ void signal();
+ };
+ class Action11: public Action1337 {
+ public:
+ void signal();
+ };
+ class Action12: public Action1337 {
+ public:
+ void signal();
+ };
+ class Action13: public Action1337 {
+ public:
+ void signal();
+ };
+public:
+ Action1 _action1;
+ Action2 _action2;
+ Action3 _action3;
+ Action4 _action4;
+ Action5 _action5;
+ Action6 _action6;
+ Action7 _action7;
+ Action8 _action8;
+ Action9 _action9;
+ Action10 _action10;
+ Action11 _action11;
+ Action12 _action12;
+ Action13 _action13;
+
+ typedef void (Scene1337::*FunctionPtrType)();
+ FunctionPtrType _delayedFunction;
+
+ bool _autoplay;
+ bool _shuffleEndedFl;
+ bool _showPlayerTurn;
+ bool _displayHelpFl;
+ bool _instructionsDisplayedFl;
+
+ // Discarded cards are put in the available cards pile, with an higher index so there no conflict
+ int _currentDiscardIndex;
+ int _availableCardsPile[100];
+ int _cardsAvailableNumb;
+ int _currentPlayerNumb;
+ int _actionPlayerIdx;
+ int _actionVictimIdx;
+ int _winnerId;
+ int _instructionsWaitCount;
+ int _cursorCurRes;
+ int _cursorCurStrip;
+ int _cursorCurFrame;
+
+ ASound _aSound1;
+ ASound _aSound2;
+ GameBoardSide _gameBoardSide[4];
+ SceneActor _helpIcon;
+ SceneActor _stockPile;
+ SceneItem _actionItem;
+ SceneObject _currentPlayerArrow;
+
+ Card *_actionCard1;
+ Card *_actionCard2;
+ Card *_actionCard3;
+ Card _animatedCard;
+ Card _shuffleAnimation;
+ Card _discardedPlatformCard;
+ Card _selectedCard;
+ Card _discardPile;
+ Card _stockCard;
+
+ SceneObject _upperDisplayCard[8];
+ SceneObject _lowerDisplayCard[8];
+
+ Scene1337();
+ virtual void synchronize(Serializer &s);
+
+ void actionDisplay(int resNum, int lineNum, int x, int y, int keepOnScreen, int width, int textMode, int fontNum, int colFG, int colBGExt, int colFGExt);
+ void setAnimationInfo(Card *card);
+ void handleNextTurn();
+ void handlePlayerTurn();
+ bool isStationCard(int cardId);
+ bool isStopConstructionCard(int cardId);
+ int getStationId(int playerId, int handCardId);
+ int findPlatformCardInHand(int playerId);
+ int findMeteorCardInHand(int playerId);
+ int findThieftCardInHand(int playerId);
+ int isDelayCard(int cardId);
+ int getStationCardId(int cardId);
+ void handlePlayer01Discard(int playerId);
+ void playThieftCard(int playerId, Card *card, int victimId);
+ int getPreventionCardId(int cardId);
+ bool isAttackPossible(int victimId, int cardId);
+ int getPlayerWithOutpost(int playerId);
+ bool checkAntiDelayCard(int delayCardId, int cardId);
+ void playStationCard(Card *station, Card *platform);
+ void playDelayCard(Card *card, Card *dest);
+ void playPlatformCard(Card *card, Card *dest);
+ void playAntiDelayCard(Card *card, Card *dest);
+ Card *getStationCard(int arg1);
+ void playCentralOutpostCard(Card *card, int playerId);
+ int getRandomCardFromHand(int playerId);
+ void discardCard(Card *card);
+ void subC4CD2();
+ void subC4CEC();
+ void playInterceptorCard(Card *subObj1, Card *subObj2);
+ void displayDialog(int dialogNumb);
+ void subPostInit();
+ void displayInstructions();
+ void suggestInstructions();
+ void shuffleCards();
+ void dealCards();
+ void showOptionsDialog();
+ void handleClick(int arg1, Common::Point pt);
+ void handlePlayer0();
+ void handlePlayer1();
+ void handlePlayer2();
+ void handlePlayer3();
+ void handleAutoplayPlayer2();
+ void updateCursorId(int arg1, bool arg2);
+ void setCursorData(int resNum, int rlbNum, int frameNum);
+ void subD18F5();
+ void subD1917();
+ void subD1940(bool flag);
+ void subD1975(int arg1, int arg2);
+
+ virtual void postInit(SceneObjectList *OwnerList = NULL);
+ virtual void remove();
+ virtual void process(Event &event);
+ virtual void dispatch();
+};
+
+} // End of namespace Ringworld2
+} // End of namespace TsAGE
+
+#endif
diff --git a/engines/tsage/ringworld2/ringworld2_scenes0.cpp b/engines/tsage/ringworld2/ringworld2_scenes0.cpp
index b82565332a..573cbbb29a 100644
--- a/engines/tsage/ringworld2/ringworld2_scenes0.cpp
+++ b/engines/tsage/ringworld2/ringworld2_scenes0.cpp
@@ -627,7 +627,7 @@ void Scene125::postInit(SceneObjectList *OwnerList) {
SceneExt::postInit();
_palette.loadPalette(0);
- if (R2_GLOBALS._sceneManager._previousScene != 125)
+ if ((R2_GLOBALS._sceneManager._previousScene != 125) && (R2_GLOBALS._sceneManager._previousScene != 1337) && (R2_GLOBALS._sceneManager._previousScene != 1330))
// Save the prior scene to return to when the console is turned off
R2_GLOBALS._player._oldCharacterScene[R2_QUINN] = R2_GLOBALS._sceneManager._previousScene;
diff --git a/engines/tsage/ringworld2/ringworld2_scenes1.cpp b/engines/tsage/ringworld2/ringworld2_scenes1.cpp
index e2c22bd0b4..81dc05e2a4 100644
--- a/engines/tsage/ringworld2/ringworld2_scenes1.cpp
+++ b/engines/tsage/ringworld2/ringworld2_scenes1.cpp
@@ -1321,5469 +1321,6 @@ void Scene1100::saveCharacter(int characterIndex) {
}
/*--------------------------------------------------------------------------
- * Scene 1200 - Air Ducts Maze
- *
- *--------------------------------------------------------------------------*/
-
-Scene1200::Scene1200() {
- _nextCrawlDirection = 0;
- _field414 = 0;
- _field416 = 0;
- _field418 = 0;
- _field41A = 0;
- _fixupMaze = false;
-}
-
-void Scene1200::synchronize(Serializer &s) {
- SceneExt::synchronize(s);
-
- s.syncAsSint16LE(_nextCrawlDirection);
- s.syncAsSint16LE(_field414);
- s.syncAsSint16LE(_field416);
- s.syncAsSint16LE(_field418);
- s.syncAsSint16LE(_field41A);
- s.syncAsSint16LE(_fixupMaze);
-}
-
-Scene1200::LaserPanel::LaserPanel() {
-}
-
-void Scene1200::LaserPanel::Jumper::init(int state) {
- _state = state;
-
- SceneActor::postInit();
- setup(1003, 1, 1);
- fixPriority(255);
-
- switch (_state) {
- case 1:
- switch (R2_GLOBALS._ductMazePanel1State) {
- case 1:
- setFrame2(2);
- setPosition(Common::Point(129, 101));
- break;
- case 2:
- setFrame2(3);
- setPosition(Common::Point(135, 95));
- break;
- default:
- break;
- }
- break;
- case 2:
- switch (R2_GLOBALS._ductMazePanel2State) {
- case 1:
- setFrame2(2);
- setPosition(Common::Point(152, 101));
- break;
- case 2:
- setFrame2(3);
- setPosition(Common::Point(158, 122));
- break;
- case 3:
- setFrame2(3);
- setPosition(Common::Point(135, 122));
- break;
- default:
- break;
- }
- break;
- case 3:
- switch (R2_GLOBALS._ductMazePanel3State) {
- case 1:
- setFrame2(3);
- setPosition(Common::Point(158, 95));
- break;
- case 2:
- setFrame2(2);
- setPosition(Common::Point(175, 101));
- break;
- default:
- break;
- }
- break;
- default:
- break;
- }
-
- setDetails(1200, 12, -1, -1, 2, (SceneItem *) NULL);
-}
-
-bool Scene1200::LaserPanel::Jumper::startAction(CursorType action, Event &event) {
- if (action != CURSOR_USE)
- return SceneActor::startAction(action, event);
-
- R2_GLOBALS._sound2.play(260);
- switch (_state) {
- case 1:
- if (R2_GLOBALS._ductMazePanel1State == 1) {
- R2_GLOBALS._ductMazePanel1State = 2;
- setFrame2(3);
- setPosition(Common::Point(135, 95));
- } else {
- R2_GLOBALS._ductMazePanel1State = 1;
- setFrame2(2);
- setPosition(Common::Point(129, 101));
- }
- break;
- case 2:
- ++R2_GLOBALS._ductMazePanel2State;
- if (R2_GLOBALS._ductMazePanel2State == 4)
- R2_GLOBALS._ductMazePanel2State = 1;
-
- switch (R2_GLOBALS._ductMazePanel2State) {
- case 1:
- setFrame2(2);
- setPosition(Common::Point(152, 101));
- break;
- case 2:
- setFrame2(3);
- setPosition(Common::Point(158, 122));
- break;
- case 3:
- setFrame2(3);
- setPosition(Common::Point(135, 122));
- break;
- default:
- break;
- }
- break;
- case 3:
- if (R2_GLOBALS._ductMazePanel3State == 1) {
- R2_GLOBALS._ductMazePanel3State = 2;
- setFrame2(2);
- setPosition(Common::Point(175, 101));
- } else {
- R2_GLOBALS._ductMazePanel3State = 1;
- setFrame2(3);
- setPosition(Common::Point(158, 95));
- }
- break;
- default:
- break;
- }
-
- Scene1200 *scene = (Scene1200 *)R2_GLOBALS._sceneManager._scene;
- scene->_field418 = 0;
-
- if ((R2_GLOBALS._ductMazePanel1State == 1) && (R2_GLOBALS._ductMazePanel2State == 1) && (R2_GLOBALS._ductMazePanel3State == 1))
- scene->_field418 = 1;
- else if ((R2_GLOBALS._ductMazePanel1State == 2) && (R2_GLOBALS._ductMazePanel2State == 1) && (R2_GLOBALS._ductMazePanel3State == 1))
- scene->_field418 = 2;
- else if ((R2_GLOBALS._ductMazePanel1State == 2) && (R2_GLOBALS._ductMazePanel2State == 1) && (R2_GLOBALS._ductMazePanel3State == 2))
- scene->_field418 = 3;
- else if ((R2_GLOBALS._ductMazePanel1State == 2) && (R2_GLOBALS._ductMazePanel2State == 3) && (R2_GLOBALS._ductMazePanel3State == 1))
- scene->_field418 = 4;
-
- return true;
-}
-
-void Scene1200::LaserPanel::postInit(SceneObjectList *OwnerList) {
- Scene1200 *scene = (Scene1200 *)R2_GLOBALS._sceneManager._scene;
-
- scene->_field41A = 1;
- R2_GLOBALS._events.setCursor(CURSOR_USE);
- setup2(1003, 1, 1, 100, 40);
- setup3(1200, 11, -1, -1);
- R2_GLOBALS._sound2.play(259);
- _jumper1.init(1);
- _jumper2.init(2);
- _jumper3.init(3);
-
- R2_GLOBALS._player._canWalk = false;
-}
-
-void Scene1200::LaserPanel::remove() {
- Scene1200 *scene = (Scene1200 *)R2_GLOBALS._sceneManager._scene;
-
- scene->_field41A = 0;
- scene->_sceneAreas.remove(&_jumper1);
- scene->_sceneAreas.remove(&_jumper2);
- scene->_sceneAreas.remove(&_jumper3);
- _jumper1.remove();
- _jumper2.remove();
- _jumper3.remove();
-
- ModalWindow::remove();
- R2_GLOBALS._player._canWalk = true;
-}
-
-void Scene1200::postInit(SceneObjectList *OwnerList) {
- loadScene(1200);
- SceneExt::postInit();
-
- if (R2_GLOBALS._sceneManager._previousScene < 3200)
- R2_GLOBALS._sound1.play(257);
-
- _nextCrawlDirection = CRAWL_EAST;
- _field414 = 0;
- _field416 = 0;
- _field418 = 0;
- _field41A = 0;
-
- if ((R2_GLOBALS._ductMazePanel1State == 1) && (R2_GLOBALS._ductMazePanel2State == 1) && (R2_GLOBALS._ductMazePanel3State == 1))
- _field418 = 1;
- else if ((R2_GLOBALS._ductMazePanel1State == 2) && (R2_GLOBALS._ductMazePanel2State == 1) && (R2_GLOBALS._ductMazePanel3State == 1))
- _field418 = 2;
- else if ((R2_GLOBALS._ductMazePanel1State == 2) && (R2_GLOBALS._ductMazePanel2State == 1) && (R2_GLOBALS._ductMazePanel3State == 2))
- _field418 = 3;
- else if ((R2_GLOBALS._ductMazePanel1State == 2) && (R2_GLOBALS._ductMazePanel2State == 3) && (R2_GLOBALS._ductMazePanel3State == 1))
- _field418 = 4;
-
- R2_GLOBALS._player.postInit();
- R2_GLOBALS._player.disableControl();
- R2_GLOBALS._player.setup(3156, 1, 6);
- R2_GLOBALS._player.setPosition(Common::Point(160, 70));
- R2_GLOBALS._player._numFrames = 10;
- R2_GLOBALS._player._oldCharacterScene[R2_MIRANDA] = 1200;
-
- _actor1.postInit();
- _actor1.hide();
-
- _mazeUI.setDisplayBounds(Rect(110, 20, 210, 120));
-
- _mazeUI.postInit();
- _mazeUI.load(1);
- _mazeUI.setMazePosition(R2_GLOBALS._ventCellPos);
-
- R2_GLOBALS._player.enableControl();
- _item1.setDetails(Rect(0, 0, 320, 200), 1200, 0, 1, 2, 1, NULL);
-}
-
-void Scene1200::signal() {
- switch (_sceneMode++) {
- case 1:
- // No break on purpose
- case 1200:
- // No break on purpose
- case 1201:
- // No break on purpose
- case 1202:
- // No break on purpose
- case 1203:
- R2_GLOBALS._player.enableControl();
- // CHECKME: The original is calling _eventManager.waitEvent();
- _sceneMode = 2;
- break;
- case 10:
- _field416 = 1;
- _field414 = 6;
- R2_GLOBALS._player._numFrames = 5;
- R2_GLOBALS._player.setStrip(1);
- R2_GLOBALS._player.setFrame(5);
- R2_GLOBALS._player.animate(ANIM_MODE_6, this);
- break;
- case 11:
- // No break on purpose
- case 21:
- // No break on purpose
- case 31:
- // No break on purpose
- case 41:
- _field416 = 0;
- break;
- case 12:
- _field414 = 14;
- R2_GLOBALS._player._numFrames = 10;
- R2_GLOBALS._player.setup(3155, 1, 4);
- R2_GLOBALS._player.setPosition(Common::Point(160, 70));
- R2_GLOBALS._player.animate(ANIM_MODE_2, NULL);
- break;
- case 13:
- // No break on purpose
- case 16:
- // No break on purpose
- case 23:
- // No break on purpose
- case 26:
- // No break on purpose
- case 33:
- // No break on purpose
- case 36:
- // No break on purpose
- case 43:
- // No break on purpose
- case 46:
- R2_GLOBALS._player.setFrame(4);
- _sceneMode = 1;
- setAction(&_sequenceManager, this, 1, &R2_GLOBALS._player, NULL);
- break;
- case 15:
- // No break on purpose
- case 25:
- // No break on purpose
- case 35:
- // No break on purpose
- case 45:
- _field414 = 20;
- R2_GLOBALS._player.animate(ANIM_MODE_2, NULL);
- break;
- case 20:
- _field416 = 1;
- _field414 = 6;
- R2_GLOBALS._player._numFrames = 5;
- R2_GLOBALS._player.setStrip(2);
- R2_GLOBALS._player.setFrame(5);
- R2_GLOBALS._player.animate(ANIM_MODE_6, this);
- break;
- case 22:
- _field414 = 14;
- R2_GLOBALS._player._numFrames = 10;
- R2_GLOBALS._player.setup(3155, 2, 4);
- R2_GLOBALS._player.setPosition(Common::Point(160, 70));
- R2_GLOBALS._player.animate(ANIM_MODE_2, NULL);
- break;
- case 30:
- _field416 = 1;
- _field414 = 6;
- R2_GLOBALS._player._numFrames = 5;
- R2_GLOBALS._player.setStrip(3);
- R2_GLOBALS._player.setFrame(5);
- R2_GLOBALS._player.animate(ANIM_MODE_6, this);
- break;
- case 32:
- _field414 = 14;
- R2_GLOBALS._player._numFrames = 10;
- R2_GLOBALS._player.setup(3155, 3, 4);
- R2_GLOBALS._player.setPosition(Common::Point(160, 70));
- R2_GLOBALS._player.animate(ANIM_MODE_2, NULL);
- break;
- case 40:
- _field416 = 1;
- _field414 = 6;
- R2_GLOBALS._player._numFrames = 5;
- R2_GLOBALS._player.setStrip(4);
- R2_GLOBALS._player.setFrame(5);
- R2_GLOBALS._player.animate(ANIM_MODE_6, this);
- break;
- case 42:
- _field414 = 14;
- R2_GLOBALS._player._numFrames = 10;
- R2_GLOBALS._player.setup(3155, 4, 4);
- R2_GLOBALS._player.setPosition(Common::Point(160, 70));
- R2_GLOBALS._player.animate(ANIM_MODE_2, NULL);
- break;
- case 50:
- // No break on purpose
- case 55:
- // No break on purpose
- case 60:
- R2_GLOBALS._player.setup(3156, 5, 1);
- R2_GLOBALS._player._numFrames = 5;
- R2_GLOBALS._player.animate(ANIM_MODE_5, this);
- break;
- case 51:
- // No break on purpose
- case 56:
- // No break on purpose
- case 117:
- R2_GLOBALS._player.setup(3157, 1, 1);
- R2_GLOBALS._player.animate(ANIM_MODE_5, this);
- break;
- case 52:
- // No break on purpose
- case 82:
- // No break on purpose
- case 118:
- R2_GLOBALS._player.setup(3156, 3, 6);
- _sceneMode = 1;
- setAction(&_sequenceManager, this, 1, &R2_GLOBALS._player, NULL);
- break;
- case 57:
- // No break on purpose
- case 91:
- // No break on purpose
- case 96:
- R2_GLOBALS._player.setup(3157, 2, 1);
- R2_GLOBALS._player.animate(ANIM_MODE_5, this);
- break;
- case 58:
- // No break on purpose
- case 92:
- // No break on purpose
- case 122:
- R2_GLOBALS._player.setup(3156, 2, 6);
- _sceneMode = 1;
- setAction(&_sequenceManager, this, 1, &R2_GLOBALS._player, NULL);
- break;
- case 61:
- R2_GLOBALS._player.setup(3157, 4, 5);
- R2_GLOBALS._player.animate(ANIM_MODE_6, this);
- break;
- case 62:
- // No break on purpose
- case 72:
- // No break on purpose
- case 98:
- R2_GLOBALS._player.setup(3156, 4, 6);
- _sceneMode = 1;
- setAction(&_sequenceManager, this, 1, &R2_GLOBALS._player, NULL);
- break;
- case 70:
- // No break on purpose
- case 75:
- // No break on purpose
- case 80:
- R2_GLOBALS._player.setup(3156, 6, 1);
- R2_GLOBALS._player._numFrames = 5;
- R2_GLOBALS._player.animate(ANIM_MODE_5, this);
- break;
- case 71:
- // No break on purpose
- case 76:
- // No break on purpose
- case 97:
- R2_GLOBALS._player.setup(3157, 3, 1);
- R2_GLOBALS._player.animate(ANIM_MODE_5, this);
- break;
- case 77:
- // No break on purpose
- case 111:
- // No break on purpose
- case 116:
- R2_GLOBALS._player.setup(3157, 4, 1);
- R2_GLOBALS._player.animate(ANIM_MODE_5, this);
- break;
- case 78:
- // No break on purpose
- case 102:
- // No break on purpose
- case 112:
- R2_GLOBALS._player.setup(3156, 1, 6);
- _sceneMode = 1;
- setAction(&_sequenceManager, this, 1, &R2_GLOBALS._player, NULL);
- break;
- case 81:
- R2_GLOBALS._player.setup(3157, 2, 5);
- R2_GLOBALS._player.animate(ANIM_MODE_6, this);
- break;
- case 90:
- // No break on purpose
- case 95:
- // No break on purpose
- case 100:
- R2_GLOBALS._player.setup(3156, 7, 1);
- R2_GLOBALS._player._numFrames = 5;
- R2_GLOBALS._player.animate(ANIM_MODE_5, this);
- break;
- case 101:
- R2_GLOBALS._player.setup(3157, 1, 5);
- R2_GLOBALS._player.animate(ANIM_MODE_6, this);
- break;
- case 110:
- // No break on purpose
- case 115:
- // No break on purpose
- case 120:
- R2_GLOBALS._player.setup(3156, 8, 1);
- R2_GLOBALS._player._numFrames = 5;
- R2_GLOBALS._player.animate(ANIM_MODE_5, this);
- break;
- case 121:
- R2_GLOBALS._player.setup(3157, 3, 5);
- R2_GLOBALS._player.animate(ANIM_MODE_6, this);
- break;
- default:
- // CHECKME: The original is walling _eventManager.waitEvent();
- _sceneMode = 2;
- break;
- }
-}
-
-void Scene1200::process(Event &event) {
- if (_field414 != 0)
- return;
-
- Scene::process(event);
-
- if (!R2_GLOBALS._player._canWalk)
- return;
-
- if (event.eventType == EVENT_BUTTON_DOWN) {
- Common::Point cellPos = R2_GLOBALS._ventCellPos;
- _mazeUI.pixelToCellXY(cellPos);
-
- int cellId = _mazeUI.getCellFromPixelXY(event.mousePos);
- switch (R2_GLOBALS._events.getCursor()) {
- case CURSOR_WALK:
- event.handled = true;
- if ((event.mousePos.x > 179) && (event.mousePos.x < 210) && (event.mousePos.y > 50) && (event.mousePos.y < 89))
- startCrawling(CRAWL_EAST);
-
- if ((event.mousePos.x > 109) && (event.mousePos.x < 140) && (event.mousePos.y > 50) && (event.mousePos.y < 89))
- startCrawling(CRAWL_WEST);
-
- if ((event.mousePos.x > 140) && (event.mousePos.x < 179) && (event.mousePos.y > 89) && (event.mousePos.y < 120))
- startCrawling(CRAWL_SOUTH);
-
- if ((event.mousePos.x > 140) && (event.mousePos.x < 179) && (event.mousePos.y > 19) && (event.mousePos.y < 50))
- startCrawling(CRAWL_NORTH);
- break;
- case CURSOR_USE:
- if (cellId > 36) {
- if ( ((cellPos.x == 3) && (cellPos.y == 33))
- || ((cellPos.x == 7) && (cellPos.y == 33))
- || ((cellPos.x == 33) && (cellPos.y == 41))
- || ((cellPos.x == 5) && (cellPos.y == 5))
- || ((cellPos.x == 13) && (cellPos.y == 21))
- || ((cellPos.x == 17) && (cellPos.y == 21))
- || ((cellPos.x == 17) && (cellPos.y == 5))
- || ((cellPos.x == 17) && (cellPos.y == 9))
- || ((cellPos.x == 29) && (cellPos.y == 17))
- || ((cellPos.x == 33) && (cellPos.y == 17))
- || ((cellPos.x == 35) && (cellPos.y == 17))
- || ((cellPos.x == 41) && (cellPos.y == 21)) ) {
- _laserPanel.postInit();
- event.handled = true;
- }
- }
-
- if ((cellId == 1) || (cellId == 4) || (cellId == 11) || (cellId == 14)) {
- if ( ((cellPos.x == 3) && (cellPos.y == 9))
- || ((cellPos.x == 11) && (cellPos.y == 27))
- || ((cellPos.x == 17) && (cellPos.y == 7))
- || ((cellPos.x == 17) && (cellPos.y == 27))
- || ((cellPos.x == 17) && (cellPos.y == 33))
- || (cellPos.x == 33) ) {
- switch (cellPos.x) {
- case 3:
- R2_GLOBALS._sceneManager.changeScene(3150);
- break;
- case 33:
- if (R2_GLOBALS._scientistConvIndex >= 4)
- R2_GLOBALS._sceneManager.changeScene(3250);
- else
- SceneItem::display(1200, 6, 0, 280, 1, 160, 9, 1, 2, 20, 7, 154, LIST_END);
- break;
- default:
- SceneItem::display(1200, 5, 0, 280, 1, 160, 9, 1, 2, 20, 7, 154, LIST_END);
- break;
- }
- event.handled = true;
- }
- }
- break;
- case CURSOR_LOOK:
- if ((cellId == 1) || (cellId == 4) || (cellId == 11) || (cellId == 14)) {
- event.handled = true;
- switch (cellPos.x) {
- case 3:
- // It was your cell.
- SceneItem::display(1200, 8, 0, 280, 1, 160, 9, 1, 2, 20, 7, 7, LIST_END);
- break;
- case 9:
- R2_GLOBALS._sceneManager.changeScene(3240);
- break;
- case 11:
- if (cellPos.y == 27)
- R2_GLOBALS._sceneManager.changeScene(3210);
- else
- // A vent grill
- SceneItem::display(1200, 10, 0, 280, 1, 160, 9, 1, 2, 20, 7, 7, LIST_END);
- break;
- case 17:
- switch (cellPos.y) {
- case 5:
- R2_GLOBALS._sceneManager.changeScene(3230);
- break;
- case 21:
- R2_GLOBALS._sceneManager.changeScene(3220);
- break;
- case 33:
- R2_GLOBALS._sceneManager.changeScene(3200);
- break;
- default:
- // A vent grill
- SceneItem::display(1200, 10, 0, 280, 1, 160, 9, 1, 2, 20, 7, 7, LIST_END);
- break;
- }
- break;
- case 33:
- R2_GLOBALS._sceneManager.changeScene(3245);
- break;
- default:
- SceneItem::display(1200, 10, 0, 280, 1, 160, 9, 1, 2, 20, 7, 7, LIST_END);
- break;
- }
- }
- if (cellId > 36) {
- // "An anti-pest laser"
- event.handled = true;
- SceneItem::display(1200, 9, 0, 280, 1, 160, 9, 1, 2, 20, 7, 7, LIST_END);
- }
- break;
- case CURSOR_TALK:
- event.handled = true;
- break;
- default:
- return;
- }
- } else if (event.eventType == EVENT_KEYPRESS) {
- if (_field414) {
- event.handled = false;
- return;
- }
-
- switch (event.kbd.keycode) {
- case Common::KEYCODE_KP8:
- case Common::KEYCODE_UP:
- startCrawling(CRAWL_NORTH);
- break;
- case Common::KEYCODE_KP4:
- case Common::KEYCODE_LEFT:
- startCrawling(CRAWL_WEST);
- break;
- case Common::KEYCODE_KP6:
- case Common::KEYCODE_RIGHT:
- startCrawling(CRAWL_EAST);
- break;
- case Common::KEYCODE_KP2:
- case Common::KEYCODE_DOWN:
- startCrawling(CRAWL_SOUTH);
- break;
- default:
- event.handled = false;
- return;
- break;
- }
- } else
- return;
-}
-
-void Scene1200::dispatch() {
- Rect tmpRect;
- Scene::dispatch();
-
- if (_fixupMaze) {
- _mazeUI.setMazePosition(R2_GLOBALS._ventCellPos);
- //_mazeUI.draw();
- _fixupMaze = false;
- }
-
- if (_field414 != 0) {
- tmpRect.set(110, 20, 210, 120);
- _field414--;
-
- switch (_nextCrawlDirection) {
- case CRAWL_EAST:
- R2_GLOBALS._ventCellPos.x += 2;
- break;
- case CRAWL_WEST:
- R2_GLOBALS._ventCellPos.x -= 2;
- break;
- case CRAWL_SOUTH:
- R2_GLOBALS._ventCellPos.y += 2;
- break;
- case CRAWL_NORTH:
- R2_GLOBALS._ventCellPos.y -= 2;
- break;
- default:
- break;
- }
-
- _mazeUI.setMazePosition(R2_GLOBALS._ventCellPos);
- //_mazeUI.draw();
-
- if (_field416 != 0) {
- switch(_nextCrawlDirection) {
- case CRAWL_EAST:
- R2_GLOBALS._player.setPosition(Common::Point(R2_GLOBALS._player._position.x - 2, R2_GLOBALS._player._position.y));
- break;
- case CRAWL_WEST:
- R2_GLOBALS._player.setPosition(Common::Point(R2_GLOBALS._player._position.x + 2, R2_GLOBALS._player._position.y));
- break;
- case CRAWL_SOUTH:
- R2_GLOBALS._player.setPosition(Common::Point(R2_GLOBALS._player._position.x, R2_GLOBALS._player._position.y - 2));
- break;
- case CRAWL_NORTH:
- R2_GLOBALS._player.setPosition(Common::Point(R2_GLOBALS._player._position.x, R2_GLOBALS._player._position.y + 2));
- break;
- default:
- break;
- }
- }
- if (_field414 == 0) {
- if (_field416 == 0)
- R2_GLOBALS._player.animate(ANIM_MODE_NONE, NULL);
- signal();
- }
- }
-}
-
-void Scene1200::saveCharacter(int characterIndex) {
- R2_GLOBALS._sound1.fadeOut2(NULL);
- SceneExt::saveCharacter(characterIndex);
-}
-
-void Scene1200::startCrawling(CrawlDirection dir) {
- Common::Point cellPos = R2_GLOBALS._ventCellPos;
- _mazeUI.pixelToCellXY(cellPos);
-
- switch (dir) {
- case CRAWL_EAST:
- if ( ((_mazeUI.getCellFromPixelXY(Common::Point(200, 50)) > 36) || (_mazeUI.getCellFromPixelXY(Common::Point(200, 88)) > 36))
- && ( ((cellPos.x == 3) && (cellPos.y == 33) && (_field418 != 4))
- || ((cellPos.x == 13) && (cellPos.y == 21) && (_field418 != 2))
- || ((cellPos.x == 29) && (cellPos.y == 17) && (_field418 != 1))
- || ((cellPos.x == 33) && (cellPos.y == 41)) )
- ) {
- R2_GLOBALS._player.disableControl();
- _sceneMode = 1200;
- setAction(&_sequenceManager, this, 1200, &_actor1, NULL);
- } else if (_mazeUI.getCellFromPixelXY(Common::Point(200, 69)) == 36) {
- switch (_nextCrawlDirection) {
- case CRAWL_EAST:
- if (R2_GLOBALS._player._visage == 3155)
- _sceneMode = 15;
- else
- _sceneMode = 10;
- break;
- case CRAWL_WEST:
- if (R2_GLOBALS._player._visage == 3156)
- _sceneMode = 76;
- else
- _sceneMode = 75;
- break;
- case CRAWL_SOUTH:
- if (R2_GLOBALS._player._visage == 3156)
- _sceneMode = 101;
- else
- _sceneMode = 100;
- break;
- case CRAWL_NORTH:
- if (R2_GLOBALS._player._visage == 3156)
- _sceneMode = 111;
- else
- _sceneMode = 110;
- break;
- default:
- break;
- }
- R2_GLOBALS._player.disableControl();
- _nextCrawlDirection = 1;
- signal();
- }
- break;
- case CRAWL_WEST:
- if ( ((_mazeUI.getCellFromPixelXY(Common::Point(120, 50)) > 36) || (_mazeUI.getCellFromPixelXY(Common::Point(120, 88)) > 36))
- && ( ((cellPos.x == 7) && (cellPos.y == 33) && (_field418 != 4))
- || ((cellPos.x == 17) && (cellPos.y == 21) && (_field418 != 2))
- || ((cellPos.x == 33) && (cellPos.y == 17) && (_field418 != 1))
- || ((cellPos.x == 5) && (cellPos.y == 5)) )
- ) {
- R2_GLOBALS._player.disableControl();
- _sceneMode = 1201;
- setAction(&_sequenceManager, this, 1201, &_actor1, NULL);
- } else if (_mazeUI.getCellFromPixelXY(Common::Point(120, 69)) == 36) {
- switch (_nextCrawlDirection) {
- case CRAWL_EAST:
- if (R2_GLOBALS._player._visage == 3156)
- _sceneMode = 56;
- else
- _sceneMode = 55;
- break;
- case CRAWL_WEST:
- if (R2_GLOBALS._player._visage == 3155)
- _sceneMode = 25;
- else
- _sceneMode = 20;
- break;
- case CRAWL_SOUTH:
- if (R2_GLOBALS._player._visage == 3156)
- _sceneMode = 91;
- else
- _sceneMode = 90;
- break;
- case CRAWL_NORTH:
- if (R2_GLOBALS._player._visage == 3156)
- _sceneMode = 121;
- else
- _sceneMode = 120;
- break;
- default:
- break;
- }
- R2_GLOBALS._player.disableControl();
- _nextCrawlDirection = 2;
- signal();
- }
- break;
- case CRAWL_SOUTH:
- if ( ((_mazeUI.getCellFromPixelXY(Common::Point(140, 110)) > 36) || (_mazeUI.getCellFromPixelXY(Common::Point(178, 110)) > 36))
- && ( ((cellPos.x == 17) && (cellPos.y == 5) && (_field418 != 3))
- || ((cellPos.x == 41) && (cellPos.y == 21)) )
- ) {
- R2_GLOBALS._player.disableControl();
- _sceneMode = 1203;
- setAction(&_sequenceManager, this, 1203, &_actor1, NULL);
- } else if (_mazeUI.getCellFromPixelXY(Common::Point(160, 110)) == 36) {
- switch (_nextCrawlDirection) {
- case CRAWL_EAST:
- if (R2_GLOBALS._player._visage == 3156)
- _sceneMode = 51;
- else
- _sceneMode = 50;
- break;
- case CRAWL_WEST:
- if (R2_GLOBALS._player._visage == 3156)
- _sceneMode = 81;
- else
- _sceneMode = 80;
- break;
- case CRAWL_SOUTH:
- if (R2_GLOBALS._player._visage == 3155)
- _sceneMode = 35;
- else
- _sceneMode = 30;
- break;
- case CRAWL_NORTH:
- if (R2_GLOBALS._player._visage == 3156)
- _sceneMode = 116;
- else
- _sceneMode = 115;
- break;
- default:
- break;
- }
- R2_GLOBALS._player.disableControl();
- _nextCrawlDirection = 3;
- signal();
- }
- break;
- case CRAWL_NORTH:
- if ( ((_mazeUI.getCellFromPixelXY(Common::Point(140, 30)) > 36) || (_mazeUI.getCellFromPixelXY(Common::Point(178, 30)) > 36))
- && ( ((cellPos.x == 17) && (cellPos.y == 9) && (_field418 != 3))
- || ((cellPos.x == 35) && (cellPos.y == 17)) )
- ) {
- R2_GLOBALS._player.disableControl();
- _sceneMode = 1202;
- setAction(&_sequenceManager, this, 1202, &_actor1, NULL);
- } else if (_mazeUI.getCellFromPixelXY(Common::Point(160, 30)) == 36) {
- switch (_nextCrawlDirection) {
- case CRAWL_EAST:
- if (R2_GLOBALS._player._visage == 3156)
- _sceneMode = 61;
- else
- _sceneMode = 60;
- break;
- case CRAWL_WEST:
- if (R2_GLOBALS._player._visage == 3156)
- _sceneMode = 71;
- else
- _sceneMode = 70;
- break;
- case CRAWL_SOUTH:
- if (R2_GLOBALS._player._visage == 3156)
- _sceneMode = 96;
- else
- _sceneMode = 95;
- break;
- case CRAWL_NORTH:
- if (R2_GLOBALS._player._visage == 3155)
- _sceneMode = 45;
- else
- _sceneMode = 40;
- break;
- default:
- _sceneMode = 1;
- R2_GLOBALS._player.setup(3156, 4, 6);
- break;
- }
- R2_GLOBALS._player.disableControl();
- _nextCrawlDirection = 4;
- signal();
- }
- break;
- default:
- break;
- }
-}
-
-/*--------------------------------------------------------------------------
- * Scene 1337 - Card game
- *
- *--------------------------------------------------------------------------*/
-
-Scene1337::Card::Card() {
- _cardId = 0;
- _stationPos = Common::Point(0, 0);
-}
-
-void Scene1337::Card::synchronize(Serializer &s) {
- warning("STUBBED: Card::synchronize()");
-}
-
-bool Scene1337::Card::isIn(Common::Point pt) {
- if ((_stationPos.x > pt.x) || (_stationPos.x + 24 < pt.x))
- return false;
-
- if ((_stationPos.y > pt.y) || (_stationPos.y + 24 < pt.y))
- return false;
-
- return true;
-}
-
-Scene1337::GameBoardSide::GameBoardSide() {
- _card1Pos = Common::Point(0, 0);
- _card2Pos = Common::Point(0, 0);
- _card3Pos = Common::Point(0, 0);
- _card4Pos = Common::Point(0, 0);
- _frameNum = 0;
-}
-
-void Scene1337::GameBoardSide::synchronize(Serializer &s) {
- warning("STUBBED: GameBoardSide::synchronize()");
-}
-
-Scene1337::Scene1337() {
- _autoplay = false;
- _cardsAvailableNumb = 0;
- _currentDiscardIndex = 0;
-
- for (int i = 0; i < 100; i++)
- _availableCardsPile[i] = 0;
-
- _shuffleEndedFl = false;
- _currentPlayerNumb = 0;
- _actionIdx1 = 0;
- _actionIdx2 = 0;
- _showPlayerTurn = false;
- _displayHelpFl = false;
- _winnerId = -1;
- _instructionsDisplayedFl = false;
- _instructionsWaitCount = 0;
-
- _delayedFunction = nullptr;
- _actionCard1 = nullptr;
- _actionCard2 = nullptr;
- _actionCard3 = nullptr;
-
- _cursorCurRes = 0;
- _cursorCurStrip = 0;
- _cursorCurFrame = 0;
-}
-
-void Scene1337::synchronize(Serializer &s) {
- warning("STUBBED: Scene1337::synchronize()");
-}
-
-void Scene1337::Action1337::waitFrames(int32 frameCount) {
- uint32 firstFrameNumber = g_globals->_events.getFrameNumber();
- uint32 curFrame = firstFrameNumber;
- uint32 destFrame = firstFrameNumber + frameCount;
-
- while ((curFrame < destFrame) && !g_vm->shouldQuit()) {
- TsAGE::Event event;
- g_globals->_events.getEvent(event);
- curFrame = g_globals->_events.getFrameNumber();
- }
-
- // CHECKME: The original is calling _eventManager.waitEvent();
-}
-
-/**
- * Display instructions
- */
-void Scene1337::Action1::signal() {
- Scene1337 *scene = (Scene1337 *)R2_GLOBALS._sceneManager._scene;
-
- switch (_actionIndex++) {
- case 1: {
- scene->actionDisplay(1331, 6, 159, 10, 1, 200, 0, 7, 0, 154, 154);
- R2_GLOBALS._sceneObjects->draw();
- scene->actionDisplay(1331, 7, 159, 10, 1, 200, 0, 7, 0, 154, 154);
- scene->actionDisplay(1331, 8, 159, 10, 1, 200, 0, 7, 0, 154, 154);
-
- scene->_gameBoardSide[1]._outpostStation[0]._cardId = 2;
- scene->_gameBoardSide[1]._outpostStation[0]._card.postInit();
- scene->_gameBoardSide[1]._outpostStation[0]._card.setVisage(1332);
- scene->_gameBoardSide[1]._outpostStation[0]._card.setPosition(scene->_gameBoardSide[1]._outpostStation[0]._stationPos, 0);
- scene->_gameBoardSide[1]._outpostStation[0]._card.setStrip(2);
- scene->_gameBoardSide[1]._outpostStation[0]._card.setFrame(scene->_gameBoardSide[1]._outpostStation[0]._cardId);
- scene->_gameBoardSide[1]._outpostStation[0]._card.fixPriority(170);
- scene->setAnimationInfo(&scene->_gameBoardSide[1]._outpostStation[0]);
-
- scene->_gameBoardSide[1]._outpostStation[1]._cardId = 3;
- scene->_gameBoardSide[1]._outpostStation[1]._card.postInit();
- scene->_gameBoardSide[1]._outpostStation[1]._card.setVisage(1332);
- scene->_gameBoardSide[1]._outpostStation[1]._card.setPosition(scene->_gameBoardSide[1]._outpostStation[1]._stationPos, 0);
- scene->_gameBoardSide[1]._outpostStation[1]._card.setStrip(2);
- scene->_gameBoardSide[1]._outpostStation[1]._card.setFrame(scene->_gameBoardSide[1]._outpostStation[1]._cardId);
- scene->_gameBoardSide[1]._outpostStation[1]._card.fixPriority(170);
- scene->setAnimationInfo(&scene->_gameBoardSide[1]._outpostStation[1]);
-
- scene->_gameBoardSide[2]._outpostStation[0]._cardId = 4;
- scene->_gameBoardSide[2]._outpostStation[0]._card.postInit();
- scene->_gameBoardSide[2]._outpostStation[0]._card.setVisage(1332);
- scene->_gameBoardSide[2]._outpostStation[0]._card.setPosition(scene->_gameBoardSide[2]._outpostStation[0]._stationPos, 0);
- scene->_gameBoardSide[2]._outpostStation[0]._card.setStrip(2);
- scene->_gameBoardSide[2]._outpostStation[0]._card.setFrame(scene->_gameBoardSide[2]._outpostStation[0]._cardId);
- scene->setAnimationInfo(&scene->_gameBoardSide[2]._outpostStation[0]);
-
- scene->_gameBoardSide[3]._outpostStation[0]._cardId = 5;
- scene->_gameBoardSide[3]._outpostStation[0]._card.postInit();
- scene->_gameBoardSide[3]._outpostStation[0]._card.setVisage(1332);
- scene->_gameBoardSide[3]._outpostStation[0]._card.setPosition(scene->_gameBoardSide[3]._outpostStation[0]._stationPos, 0);
- scene->_gameBoardSide[3]._outpostStation[0]._card.setStrip(2);
- scene->_gameBoardSide[3]._outpostStation[0]._card.setFrame(scene->_gameBoardSide[3]._outpostStation[0]._cardId);
- scene->_gameBoardSide[3]._outpostStation[0]._card.fixPriority(170);
- scene->setAnimationInfo(&scene->_gameBoardSide[3]._outpostStation[0]);
-
- scene->_gameBoardSide[3]._outpostStation[1]._cardId = 6;
- scene->_gameBoardSide[3]._outpostStation[1]._card.postInit();
- scene->_gameBoardSide[3]._outpostStation[1]._card.setVisage(1332);
- scene->_gameBoardSide[3]._outpostStation[1]._card.setPosition(scene->_gameBoardSide[3]._outpostStation[1]._stationPos, 0);
- scene->_gameBoardSide[3]._outpostStation[1]._card.setStrip(2);
- scene->_gameBoardSide[3]._outpostStation[1]._card.setFrame(scene->_gameBoardSide[3]._outpostStation[1]._cardId);
- scene->_gameBoardSide[3]._outpostStation[1]._card.fixPriority(170);
- scene->setAnimationInfo(&scene->_gameBoardSide[3]._outpostStation[1]);
-
- scene->_gameBoardSide[3]._outpostStation[2]._cardId = 7;
- scene->_gameBoardSide[3]._outpostStation[2]._card.postInit();
- scene->_gameBoardSide[3]._outpostStation[2]._card.setVisage(1332);
- scene->_gameBoardSide[3]._outpostStation[2]._card.setPosition(scene->_gameBoardSide[3]._outpostStation[2]._stationPos, 0);
- scene->_gameBoardSide[3]._outpostStation[2]._card.setStrip(2);
- scene->_gameBoardSide[3]._outpostStation[2]._card.setFrame(scene->_gameBoardSide[3]._outpostStation[2]._cardId);
- scene->_gameBoardSide[3]._outpostStation[2]._card.fixPriority(170);
- scene->setAnimationInfo(&scene->_gameBoardSide[3]._outpostStation[2]);
-
- scene->_gameBoardSide[0]._outpostStation[0]._cardId = 8;
- scene->_gameBoardSide[0]._outpostStation[0]._card.postInit();
- scene->_gameBoardSide[0]._outpostStation[0]._card.setVisage(1332);
- scene->_gameBoardSide[0]._outpostStation[0]._card.setPosition(scene->_gameBoardSide[0]._outpostStation[0]._stationPos, 0);
- scene->_gameBoardSide[0]._outpostStation[0]._card.setStrip(2);
- scene->_gameBoardSide[0]._outpostStation[0]._card.setFrame(scene->_gameBoardSide[0]._outpostStation[0]._cardId);
- scene->_gameBoardSide[0]._outpostStation[0]._card.fixPriority(170);
- scene->setAnimationInfo(&scene->_gameBoardSide[0]._outpostStation[0]);
-
- scene->_gameBoardSide[0]._outpostStation[1]._cardId = 9;
- scene->_gameBoardSide[0]._outpostStation[1]._card.postInit();
- scene->_gameBoardSide[0]._outpostStation[1]._card.setVisage(1332);
- scene->_gameBoardSide[0]._outpostStation[1]._card.setPosition(scene->_gameBoardSide[0]._outpostStation[1]._stationPos, 0);
- scene->_gameBoardSide[0]._outpostStation[1]._card.setStrip(2);
- scene->_gameBoardSide[0]._outpostStation[1]._card.setFrame(scene->_gameBoardSide[0]._outpostStation[1]._cardId);
- scene->_gameBoardSide[0]._outpostStation[1]._card.fixPriority(170);
- scene->setAnimationInfo(&scene->_gameBoardSide[0]._outpostStation[1]);
-
- R2_GLOBALS._sceneObjects->draw();
-
- waitFrames(60);
- scene->actionDisplay(1331, 9, 159, 10, 1, 200, 0, 7, 0, 154, 154);
-
- scene->_gameBoardSide[2]._outpostStation[1]._cardId = 2;
- scene->_gameBoardSide[2]._outpostStation[1]._card.postInit();
- scene->_gameBoardSide[2]._outpostStation[1]._card.setVisage(1332);
- scene->_gameBoardSide[2]._outpostStation[1]._card.setPosition(scene->_gameBoardSide[2]._outpostStation[1]._stationPos, 0);
- scene->_gameBoardSide[2]._outpostStation[1]._card.setStrip(2);
- scene->_gameBoardSide[2]._outpostStation[1]._card.setFrame(scene->_gameBoardSide[2]._outpostStation[1]._cardId);
- scene->_gameBoardSide[2]._outpostStation[1]._card.fixPriority(170);
- scene->setAnimationInfo(&scene->_gameBoardSide[2]._outpostStation[1]);
-
- scene->_gameBoardSide[2]._outpostStation[2]._cardId = 3;
- scene->_gameBoardSide[2]._outpostStation[2]._card.postInit();
- scene->_gameBoardSide[2]._outpostStation[2]._card.setVisage(1332);
- scene->_gameBoardSide[2]._outpostStation[2]._card.setPosition(scene->_gameBoardSide[2]._outpostStation[2]._stationPos, 0);
- scene->_gameBoardSide[2]._outpostStation[2]._card.setStrip(2);
- scene->_gameBoardSide[2]._outpostStation[2]._card.setFrame(scene->_gameBoardSide[2]._outpostStation[2]._cardId);
- scene->_gameBoardSide[2]._outpostStation[2]._card.fixPriority(170);
- scene->setAnimationInfo(&scene->_gameBoardSide[2]._outpostStation[2]);
-
- scene->_gameBoardSide[2]._outpostStation[3]._cardId = 5;
- scene->_gameBoardSide[2]._outpostStation[3]._card.postInit();
- scene->_gameBoardSide[2]._outpostStation[3]._card.setVisage(1332);
- scene->_gameBoardSide[2]._outpostStation[3]._card.setPosition(scene->_gameBoardSide[2]._outpostStation[3]._stationPos, 0);
- scene->_gameBoardSide[2]._outpostStation[3]._card.setStrip(2);
- scene->_gameBoardSide[2]._outpostStation[3]._card.setFrame(scene->_gameBoardSide[2]._outpostStation[3]._cardId);
- scene->_gameBoardSide[2]._outpostStation[3]._card.fixPriority(170);
- scene->setAnimationInfo(&scene->_gameBoardSide[2]._outpostStation[3]);
-
- scene->_gameBoardSide[2]._outpostStation[4]._cardId = 6;
- scene->_gameBoardSide[2]._outpostStation[4]._card.postInit();
- scene->_gameBoardSide[2]._outpostStation[4]._card.setVisage(1332);
- scene->_gameBoardSide[2]._outpostStation[4]._card.setPosition(scene->_gameBoardSide[2]._outpostStation[4]._stationPos, 0);
- scene->_gameBoardSide[2]._outpostStation[4]._card.setStrip(2);
- scene->_gameBoardSide[2]._outpostStation[4]._card.setFrame(scene->_gameBoardSide[2]._outpostStation[4]._cardId);
- scene->_gameBoardSide[2]._outpostStation[4]._card.fixPriority(170);
- scene->setAnimationInfo(&scene->_gameBoardSide[2]._outpostStation[4]);
-
- scene->_gameBoardSide[2]._outpostStation[5]._cardId = 7;
- scene->_gameBoardSide[2]._outpostStation[5]._card.postInit();
- scene->_gameBoardSide[2]._outpostStation[5]._card.setVisage(1332);
- scene->_gameBoardSide[2]._outpostStation[5]._card.setPosition(scene->_gameBoardSide[2]._outpostStation[5]._stationPos, 0);
- scene->_gameBoardSide[2]._outpostStation[5]._card.setStrip(2);
- scene->_gameBoardSide[2]._outpostStation[5]._card.setFrame(scene->_gameBoardSide[2]._outpostStation[5]._cardId);
- scene->_gameBoardSide[2]._outpostStation[5]._card.fixPriority(170);
- scene->setAnimationInfo(&scene->_gameBoardSide[2]._outpostStation[5]);
-
- scene->_gameBoardSide[2]._outpostStation[6]._cardId = 8;
- scene->_gameBoardSide[2]._outpostStation[6]._card.postInit();
- scene->_gameBoardSide[2]._outpostStation[6]._card.setVisage(1332);
- scene->_gameBoardSide[2]._outpostStation[6]._card.setPosition(scene->_gameBoardSide[2]._outpostStation[6]._stationPos, 0);
- scene->_gameBoardSide[2]._outpostStation[6]._card.setStrip(2);
- scene->_gameBoardSide[2]._outpostStation[6]._card.setFrame(scene->_gameBoardSide[2]._outpostStation[6]._cardId);
- scene->_gameBoardSide[2]._outpostStation[6]._card.fixPriority(170);
- scene->setAnimationInfo(&scene->_gameBoardSide[2]._outpostStation[6]);
-
- scene->_gameBoardSide[2]._outpostStation[7]._cardId = 9;
- scene->_gameBoardSide[2]._outpostStation[7]._card.postInit();
- scene->_gameBoardSide[2]._outpostStation[7]._card.setVisage(1332);
- scene->_gameBoardSide[2]._outpostStation[7]._card.setPosition(scene->_gameBoardSide[2]._outpostStation[7]._stationPos, 0);
- scene->_gameBoardSide[2]._outpostStation[7]._card.setStrip(2);
- scene->_gameBoardSide[2]._outpostStation[7]._card.setFrame(scene->_gameBoardSide[2]._outpostStation[7]._cardId);
- scene->_gameBoardSide[2]._outpostStation[7]._card.fixPriority(170);
- scene->setAnimationInfo(&scene->_gameBoardSide[2]._outpostStation[7]);
-
- scene->_aSound1.play(62);
-
- R2_GLOBALS._sceneObjects->draw();
-
- waitFrames(120);
- scene->_gameBoardSide[2]._outpostStation[0]._card.remove();
- scene->_gameBoardSide[2]._outpostStation[1]._card.remove();
- scene->_gameBoardSide[2]._outpostStation[2]._card.remove();
- scene->_gameBoardSide[2]._outpostStation[3]._card.remove();
- scene->_gameBoardSide[2]._outpostStation[4]._card.remove();
- scene->_gameBoardSide[2]._outpostStation[5]._card.remove();
- scene->_gameBoardSide[2]._outpostStation[6]._card.remove();
- scene->_gameBoardSide[2]._outpostStation[7]._card.remove();
-
- scene->_gameBoardSide[1]._outpostStation[0]._card.remove();
- scene->_gameBoardSide[1]._outpostStation[1]._card.remove();
-
- scene->_gameBoardSide[3]._outpostStation[0]._card.remove();
- scene->_gameBoardSide[3]._outpostStation[1]._card.remove();
- scene->_gameBoardSide[3]._outpostStation[2]._card.remove();
-
- scene->_gameBoardSide[0]._outpostStation[0]._card.remove();
- scene->_gameBoardSide[0]._outpostStation[1]._card.remove();
-
- scene->_stockPile.setup(1332, 5, 1);
- scene->_stockPile.setPosition(Common::Point(165, 95));
- scene->_stockPile.setPriority(110);
- scene->_stockPile._effect = EFFECT_SHADED;
- scene->_stockPile.show();
-
- scene->_gameBoardSide[1]._handCard[0]._card.postInit();
- scene->_gameBoardSide[1]._handCard[0]._card.setVisage(1332);
- scene->_gameBoardSide[1]._handCard[0]._card.setPosition(scene->_gameBoardSide[1]._handCard[0]._stationPos, 0);
- scene->_gameBoardSide[1]._handCard[0]._card.setStrip(1);
- scene->_gameBoardSide[1]._handCard[0]._card.setFrame(4);
- scene->_gameBoardSide[1]._handCard[0]._card.fixPriority(170);
-
- scene->_gameBoardSide[1]._handCard[1]._card.postInit();
- scene->_gameBoardSide[1]._handCard[1]._card.setVisage(1332);
- scene->_gameBoardSide[1]._handCard[1]._card.setPosition(scene->_gameBoardSide[1]._handCard[1]._stationPos, 0);
- scene->_gameBoardSide[1]._handCard[1]._card.setStrip(1);
- scene->_gameBoardSide[1]._handCard[1]._card.setFrame(4);
- scene->_gameBoardSide[1]._handCard[1]._card.fixPriority(170);
-
- scene->_gameBoardSide[1]._handCard[2]._card.postInit();
- scene->_gameBoardSide[1]._handCard[2]._card.setVisage(1332);
- scene->_gameBoardSide[1]._handCard[2]._card.setPosition(scene->_gameBoardSide[1]._handCard[2]._stationPos, 0);
- scene->_gameBoardSide[1]._handCard[2]._card.setStrip(1);
- scene->_gameBoardSide[1]._handCard[2]._card.setFrame(4);
- scene->_gameBoardSide[1]._handCard[2]._card.fixPriority(170);
-
- scene->_gameBoardSide[2]._handCard[0]._cardId = 30;
- scene->_gameBoardSide[2]._handCard[0]._card.postInit();
- scene->_gameBoardSide[2]._handCard[0]._card.setVisage(1332);
- scene->_gameBoardSide[2]._handCard[0]._card.setPosition(scene->_gameBoardSide[2]._handCard[0]._stationPos, 0);
- scene->_gameBoardSide[2]._handCard[0]._card.setStrip(1);
- scene->_gameBoardSide[2]._handCard[0]._card.setFrame(2);
- scene->_gameBoardSide[2]._handCard[0]._card.fixPriority(170);
- scene->setAnimationInfo(&scene->_gameBoardSide[2]._handCard[0]);
-
- scene->_gameBoardSide[2]._handCard[1]._cardId = 16;
- scene->_gameBoardSide[2]._handCard[1]._card.postInit();
- scene->_gameBoardSide[2]._handCard[1]._card.setVisage(1332);
- scene->_gameBoardSide[2]._handCard[1]._card.setPosition(scene->_gameBoardSide[2]._handCard[1]._stationPos, 0);
- scene->_gameBoardSide[2]._handCard[1]._card.setStrip(1);
- scene->_gameBoardSide[2]._handCard[1]._card.setFrame(2);
- scene->_gameBoardSide[2]._handCard[1]._card.fixPriority(170);
- scene->setAnimationInfo(&scene->_gameBoardSide[2]._handCard[1]);
-
- scene->_gameBoardSide[2]._handCard[2]._cardId = 1;
- scene->_gameBoardSide[2]._handCard[2]._card.postInit();
- scene->_gameBoardSide[2]._handCard[2]._card.setVisage(1332);
- scene->_gameBoardSide[2]._handCard[2]._card.setPosition(scene->_gameBoardSide[2]._handCard[2]._stationPos, 0);
- scene->_gameBoardSide[2]._handCard[2]._card.setStrip(1);
- scene->_gameBoardSide[2]._handCard[2]._card.setFrame(2);
- scene->_gameBoardSide[2]._handCard[2]._card.fixPriority(170);
- scene->setAnimationInfo(&scene->_gameBoardSide[2]._handCard[2]);
-
- scene->_gameBoardSide[3]._handCard[0]._card.postInit();
- scene->_gameBoardSide[3]._handCard[0]._card.setVisage(1332);
- scene->_gameBoardSide[3]._handCard[0]._card.setPosition(scene->_gameBoardSide[3]._handCard[0]._stationPos, 0);
- scene->_gameBoardSide[3]._handCard[0]._card.setStrip(1);
- scene->_gameBoardSide[3]._handCard[0]._card.setFrame(3);
- scene->_gameBoardSide[3]._handCard[0]._card.fixPriority(170);
-
- scene->_gameBoardSide[3]._handCard[1]._card.postInit();
- scene->_gameBoardSide[3]._handCard[1]._card.setVisage(1332);
- scene->_gameBoardSide[3]._handCard[1]._card.setPosition(scene->_gameBoardSide[3]._handCard[1]._stationPos, 0);
- scene->_gameBoardSide[3]._handCard[1]._card.setStrip(1);
- scene->_gameBoardSide[3]._handCard[1]._card.setFrame(3);
- scene->_gameBoardSide[3]._handCard[1]._card.fixPriority(170);
-
- scene->_gameBoardSide[3]._handCard[2]._card.postInit();
- scene->_gameBoardSide[3]._handCard[2]._card.setVisage(1332);
- scene->_gameBoardSide[3]._handCard[2]._card.setPosition(scene->_gameBoardSide[3]._handCard[2]._stationPos, 0);
- scene->_gameBoardSide[3]._handCard[2]._card.setStrip(1);
- scene->_gameBoardSide[3]._handCard[2]._card.setFrame(3);
- scene->_gameBoardSide[3]._handCard[2]._card.fixPriority(170);
-
- scene->_gameBoardSide[0]._handCard[0]._card.postInit();
- scene->_gameBoardSide[0]._handCard[0]._card.setVisage(1332);
- scene->_gameBoardSide[0]._handCard[0]._card.setPosition(scene->_gameBoardSide[0]._handCard[0]._stationPos, 0);
- scene->_gameBoardSide[0]._handCard[0]._card.setStrip(1);
- scene->_gameBoardSide[0]._handCard[0]._card.setFrame(2);
- scene->_gameBoardSide[0]._handCard[0]._card.fixPriority(170);
-
- scene->_gameBoardSide[0]._handCard[1]._card.postInit();
- scene->_gameBoardSide[0]._handCard[1]._card.setVisage(1332);
- scene->_gameBoardSide[0]._handCard[1]._card.setPosition(scene->_gameBoardSide[0]._handCard[1]._stationPos, 0);
- scene->_gameBoardSide[0]._handCard[1]._card.setStrip(1);
- scene->_gameBoardSide[0]._handCard[1]._card.setFrame(2);
- scene->_gameBoardSide[0]._handCard[1]._card.fixPriority(170);
-
- scene->_gameBoardSide[0]._handCard[2]._card.postInit();
- scene->_gameBoardSide[0]._handCard[2]._card.setVisage(1332);
- scene->_gameBoardSide[0]._handCard[2]._card.setPosition(scene->_gameBoardSide[0]._handCard[2]._stationPos, 0);
- scene->_gameBoardSide[0]._handCard[2]._card.setStrip(1);
- scene->_gameBoardSide[0]._handCard[2]._card.setFrame(2);
- scene->_gameBoardSide[0]._handCard[2]._card.fixPriority(170);
-
- R2_GLOBALS._sceneObjects->draw();
-
- scene->actionDisplay(1331, 10, 159, 10, 1, 200, 0, 7, 0, 154, 154);
- scene->_animatedCard._card.setPosition(Common::Point(162, 95), 0);
- scene->_animatedCard._card.show();
- scene->_aSound2.play(61);
-
- Common::Point pt(91, 174);
- NpcMover *mover = new NpcMover();
- scene->_animatedCard._card.addMover(mover, &pt, this);
- }
- break;
- case 2: {
- scene->_gameBoardSide[2]._handCard[3]._cardId = 2;
- scene->_gameBoardSide[2]._handCard[3]._card.postInit();
- scene->_gameBoardSide[2]._handCard[3]._card.setVisage(1332);
- scene->_gameBoardSide[2]._handCard[3]._card.setPosition(scene->_gameBoardSide[2]._handCard[3]._stationPos, 0);
- scene->_gameBoardSide[2]._handCard[3]._card.setStrip(1);
- scene->_gameBoardSide[2]._handCard[3]._card.setFrame(2);
- scene->_gameBoardSide[2]._handCard[3]._card.fixPriority(170);
-
- scene->_animatedCard._card.hide();
- scene->setAnimationInfo(&scene->_gameBoardSide[2]._handCard[3]);
-
- R2_GLOBALS._sceneObjects->draw();
-
- waitFrames(60);
- scene->actionDisplay(1331, 11, 159, 10, 1, 200, 0, 7, 0, 154, 154);
- scene->actionDisplay(1331, 12, 159, 10, 1, 200, 0, 7, 0, 154, 154);
-
- scene->_gameBoardSide[2]._outpostStation[1]._cardId = 1;
- scene->_gameBoardSide[2]._outpostStation[1]._card.postInit();
- scene->_gameBoardSide[2]._outpostStation[1]._card.setVisage(1332);
- scene->_gameBoardSide[2]._outpostStation[1]._card.setPosition(scene->_gameBoardSide[2]._outpostStation[1]._stationPos, 0);
- scene->_gameBoardSide[2]._outpostStation[1]._card.hide();
-
- scene->_animatedCard._card.setStrip(scene->_gameBoardSide[2]._handCard[2]._card._strip);
- scene->_animatedCard._card.setFrame(scene->_gameBoardSide[2]._handCard[2]._card._frame);
- scene->_animatedCard._card.animate(ANIM_MODE_NONE, NULL);
-
- scene->_gameBoardSide[2]._handCard[2]._cardId = 0;
- scene->_gameBoardSide[2]._handCard[2]._card.remove();
-
- scene->_animatedCard._card.setPosition(scene->_gameBoardSide[2]._handCard[2]._stationPos, 0);
- scene->_animatedCard._card.show();
-
- NpcMover *mover = new NpcMover();
- scene->_animatedCard._card.addMover(mover, &scene->_gameBoardSide[2]._outpostStation[1]._stationPos, this);
- }
- break;
- case 3: {
- scene->_animatedCard._card.hide();
- scene->setAnimationInfo(&scene->_gameBoardSide[2]._outpostStation[1]);
- scene->_aSound1.play(59);
-
- R2_GLOBALS._sceneObjects->draw();
-
- waitFrames(60);
- scene->actionDisplay(1331, 13, 159, 10, 1, 200, 0, 7, 0, 154, 154);
-
- scene->_gameBoardSide[2]._outpostStation[1]._cardId = scene->_gameBoardSide[2]._handCard[3]._cardId;
-
- scene->_animatedCard._card.setStrip(scene->_gameBoardSide[2]._handCard[3]._card._strip);
- scene->_animatedCard._card.setFrame(scene->_gameBoardSide[2]._handCard[3]._card._frame);
-
- scene->_gameBoardSide[2]._handCard[3]._cardId = 0;
- scene->_gameBoardSide[2]._handCard[3]._card.remove();
-
- scene->_animatedCard._card.setPosition(scene->_gameBoardSide[2]._handCard[3]._stationPos, 0);
- scene->_animatedCard._card.show();
-
- NpcMover *mover = new NpcMover();
- scene->_animatedCard._card.addMover(mover, &scene->_gameBoardSide[2]._outpostStation[1]._stationPos, this);
- }
- break;
- case 4: {
- scene->_animatedCard._card.hide();
- scene->setAnimationInfo(&scene->_gameBoardSide[2]._outpostStation[1]);
- scene->_aSound1.play(59);
-
- scene->_discardPile._cardId = 1;
- scene->_discardPile._card.hide();
-
- scene->_animatedCard._card.setStrip(5);
- scene->_animatedCard._card.setFrame(1);
- scene->_animatedCard._card.animate(ANIM_MODE_2, NULL);
- scene->_animatedCard._card.setPosition(scene->_gameBoardSide[2]._outpostStation[1]._stationPos, 0);
- scene->_animatedCard._card.show();
-
- NpcMover *mover = new NpcMover();
- scene->_animatedCard._card.addMover(mover, &scene->_discardPile._stationPos, this);
- }
- break;
- case 5: {
- scene->_animatedCard._card.hide();
-
- scene->_discardPile._card.postInit();
- scene->_discardPile._card.setVisage(1332);
- scene->_discardPile._card.setPosition(scene->_discardPile._stationPos, 0);
- scene->setAnimationInfo(&scene->_discardPile);
- scene->_aSound2.play(61);
-
- R2_GLOBALS._sceneObjects->draw();
-
- waitFrames(60);
- scene->actionDisplay(1331, 14, 159, 10, 1, 200, 0, 7, 0, 154, 154);
-
- scene->_gameBoardSide[2]._delayCard._card.postInit();
- scene->_gameBoardSide[2]._delayCard._card.setVisage(1332);
- scene->_gameBoardSide[2]._delayCard._card.setPosition(scene->_gameBoardSide[2]._delayCard._stationPos, 0);
- scene->_gameBoardSide[2]._delayCard._card.hide();
-
- scene->_gameBoardSide[3]._handCard[2]._cardId = 0;
- scene->_gameBoardSide[3]._handCard[2].remove();
-
- scene->_animatedCard._card.setPosition(scene->_gameBoardSide[3]._handCard[2]._stationPos, 0);
- scene->_animatedCard._card.show();
-
- NpcMover *mover = new NpcMover();
- scene->_animatedCard._card.addMover(mover, &scene->_gameBoardSide[2]._delayCard._stationPos, this);
- }
- break;
- case 6: {
- scene->_animatedCard._card.hide();
- scene->_gameBoardSide[2]._delayCard._cardId = 21;
- scene->setAnimationInfo(&scene->_gameBoardSide[2]._delayCard);
- scene->_aSound1.play(57);
-
- R2_GLOBALS._sceneObjects->draw();
-
- waitFrames(60);
- scene->actionDisplay(1331, 15, 159, 10, 1, 200, 0, 7, 0, 154, 154);
-
- int tmpVal = 15;
- int i = -1;
-
- for (i = 0; i <= 7; i++) {
- tmpVal += 29;
-
- scene->_upperDisplayCard[i].postInit();
- scene->_upperDisplayCard[i].setVisage(1332);
- scene->_upperDisplayCard[i].setPosition(Common::Point(tmpVal, 90), 0);
- scene->_upperDisplayCard[i].setStrip(3);
- scene->_upperDisplayCard[i].fixPriority(190);
-
- scene->_lowerDisplayCard[i].postInit();
- scene->_lowerDisplayCard[i].setVisage(1332);
- scene->_lowerDisplayCard[i].setPosition(Common::Point(tmpVal, 90), 0);
- scene->_lowerDisplayCard[i].setStrip(7);
- scene->_lowerDisplayCard[i].setFrame(1);
- scene->_lowerDisplayCard[i].fixPriority(180);
- }
-
- scene->_upperDisplayCard[0].setFrame(1);
- scene->_upperDisplayCard[1].setFrame(3);
- scene->_upperDisplayCard[2].setFrame(6);
- scene->_upperDisplayCard[3].setFrame(8);
- scene->_upperDisplayCard[4].setFrame(9);
- scene->_upperDisplayCard[5].setFrame(10);
- scene->_upperDisplayCard[6].setFrame(11);
- scene->_upperDisplayCard[7].setFrame(12);
-
- R2_GLOBALS._sceneObjects->draw();
-
- waitFrames(240);
-
- scene->_upperDisplayCard[0].remove();
- scene->_upperDisplayCard[1].remove();
- scene->_upperDisplayCard[2].remove();
- scene->_upperDisplayCard[3].remove();
- scene->_upperDisplayCard[4].remove();
- scene->_upperDisplayCard[5].remove();
- scene->_upperDisplayCard[6].remove();
- scene->_upperDisplayCard[7].remove();
-
- scene->_lowerDisplayCard[0].remove();
- scene->_lowerDisplayCard[1].remove();
- scene->_lowerDisplayCard[2].remove();
- scene->_lowerDisplayCard[3].remove();
- scene->_lowerDisplayCard[4].remove();
- scene->_lowerDisplayCard[5].remove();
- scene->_lowerDisplayCard[6].remove();
- scene->_lowerDisplayCard[7].remove();
-
- scene->_discardPile._cardId = scene->_gameBoardSide[2]._delayCard._cardId;
-
- scene->_gameBoardSide[2]._delayCard._cardId = 0;
- scene->_gameBoardSide[2]._delayCard._card.remove();
-
- scene->_animatedCard._card.setPosition(scene->_gameBoardSide[2]._delayCard._stationPos, 0);
- scene->_animatedCard._card.show();
-
- NpcMover *mover = new NpcMover();
- scene->_animatedCard._card.addMover(mover, &scene->_discardPile._stationPos, this);
- }
- break;
- case 7: {
- scene->_animatedCard._card.hide();
- scene->setAnimationInfo(&scene->_discardPile);
- scene->_aSound2.play(61);
-
- R2_GLOBALS._sceneObjects->draw();
-
- scene->_gameBoardSide[2]._delayCard._card.postInit();
- scene->_gameBoardSide[2]._delayCard._card.setVisage(1332);
- scene->_gameBoardSide[2]._delayCard._card.setPosition(scene->_gameBoardSide[2]._delayCard._stationPos, 0);
- scene->_gameBoardSide[2]._delayCard._card.hide();
-
- scene->_gameBoardSide[3]._handCard[1]._cardId = 0;
- scene->_gameBoardSide[3]._handCard[1].remove();
-
- scene->_animatedCard._card.setPosition(scene->_gameBoardSide[3]._handCard[1]._stationPos, 0);
- scene->_animatedCard._card.show();
-
- NpcMover *mover = new NpcMover();
- scene->_animatedCard._card.addMover(mover, &scene->_gameBoardSide[2]._delayCard._stationPos, this);
- }
- break;
- case 8: {
- scene->_animatedCard._card.hide();
- scene->_gameBoardSide[2]._delayCard._cardId = 14;
- scene->setAnimationInfo(&scene->_gameBoardSide[2]._delayCard);
- scene->_aSound1.play(57);
-
- R2_GLOBALS._sceneObjects->draw();
-
- scene->actionDisplay(1331, 16, 159, 10, 1, 200, 0, 7, 0, 154, 154);
- int tmpVal = 72;
- int i = -1;
-
- for (i = 0; i <= 3; i++) {
- tmpVal += 29;
- scene->_upperDisplayCard[i].postInit();
- scene->_upperDisplayCard[i].setVisage(1332);
- scene->_upperDisplayCard[i].setPosition(Common::Point(tmpVal, 71), 0);
- scene->_upperDisplayCard[i].setStrip(3);
- scene->_upperDisplayCard[i].fixPriority(190);
-
- scene->_lowerDisplayCard[i].postInit();
- scene->_lowerDisplayCard[i].setVisage(1332);
- scene->_lowerDisplayCard[i].setPosition(Common::Point(tmpVal, 71), 0);
- scene->_lowerDisplayCard[i].setStrip(7);
- scene->_lowerDisplayCard[i].setFrame(1);
- scene->_lowerDisplayCard[i].fixPriority(180);
- }
-
- scene->_upperDisplayCard[0].setFrame(2);
- scene->_upperDisplayCard[1].setFrame(5);
- scene->_upperDisplayCard[2].setFrame(7);
- scene->_upperDisplayCard[3].setFrame(15);
-
- R2_GLOBALS._sceneObjects->draw();
-
- waitFrames(240);
- scene->actionDisplay(1331, 17, 159, 10, 1, 200, 0, 7, 0, 154, 154);
-
- tmpVal = 72;
- for (i = 4; i <= 7; i++) {
- tmpVal += 29;
-
- scene->_upperDisplayCard[i].postInit();
- scene->_upperDisplayCard[i].setVisage(1332);
- scene->_upperDisplayCard[i].setPosition(Common::Point(tmpVal, 100), 0);
- scene->_upperDisplayCard[i].setStrip(4);
- scene->_upperDisplayCard[i].fixPriority(190);
-
- scene->_lowerDisplayCard[i].postInit();
- scene->_lowerDisplayCard[i].setVisage(1332);
- scene->_lowerDisplayCard[i].setPosition(Common::Point(tmpVal, 100), 0);
- scene->_lowerDisplayCard[i].setStrip(7);
- scene->_lowerDisplayCard[i].setFrame(1);
- scene->_lowerDisplayCard[i].fixPriority(180);
- }
-
- scene->_upperDisplayCard[4].setFrame(1);
- scene->_upperDisplayCard[5].setFrame(5);
- scene->_upperDisplayCard[6].setFrame(7);
- scene->_upperDisplayCard[7].setFrame(3);
-
- R2_GLOBALS._sceneObjects->draw();
-
- waitFrames(240);
-
- scene->_upperDisplayCard[0].remove();
- scene->_upperDisplayCard[1].remove();
- scene->_upperDisplayCard[2].remove();
- scene->_upperDisplayCard[3].remove();
- scene->_upperDisplayCard[4].remove();
- scene->_upperDisplayCard[5].remove();
- scene->_upperDisplayCard[6].remove();
- scene->_upperDisplayCard[7].remove();
-
- scene->_lowerDisplayCard[0].remove();
- scene->_lowerDisplayCard[1].remove();
- scene->_lowerDisplayCard[2].remove();
- scene->_lowerDisplayCard[3].remove();
- scene->_lowerDisplayCard[4].remove();
- scene->_lowerDisplayCard[5].remove();
- scene->_lowerDisplayCard[6].remove();
- scene->_lowerDisplayCard[7].remove();
-
- scene->_discardPile._cardId = scene->_gameBoardSide[2]._handCard[0]._cardId;
-
- scene->_animatedCard._card.setStrip(scene->_gameBoardSide[2]._handCard[0]._card._strip);
- scene->_animatedCard._card.setFrame(scene->_gameBoardSide[2]._handCard[0]._card._frame);
- scene->_animatedCard._card.animate(ANIM_MODE_NONE, NULL);
-
- scene->_gameBoardSide[2]._handCard[0]._cardId = 0;
- scene->_gameBoardSide[2]._handCard[0]._card.remove();
-
- scene->_animatedCard._card.setPosition(scene->_gameBoardSide[2]._handCard[0]._stationPos, 0);
- scene->_animatedCard._card.show();
-
- NpcMover *mover = new NpcMover();
- scene->_animatedCard._card.addMover(mover, &scene->_gameBoardSide[2]._delayCard._stationPos, this);
- }
- break;
- case 9: {
- scene->_aSound1.play(58);
- scene->_gameBoardSide[2]._delayCard._cardId = 0;
- scene->_gameBoardSide[2]._delayCard.remove();
- scene->_animatedCard._card.setStrip(5);
- scene->_animatedCard._card.setFrame(1);
- scene->_animatedCard._card.animate(ANIM_MODE_2, NULL);
- scene->_animatedCard._card.setPosition(scene->_gameBoardSide[2]._delayCard._stationPos, 0);
- scene->_animatedCard._card.show();
-
- NpcMover *mover = new NpcMover();
- scene->_animatedCard._card.addMover(mover, &scene->_discardPile._stationPos, this);
- }
- break;
- case 10: {
- scene->_animatedCard._card.hide();
- scene->setAnimationInfo(&scene->_discardPile);
- scene->_aSound2.play(61);
-
- R2_GLOBALS._sceneObjects->draw();
- scene->actionDisplay(1331, 18, 159, 10, 1, 200, 0, 7, 0, 154, 154);
-
- scene->_upperDisplayCard[0].postInit();
- scene->_upperDisplayCard[0].setVisage(1332);
- scene->_upperDisplayCard[0].setPosition(Common::Point(131, 71), 0);
- scene->_upperDisplayCard[0].fixPriority(190);
- scene->_upperDisplayCard[0].setStrip(3);
- scene->_upperDisplayCard[0].setFrame(4);
-
- scene->_lowerDisplayCard[0].postInit();
- scene->_lowerDisplayCard[0].setVisage(1332);
- scene->_lowerDisplayCard[0].setPosition(Common::Point(131, 71), 0);
- scene->_lowerDisplayCard[0].setStrip(7);
- scene->_lowerDisplayCard[0].setFrame(1);
- scene->_lowerDisplayCard[0].fixPriority(180);
-
- scene->_upperDisplayCard[1].postInit();
- scene->_upperDisplayCard[1].setVisage(1332);
- scene->_upperDisplayCard[1].setPosition(Common::Point(160, 71), 0);
- scene->_upperDisplayCard[1].fixPriority(190);
- scene->_upperDisplayCard[1].setStrip(3);
- scene->_upperDisplayCard[1].setFrame(16);
-
- scene->_lowerDisplayCard[1].postInit();
- scene->_lowerDisplayCard[1].setVisage(1332);
- scene->_lowerDisplayCard[1].setPosition(Common::Point(160, 71), 0);
- scene->_lowerDisplayCard[1].setStrip(7);
- scene->_lowerDisplayCard[1].setFrame(1);
- scene->_lowerDisplayCard[1].fixPriority(180);
-
- scene->_upperDisplayCard[2].postInit();
- scene->_upperDisplayCard[2].setVisage(1332);
- scene->_upperDisplayCard[2].setPosition(Common::Point(131, 100), 0);
- scene->_upperDisplayCard[2].fixPriority(190);
- scene->_upperDisplayCard[2].setStrip(4);
- scene->_upperDisplayCard[2].setFrame(4);
-
- scene->_lowerDisplayCard[2].postInit();
- scene->_lowerDisplayCard[2].setVisage(1332);
- scene->_lowerDisplayCard[2].setPosition(Common::Point(131, 100), 0);
- scene->_lowerDisplayCard[2].setStrip(7);
- scene->_lowerDisplayCard[2].setFrame(1);
- scene->_lowerDisplayCard[2].fixPriority(180);
-
- scene->_upperDisplayCard[3].postInit();
- scene->_upperDisplayCard[3].setVisage(1332);
- scene->_upperDisplayCard[3].setPosition(Common::Point(160, 100), 0);
- scene->_upperDisplayCard[3].fixPriority(190);
- scene->_upperDisplayCard[3].setStrip(4);
- scene->_upperDisplayCard[3].setFrame(2);
-
- scene->_lowerDisplayCard[3].postInit();
- scene->_lowerDisplayCard[3].setVisage(1332);
- scene->_lowerDisplayCard[3].setPosition(Common::Point(160, 100), 0);
- scene->_lowerDisplayCard[3].setStrip(7);
- scene->_lowerDisplayCard[3].setFrame(1);
- scene->_lowerDisplayCard[3].fixPriority(180);
-
- R2_GLOBALS._sceneObjects->draw();
-
- waitFrames(240);
-
- scene->_upperDisplayCard[0].remove();
- scene->_upperDisplayCard[1].remove();
- scene->_upperDisplayCard[2].remove();
- scene->_upperDisplayCard[3].remove();
-
- scene->_lowerDisplayCard[0].remove();
- scene->_lowerDisplayCard[1].remove();
- scene->_lowerDisplayCard[2].remove();
- scene->_lowerDisplayCard[3].remove();
-
- scene->_currentPlayerArrow.setFrame(1);
- scene->_currentPlayerArrow.show();
- scene->_currentPlayerArrow.animate(ANIM_MODE_2, NULL);
-
- R2_GLOBALS._sceneObjects->draw();
-
- scene->actionDisplay(1331, 19, 159, 10, 1, 220, 0, 7, 0, 154, 154);
-
- scene->_currentPlayerArrow.hide();
-
- scene->actionDisplay(1331, 20, 159, 10, 1, 220, 0, 7, 0, 154, 154);
- scene->actionDisplay(1331, 21, 159, 10, 1, 220, 0, 7, 0, 154, 154);
-
- scene->_discardPile._cardId = scene->_gameBoardSide[2]._handCard[1]._cardId;
-
- scene->_animatedCard._card.setStrip(scene->_gameBoardSide[2]._handCard[1]._card._strip);
- scene->_animatedCard._card.setFrame(scene->_gameBoardSide[2]._handCard[1]._card._frame);
- scene->_animatedCard._card.animate(ANIM_MODE_NONE, NULL);
-
- scene->_gameBoardSide[2]._handCard[1]._cardId = 0;
- scene->_gameBoardSide[2]._handCard[1]._card.remove();
-
- scene->_animatedCard._card.setPosition(scene->_gameBoardSide[2]._handCard[1]._stationPos, 0);
- scene->_animatedCard._card.show();
-
- NpcMover *mover = new NpcMover();
- scene->_animatedCard._card.addMover(mover, &scene->_discardPile._stationPos, this);
- }
- break;
- case 11: {
- scene->_animatedCard._card.hide();
- scene->setAnimationInfo(&scene->_discardPile);
- scene->_aSound2.play(61);
- scene->_animatedCard._card.setStrip(5);
- scene->_animatedCard._card.setFrame(1);
- scene->_animatedCard._card.animate(ANIM_MODE_2, NULL);
-
- R2_GLOBALS._sceneObjects->draw();
-
- scene->actionDisplay(1331, 22, 159, 10, 1, 200, 0, 7, 0, 154, 154);
-
- int i = -1;
- for (i = 0; i <= 3; i ++) {
- scene->_gameBoardSide[3]._handCard[i]._cardId = 0;
- scene->_gameBoardSide[3]._handCard[i]._card.remove();
-
- scene->_gameBoardSide[2]._handCard[i]._cardId = 0;
- scene->_gameBoardSide[2]._handCard[i]._card.remove();
-
- scene->_gameBoardSide[0]._handCard[i]._cardId = 0;
- scene->_gameBoardSide[0]._handCard[i]._card.remove();
-
- scene->_gameBoardSide[1]._handCard[i]._cardId = 0;
- scene->_gameBoardSide[1]._handCard[i]._card.remove();
- }
-
- for (i = 0; i <= 7; i++) {
- scene->_gameBoardSide[3]._outpostStation[i]._cardId = 0;
- scene->_gameBoardSide[3]._outpostStation[i]._card.remove();
-
- scene->_gameBoardSide[2]._outpostStation[i]._cardId = 0;
- scene->_gameBoardSide[2]._outpostStation[i]._card.remove();
-
- scene->_gameBoardSide[0]._outpostStation[i]._cardId = 0;
- scene->_gameBoardSide[0]._outpostStation[i]._card.remove();
-
- scene->_gameBoardSide[1]._outpostStation[i]._cardId = 0;
- scene->_gameBoardSide[1]._outpostStation[i]._card.remove();
- }
-
- scene->_gameBoardSide[2]._delayCard._cardId = 0;
- scene->_gameBoardSide[2]._delayCard._card.remove();
-
- scene->_discardPile._cardId = 0;
- scene->_discardPile._card.remove();
-
- scene->_stockPile.remove();
- }
- // No break on purpose
- case 0:
- R2_GLOBALS._sceneObjects->draw();
- signal();
- break;
- case 12:
- scene->suggestInstructions();
- remove();
- break;
- default:
- break;
- }
-}
-
-/**
- * Shuffle cards animation
- */
-void Scene1337::Action2::signal() {
- Scene1337 *scene = (Scene1337 *)R2_GLOBALS._sceneManager._scene;
-
- switch (_actionIndex++) {
- case 0:
- scene->_shuffleAnimation._card.postInit();
- scene->_shuffleAnimation._card.setVisage(1332);
- scene->_shuffleAnimation._card.setStrip(8);
- scene->_shuffleAnimation._card.setFrame(1);
- scene->_shuffleAnimation._card.fixPriority(300);
- scene->_shuffleAnimation._card.setPosition(Common::Point(156, 108));
-
- scene->_discardPile._card.remove();
- scene->_discardPile._cardId = 0;
-
- scene->_aSound1.play(60);
- scene->_shuffleAnimation._card.animate(ANIM_MODE_5, this);
- break;
- case 1:
- scene->_shuffleAnimation._card.setFrame(1);
-
- scene->_aSound1.play(60);
- scene->_shuffleAnimation._card.animate(ANIM_MODE_5, this);
- break;
- case 2: {
- Common::Point pt(156, 108);
- NpcMover *mover = new NpcMover();
- scene->_shuffleAnimation._card.addMover(mover, &pt, this);
- }
- break;
- case 3:
- scene->_shuffleAnimation._card.remove();
- scene->_stockPile.setup(1332, 5, 1);
- scene->_stockPile.setPosition(Common::Point(162, 95));
- scene->_stockPile.setPriority(110);
- scene->_stockPile._effect = EFFECT_SHADED;
- scene->_stockPile.show();
- scene->_shuffleEndedFl = true;
- break;
- default:
- break;
- }
-}
-
-/**
- * Deal cards
- */
-void Scene1337::Action3::signal() {
- Scene1337 *scene = (Scene1337 *)R2_GLOBALS._sceneManager._scene;
-
- scene->_animatedCard._card.setPosition(Common::Point(162, 95), 0);
-
- switch (_actionIndex++) {
- case 0: {
- scene->_animatedCard._card._moveDiff = Common::Point(30, 30);
- scene->_animatedCard._card.setVisage(1332);
- scene->_animatedCard._card.setStrip(5);
- scene->_animatedCard._card.setFrame(1);
- scene->_animatedCard._card.fixPriority(400);
- scene->_animatedCard._card.animate(ANIM_MODE_2, NULL);
- scene->_aSound2.play(61);
-
- Common::Point pt(283, 146);
- NpcMover *mover = new NpcMover();
- scene->_animatedCard._card.addMover(mover, &pt, this);
-
- scene->_animatedCard._card.show();
- scene->_gameBoardSide[1]._handCard[0]._cardId = scene->_availableCardsPile[scene->_cardsAvailableNumb];
- }
- break;
- case 1: {
- scene->_gameBoardSide[1]._handCard[0]._card.postInit();
- scene->_gameBoardSide[1]._handCard[0]._card._moveDiff = Common::Point(30, 30);
- scene->_gameBoardSide[1]._handCard[0]._card.setVisage(1332);
- scene->_gameBoardSide[1]._handCard[0]._card.setPosition(scene->_gameBoardSide[1]._handCard[0]._stationPos, 0);
- scene->_gameBoardSide[1]._handCard[0]._card.setStrip(1);
- scene->_gameBoardSide[1]._handCard[0]._card.setFrame(4);
- scene->_gameBoardSide[1]._handCard[0]._card.fixPriority(170);
- scene->_aSound2.play(61);
-
- Common::Point pt(10, 174);
- NpcMover *mover = new NpcMover();
- scene->_animatedCard._card.addMover(mover, &pt, this);
-
- scene->_gameBoardSide[2]._handCard[0]._cardId = scene->_availableCardsPile[scene->_cardsAvailableNumb];
- }
- break;
- case 2: {
- scene->_gameBoardSide[2]._handCard[0]._card.postInit();
- scene->_gameBoardSide[2]._handCard[0]._card._moveDiff = Common::Point(30, 30);
- scene->_gameBoardSide[2]._handCard[0]._card.setVisage(1332);
- scene->_gameBoardSide[2]._handCard[0]._card.setPosition(scene->_gameBoardSide[2]._handCard[0]._stationPos, 0);
- scene->_gameBoardSide[2]._handCard[0]._card.fixPriority(170);
- if (scene->_gameBoardSide[2]._handCard[0]._cardId > 25) {
- scene->_gameBoardSide[2]._handCard[0]._card.setStrip(4);
- scene->_gameBoardSide[2]._handCard[0]._card.setFrame(scene->_gameBoardSide[2]._handCard[0]._cardId - 25);
- } else if (scene->_gameBoardSide[2]._handCard[0]._cardId > 9) {
- scene->_gameBoardSide[2]._handCard[0]._card.setStrip(3);
- scene->_gameBoardSide[2]._handCard[0]._card.setFrame(scene->_gameBoardSide[2]._handCard[0]._cardId - 9);
- } else {
- scene->_gameBoardSide[2]._handCard[0]._card.setStrip(2);
- scene->_gameBoardSide[2]._handCard[0]._card.setFrame(scene->_gameBoardSide[2]._handCard[0]._cardId);
- }
- scene->_aSound2.play(61);
-
- Common::Point pt(14, 14);
- NpcMover *mover = new NpcMover();
- scene->_animatedCard._card.addMover(mover, &pt, this);
-
- scene->_gameBoardSide[3]._handCard[0]._cardId = scene->_availableCardsPile[scene->_cardsAvailableNumb];
- }
- break;
- case 3: {
- scene->_gameBoardSide[3]._handCard[0]._card.postInit();
- scene->_gameBoardSide[3]._handCard[0]._card._moveDiff = Common::Point(30, 30);
- scene->_gameBoardSide[3]._handCard[0]._card.setVisage(1332);
- scene->_gameBoardSide[3]._handCard[0]._card.setPosition(scene->_gameBoardSide[3]._handCard[0]._stationPos, 0);
- scene->_gameBoardSide[3]._handCard[0]._card.setStrip(1);
- scene->_gameBoardSide[3]._handCard[0]._card.setFrame(3);
- scene->_gameBoardSide[3]._handCard[0]._card.fixPriority(170);
- scene->_aSound2.play(61);
-
- Common::Point pt(280, 5);
- NpcMover *mover = new NpcMover();
- scene->_animatedCard._card.addMover(mover, &pt, this);
-
- scene->_gameBoardSide[0]._handCard[0]._cardId = scene->_availableCardsPile[scene->_cardsAvailableNumb];
- }
- break;
- case 4: {
- scene->_gameBoardSide[0]._handCard[0]._card.postInit();
- scene->_gameBoardSide[0]._handCard[0]._card._moveDiff = Common::Point(30,30);
- scene->_gameBoardSide[0]._handCard[0]._card.setVisage(1332);
- scene->_gameBoardSide[0]._handCard[0]._card.setPosition(scene->_gameBoardSide[0]._handCard[0]._stationPos, 0);
- scene->_gameBoardSide[0]._handCard[0]._card.setStrip(5);
- scene->_gameBoardSide[0]._handCard[0]._card.setFrame(1);
- scene->_gameBoardSide[0]._handCard[0]._card.fixPriority(170);
- scene->_aSound2.play(61);
-
- Common::Point pt(283, 124);
- NpcMover *mover = new NpcMover();
- scene->_animatedCard._card.addMover(mover, &pt, this);
-
- scene->_gameBoardSide[1]._handCard[1]._cardId = scene->_availableCardsPile[scene->_cardsAvailableNumb];
- }
- break;
- case 5: {
- scene->_gameBoardSide[1]._handCard[1]._card.postInit();
- scene->_gameBoardSide[1]._handCard[1]._card._moveDiff = Common::Point(30, 30);
- scene->_gameBoardSide[1]._handCard[1]._card.setVisage(1332);
- scene->_gameBoardSide[1]._handCard[1]._card.setPosition(scene->_gameBoardSide[1]._handCard[1]._stationPos, 0);
- scene->_gameBoardSide[1]._handCard[1]._card.setStrip(1);
- scene->_gameBoardSide[1]._handCard[1]._card.setFrame(4);
- scene->_gameBoardSide[1]._handCard[1]._card.fixPriority(170);
- scene->_aSound2.play(61);
-
- Common::Point pt(37, 174);
- NpcMover *mover = new NpcMover();
- scene->_animatedCard._card.addMover(mover, &pt, this);
-
- scene->_gameBoardSide[2]._handCard[1]._cardId = scene->_availableCardsPile[scene->_cardsAvailableNumb];
- }
- break;
- case 6: {
- scene->_gameBoardSide[2]._handCard[1]._card.postInit();
- scene->_gameBoardSide[2]._handCard[1]._card._moveDiff = Common::Point(30, 30);
- scene->_gameBoardSide[2]._handCard[1]._card.setVisage(1332);
- scene->_gameBoardSide[2]._handCard[1]._card.setPosition(scene->_gameBoardSide[2]._handCard[1]._stationPos, 0);
- scene->_gameBoardSide[2]._handCard[1]._card.fixPriority(170);
-
- if (scene->_gameBoardSide[2]._handCard[1]._cardId > 25) {
- scene->_gameBoardSide[2]._handCard[1]._card.setStrip(4);
- scene->_gameBoardSide[2]._handCard[1]._card.setFrame(scene->_gameBoardSide[2]._handCard[1]._cardId - 25);
- } else if (scene->_gameBoardSide[2]._handCard[1]._cardId > 9) {
- scene->_gameBoardSide[2]._handCard[1]._card.setStrip(3);
- scene->_gameBoardSide[2]._handCard[1]._card.setFrame(scene->_gameBoardSide[2]._handCard[1]._cardId - 9);
- } else {
- scene->_gameBoardSide[2]._handCard[1]._card.setStrip(2);
- scene->_gameBoardSide[2]._handCard[1]._card.setFrame(scene->_gameBoardSide[2]._handCard[1]._cardId);
- }
-
- scene->_aSound2.play(61);
-
- Common::Point pt(14, 36);
- NpcMover *mover = new NpcMover();
- scene->_animatedCard._card.addMover(mover, &pt, this);
-
- scene->_gameBoardSide[3]._handCard[1]._cardId = scene->_availableCardsPile[scene->_cardsAvailableNumb];
- }
- break;
- case 7: {
- scene->_gameBoardSide[3]._handCard[1]._card.postInit();
- scene->_gameBoardSide[3]._handCard[1]._card._moveDiff = Common::Point(30, 30);
- scene->_gameBoardSide[3]._handCard[1]._card.setVisage(1332);
- scene->_gameBoardSide[3]._handCard[1]._card.setPosition(scene->_gameBoardSide[3]._handCard[1]._stationPos);
- scene->_gameBoardSide[3]._handCard[1]._card.setStrip(1);
- scene->_gameBoardSide[3]._handCard[1]._card.setFrame(3);
- scene->_gameBoardSide[3]._handCard[1]._card.fixPriority(170);
- scene->_aSound2.play(61);
-
- Common::Point pt(253, 5);
- NpcMover *mover = new NpcMover();
- scene->_animatedCard._card.addMover(mover, &pt, this);
-
- scene->_gameBoardSide[0]._handCard[1]._cardId = scene->_availableCardsPile[scene->_cardsAvailableNumb];
- }
- break;
- case 8: {
- scene->_gameBoardSide[0]._handCard[1]._card.postInit();
- scene->_gameBoardSide[0]._handCard[1]._card._moveDiff = Common::Point(30, 30);
- scene->_gameBoardSide[0]._handCard[1]._card.setVisage(1332);
- scene->_gameBoardSide[0]._handCard[1]._card.setPosition(scene->_gameBoardSide[0]._handCard[1]._stationPos, 0);
- scene->_gameBoardSide[0]._handCard[1]._card.setStrip(5);
- scene->_gameBoardSide[0]._handCard[1]._card.setFrame(1);
- scene->_gameBoardSide[0]._handCard[1]._card.fixPriority(170);
- scene->_aSound2.play(61);
-
- Common::Point pt(283, 102);
- NpcMover *mover = new NpcMover();
- scene->_animatedCard._card.addMover(mover, &pt, this);
-
- scene->_gameBoardSide[1]._handCard[2]._cardId = scene->_availableCardsPile[scene->_cardsAvailableNumb];
- }
- break;
- case 9: {
- scene->_gameBoardSide[1]._handCard[2]._card.postInit();
- scene->_gameBoardSide[1]._handCard[2]._card._moveDiff = Common::Point(30, 30);
- scene->_gameBoardSide[1]._handCard[2]._card.setVisage(1332);
- scene->_gameBoardSide[1]._handCard[2]._card.setPosition(scene->_gameBoardSide[1]._handCard[2]._stationPos, 0);
- scene->_gameBoardSide[1]._handCard[2]._card.setStrip(1);
- scene->_gameBoardSide[1]._handCard[2]._card.setFrame(4);
- scene->_gameBoardSide[1]._handCard[2]._card.fixPriority(170);
- scene->_aSound2.play(61);
-
- Common::Point pt(64, 174);
- NpcMover *mover = new NpcMover();
- scene->_animatedCard._card.addMover(mover, &pt, this);
-
- scene->_gameBoardSide[2]._handCard[2]._cardId = scene->_availableCardsPile[scene->_cardsAvailableNumb];
- }
- break;
- case 10: {
- scene->_gameBoardSide[2]._handCard[2]._card.postInit();
- scene->_gameBoardSide[2]._handCard[2]._card._moveDiff = Common::Point(30, 30);
- scene->_gameBoardSide[2]._handCard[2]._card.setVisage(1332);
- scene->_gameBoardSide[2]._handCard[2]._card.setPosition(scene->_gameBoardSide[2]._handCard[2]._stationPos, 0);
- scene->_gameBoardSide[2]._handCard[2]._card.fixPriority(170);
-
- if (scene->_gameBoardSide[2]._handCard[2]._cardId > 25) {
- scene->_gameBoardSide[2]._handCard[2]._card.setStrip(4);
- scene->_gameBoardSide[2]._handCard[2]._card.setFrame(scene->_gameBoardSide[2]._handCard[2]._cardId - 25);
- } else if (scene->_gameBoardSide[2]._handCard[2]._cardId > 9) {
- scene->_gameBoardSide[2]._handCard[2]._card.setStrip(3);
- scene->_gameBoardSide[2]._handCard[2]._card.setFrame(scene->_gameBoardSide[2]._handCard[2]._cardId - 9);
- } else {
- scene->_gameBoardSide[2]._handCard[2]._card.setStrip(2);
- scene->_gameBoardSide[2]._handCard[2]._card.setFrame(scene->_gameBoardSide[2]._handCard[2]._cardId);
- }
-
- scene->_aSound2.play(61);
-
- Common::Point pt(14, 58);
- NpcMover *mover = new NpcMover();
- scene->_animatedCard._card.addMover(mover, &pt, this);
-
- scene->_gameBoardSide[3]._handCard[2]._cardId = scene->_availableCardsPile[scene->_cardsAvailableNumb];
- }
- break;
- case 11: {
- scene->_gameBoardSide[3]._handCard[2]._card.postInit();
- scene->_gameBoardSide[3]._handCard[2]._card._moveDiff = Common::Point(30, 30);
- scene->_gameBoardSide[3]._handCard[2]._card.setVisage(1332);
- scene->_gameBoardSide[3]._handCard[2]._card.setPosition(scene->_gameBoardSide[3]._handCard[2]._stationPos, 0);
- scene->_gameBoardSide[3]._handCard[2]._card.setStrip(1);
- scene->_gameBoardSide[3]._handCard[2]._card.setFrame(3);
- scene->_gameBoardSide[3]._handCard[2]._card.fixPriority(170);
- scene->_aSound2.play(61);
-
- Common::Point pt(226, 5);
- NpcMover *mover = new NpcMover();
- scene->_animatedCard._card.addMover(mover, &pt, this);
-
- scene->_gameBoardSide[0]._handCard[2]._cardId = scene->_availableCardsPile[scene->_cardsAvailableNumb];
- }
- break;
- case 12:
- scene->_gameBoardSide[0]._handCard[2]._card.postInit();
- scene->_gameBoardSide[0]._handCard[2]._card._moveDiff = Common::Point(30, 30);
- scene->_gameBoardSide[0]._handCard[2]._card.setVisage(1332);
- scene->_gameBoardSide[0]._handCard[2]._card.setPosition(scene->_gameBoardSide[0]._handCard[2]._stationPos, 0);
- scene->_gameBoardSide[0]._handCard[2]._card.setStrip(5);
- scene->_gameBoardSide[0]._handCard[2]._card.setFrame(1);
- scene->_gameBoardSide[0]._handCard[2]._card.fixPriority(170);
- scene->_animatedCard._card.hide();
- default:
- break;
- }
-
- if (_actionIndex > 12) {
- scene->_currentPlayerNumb = 0;
- R2_GLOBALS._sceneObjects->draw();
- scene->actionDisplay(1330, 0, 159, 10, 1, 200, 0, 7, 0, 154, 154);
- scene->handleNextTurn();
- } else if (_actionIndex >= 1) {
- scene->_availableCardsPile[scene->_cardsAvailableNumb] = 0;
- scene->_cardsAvailableNumb--;
- }
-}
-
-/**
- * Action used to handle the other players' turn
- */
-void Scene1337::Action4::signal() {
- Scene1337 *scene = (Scene1337 *)R2_GLOBALS._sceneManager._scene;
-
- switch (_actionIndex++) {
- case 0:
- if ( (scene->_gameBoardSide[scene->_currentPlayerNumb]._handCard[0]._cardId == 0)
- && (!scene->isStationCard(scene->_gameBoardSide[scene->_currentPlayerNumb]._delayCard._cardId))) {
- if (scene->_cardsAvailableNumb < 0)
- scene->shuffleCards();
- scene->_animatedCard._card.setPosition(Common::Point(162, 95), 0);
- scene->_animatedCard._card.show();
- scene->_aSound2.play(61);
-
- NpcMover *mover = new NpcMover();
- scene->_animatedCard._card.addMover(mover, &scene->_gameBoardSide[scene->_currentPlayerNumb]._card1Pos, this);
-
- scene->_gameBoardSide[scene->_currentPlayerNumb]._handCard[0]._cardId = scene->_availableCardsPile[scene->_cardsAvailableNumb];
- scene->_availableCardsPile[scene->_cardsAvailableNumb] = 0;
- scene->_cardsAvailableNumb--;
-
- if (scene->_cardsAvailableNumb < 0)
- scene->_stockPile.remove();
- } else {
- // Self call, forcing next actionIndex
- signal();
- }
- break;
- case 1:
- if ( (scene->_animatedCard._card._position.x == scene->_gameBoardSide[scene->_currentPlayerNumb]._card1Pos.x)
- && (scene->_animatedCard._card._position.y == scene->_gameBoardSide[scene->_currentPlayerNumb]._card1Pos.y) ) {
- scene->_gameBoardSide[scene->_currentPlayerNumb]._handCard[0]._card.postInit();
- scene->_gameBoardSide[scene->_currentPlayerNumb]._handCard[0]._card._moveDiff = Common::Point(30, 30);
- scene->_gameBoardSide[scene->_currentPlayerNumb]._handCard[0]._card.setVisage(1332);
- scene->_gameBoardSide[scene->_currentPlayerNumb]._handCard[0]._card.setPosition(scene->_gameBoardSide[scene->_currentPlayerNumb]._handCard[0]._stationPos, 0);
- scene->_gameBoardSide[scene->_currentPlayerNumb]._handCard[0]._card.setStrip(1);
- scene->_gameBoardSide[scene->_currentPlayerNumb]._handCard[0]._card.setFrame(scene->_gameBoardSide[scene->_currentPlayerNumb]._frameNum);
- scene->_gameBoardSide[scene->_currentPlayerNumb]._handCard[0]._card.fixPriority(170);
- }
-
- if ((R2_GLOBALS._debugCardGame) || (scene->_currentPlayerNumb == 2))
- scene->setAnimationInfo(&scene->_gameBoardSide[scene->_currentPlayerNumb]._handCard[0]);
-
- scene->_animatedCard._card.hide();
- if ( (scene->_gameBoardSide[scene->_currentPlayerNumb]._handCard[0]._cardId == 0)
- && (!scene->isStationCard(scene->_gameBoardSide[scene->_currentPlayerNumb]._delayCard._cardId))) {
- if (scene->_cardsAvailableNumb < 0)
- scene->shuffleCards();
- scene->_animatedCard._card.setPosition(Common::Point(162, 95));
- scene->_animatedCard._card.show();
-
- scene->_aSound2.play(61);
-
- NpcMover *mover = new NpcMover();
- scene->_animatedCard._card.addMover(mover, &scene->_gameBoardSide[scene->_currentPlayerNumb]._card2Pos, this);
-
- scene->_gameBoardSide[scene->_currentPlayerNumb]._handCard[1]._cardId = scene->_availableCardsPile[scene->_cardsAvailableNumb];
- scene->_availableCardsPile[scene->_cardsAvailableNumb] = 0;
- scene->_cardsAvailableNumb--;
- if (scene->_cardsAvailableNumb < 0)
- scene->_stockPile.remove();
- } else
- signal();
- break;
- case 2:
- if ( (scene->_animatedCard._card._position.x == scene->_gameBoardSide[scene->_currentPlayerNumb]._card2Pos.x)
- && (scene->_animatedCard._card._position.y == scene->_gameBoardSide[scene->_currentPlayerNumb]._card2Pos.y) ) {
- scene->_gameBoardSide[scene->_currentPlayerNumb]._handCard[1]._card.postInit();
- scene->_gameBoardSide[scene->_currentPlayerNumb]._handCard[1]._card._moveDiff = Common::Point(30, 30);
- scene->_gameBoardSide[scene->_currentPlayerNumb]._handCard[1]._card.setVisage(1332);
- scene->_gameBoardSide[scene->_currentPlayerNumb]._handCard[1]._card.setPosition(scene->_gameBoardSide[scene->_currentPlayerNumb]._handCard[1]._stationPos, 0);
- scene->_gameBoardSide[scene->_currentPlayerNumb]._handCard[1]._card.setStrip(1);
- scene->_gameBoardSide[scene->_currentPlayerNumb]._handCard[1]._card.setFrame(scene->_gameBoardSide[scene->_currentPlayerNumb]._frameNum);
- scene->_gameBoardSide[scene->_currentPlayerNumb]._handCard[1]._card.fixPriority(170);
- }
-
- if ((R2_GLOBALS._debugCardGame) || (scene->_currentPlayerNumb == 2))
- scene->setAnimationInfo(&scene->_gameBoardSide[scene->_currentPlayerNumb]._handCard[1]);
-
- scene->_animatedCard._card.hide();
- if ( (scene->_gameBoardSide[scene->_currentPlayerNumb]._handCard[2]._cardId == 0)
- && (!scene->isStationCard(scene->_gameBoardSide[scene->_currentPlayerNumb]._delayCard._cardId))) {
- if (scene->_cardsAvailableNumb < 0)
- scene->shuffleCards();
- scene->_animatedCard._card.setPosition(Common::Point(162, 95));
- scene->_animatedCard._card.show();
-
- scene->_aSound2.play(61);
-
- NpcMover *mover = new NpcMover();
- scene->_animatedCard._card.addMover(mover, &scene->_gameBoardSide[scene->_currentPlayerNumb]._card3Pos, this);
-
- scene->_gameBoardSide[scene->_currentPlayerNumb]._handCard[2]._cardId = scene->_availableCardsPile[scene->_cardsAvailableNumb];
- scene->_availableCardsPile[scene->_cardsAvailableNumb] = 0;
- scene->_cardsAvailableNumb--;
- if (scene->_cardsAvailableNumb < 0)
- scene->_stockPile.remove();
- } else
- signal();
- break;
- case 3:
- if ( (scene->_animatedCard._card._position.x == scene->_gameBoardSide[scene->_currentPlayerNumb]._card3Pos.x)
- && (scene->_animatedCard._card._position.y == scene->_gameBoardSide[scene->_currentPlayerNumb]._card3Pos.y) ) {
- scene->_gameBoardSide[scene->_currentPlayerNumb]._handCard[2]._card.postInit();
- scene->_gameBoardSide[scene->_currentPlayerNumb]._handCard[2]._card._moveDiff = Common::Point(30, 30);
- scene->_gameBoardSide[scene->_currentPlayerNumb]._handCard[2]._card.setVisage(1332);
- scene->_gameBoardSide[scene->_currentPlayerNumb]._handCard[2]._card.setPosition(scene->_gameBoardSide[scene->_currentPlayerNumb]._handCard[2]._stationPos, 0);
- scene->_gameBoardSide[scene->_currentPlayerNumb]._handCard[2]._card.setStrip(1);
- scene->_gameBoardSide[scene->_currentPlayerNumb]._handCard[2]._card.setFrame(scene->_gameBoardSide[scene->_currentPlayerNumb]._frameNum);
- scene->_gameBoardSide[scene->_currentPlayerNumb]._handCard[2]._card.fixPriority(170);
- }
-
- if ((R2_GLOBALS._debugCardGame) || (scene->_currentPlayerNumb == 2))
- scene->setAnimationInfo(&scene->_gameBoardSide[scene->_currentPlayerNumb]._handCard[2]);
-
- scene->_animatedCard._card.hide();
- if ( (scene->_gameBoardSide[scene->_currentPlayerNumb]._handCard[3]._cardId == 0)
- && (!scene->isStationCard(scene->_gameBoardSide[scene->_currentPlayerNumb]._delayCard._cardId))) {
- if (scene->_cardsAvailableNumb < 0)
- scene->shuffleCards();
- scene->_animatedCard._card.setPosition(Common::Point(162, 95));
- scene->_animatedCard._card.show();
-
- scene->_aSound2.play(61);
-
- NpcMover *mover = new NpcMover();
- scene->_animatedCard._card.addMover(mover, &scene->_gameBoardSide[scene->_currentPlayerNumb]._card4Pos, this);
-
- scene->_gameBoardSide[scene->_currentPlayerNumb]._handCard[3]._cardId = scene->_availableCardsPile[scene->_cardsAvailableNumb];
- scene->_availableCardsPile[scene->_cardsAvailableNumb] = 0;
- scene->_cardsAvailableNumb--;
- if (scene->_cardsAvailableNumb < 0)
- scene->_stockPile.remove();
- } else
- signal();
- break;
- case 4:
- if ( (scene->_animatedCard._card._position.x == scene->_gameBoardSide[scene->_currentPlayerNumb]._card4Pos.x)
- && (scene->_animatedCard._card._position.y == scene->_gameBoardSide[scene->_currentPlayerNumb]._card4Pos.y) ) {
- scene->_gameBoardSide[scene->_currentPlayerNumb]._handCard[3]._card.postInit();
- scene->_gameBoardSide[scene->_currentPlayerNumb]._handCard[3]._card._moveDiff = Common::Point(30, 30);
- scene->_gameBoardSide[scene->_currentPlayerNumb]._handCard[3]._card.setVisage(1332);
- scene->_gameBoardSide[scene->_currentPlayerNumb]._handCard[3]._card.setPosition(scene->_gameBoardSide[scene->_currentPlayerNumb]._handCard[3]._stationPos, 0);
- scene->_gameBoardSide[scene->_currentPlayerNumb]._handCard[3]._card.setStrip(1);
- scene->_gameBoardSide[scene->_currentPlayerNumb]._handCard[3]._card.setFrame(scene->_gameBoardSide[scene->_currentPlayerNumb]._frameNum);
- scene->_gameBoardSide[scene->_currentPlayerNumb]._handCard[3]._card.fixPriority(170);
- }
-
- if ((R2_GLOBALS._debugCardGame) || (scene->_currentPlayerNumb == 2))
- scene->setAnimationInfo(&scene->_gameBoardSide[scene->_currentPlayerNumb]._handCard[3]);
-
- scene->_animatedCard._card.hide();
- switch (scene->_currentPlayerNumb) {
- case 0:
- scene->handlePlayer0();
- break;
- case 1:
- scene->handlePlayer1();
- break;
- case 2:
- scene->handleAutoplayPlayer2();
- break;
- case 3:
- scene->handlePlayer3();
- break;
- default:
- break;
- }
- break;
- default:
- break;
- }
-}
-
-/**
- * Animations for discarding a card
- */
-void Scene1337::Action5::signal() {
- Scene1337 *scene = (Scene1337 *)R2_GLOBALS._sceneManager._scene;
-
- switch (_actionIndex++) {
- case 0: {
- scene->_availableCardsPile[scene->_currentDiscardIndex] = scene->_actionCard1->_cardId;
- scene->_currentDiscardIndex--;
- if (!g_globals->_sceneObjects->contains(&scene->_discardPile._card)) {
- // The first discarded card makes the pile appear
- scene->_discardPile._card.postInit();
- scene->_discardPile._card.hide();
- scene->_discardPile._card.setVisage(1332);
- scene->_discardPile._card.setPosition(scene->_discardPile._stationPos, 0);
- scene->_discardPile._card.fixPriority(170);
- }
-
- scene->_discardPile._cardId = scene->_actionCard1->_cardId;
- scene->_actionCard1->_cardId = 0;
- scene->_actionCard1->_card.remove();
-
- if (scene->_actionCard1 == &scene->_selectedCard) {
- scene->setCursorData(5, 1, 4);
- scene->subC4CEC();
- }
- scene->_animatedCard._card.setPosition(scene->_actionCard1->_stationPos, 0);
- scene->_animatedCard._card.show();
- Common::Point pt(128, 95);
- NpcMover *mover = new NpcMover();
- scene->_animatedCard._card.addMover(mover, &pt, this);
- }
- break;
- case 1:
- scene->_animatedCard._card.hide();
- scene->setAnimationInfo(&scene->_discardPile);
- scene->_aSound2.play(61);
- scene->handleNextTurn();
- break;
- default:
- break;
- }
-}
-
-/**
- * Animations for playing a platform card
- */
-void Scene1337::Action6::signal() {
- Scene1337 *scene = (Scene1337 *)R2_GLOBALS._sceneManager._scene;
-
- switch (_actionIndex++) {
- case 0: {
- scene->_actionCard2->_cardId = 1;
- scene->_actionCard2->_card.postInit();
- scene->_actionCard2->_card.hide();
- scene->_actionCard2->_card.setVisage(1332);
- scene->_actionCard2->_card.setPosition(scene->_actionCard2->_stationPos);
- scene->_actionCard2->_card.fixPriority(170);
-
- scene->_actionCard1->_cardId = 0;
- scene->_actionCard1->_card.remove();
-
- scene->_animatedCard._card.setPosition(scene->_actionCard1->_stationPos);
- scene->_animatedCard._card.show();
-
- NpcMover *mover = new NpcMover();
- scene->_animatedCard._card.addMover(mover, &scene->_actionCard2->_stationPos, this);
- }
- break;
- case 1:
- scene->_animatedCard._card.hide();
- scene->setAnimationInfo(scene->_actionCard2);
- scene->_aSound1.play(59);
- if (scene->_actionCard1 == &scene->_selectedCard) {
- scene->setCursorData(5, 1, 4);
- scene->subC4CEC();
- }
- scene->handleNextTurn();
- break;
- default:
- break;
- }
-}
-
-/**
- * Upgrade platform to station by playing a station card on top of it
- */
-void Scene1337::Action7::signal() {
- Scene1337 *scene = (Scene1337 *)R2_GLOBALS._sceneManager._scene;
-
- switch (_actionIndex++) {
- case 0: {
- scene->_actionCard2->_cardId = scene->_actionCard1->_cardId;
-
- scene->_actionCard1->_cardId = 0;
- scene->_actionCard1->_card.remove();
-
- scene->_animatedCard._card.setPosition(scene->_actionCard1->_stationPos, 0);
- scene->_animatedCard._card.show();
- NpcMover *mover = new NpcMover();
- scene->_animatedCard._card.addMover(mover, &scene->_actionCard2->_stationPos, this);
- }
- break;
- case 1:
- if (scene->_actionCard1 == &scene->_selectedCard) {
- scene->setCursorData(5, 1, 4);
- scene->subC4CEC();
- }
- scene->setAnimationInfo(scene->_actionCard2);
- scene->_aSound1.play(59);
- scene->_discardedPlatformCard._cardId = 1;
- scene->_discardedPlatformCard._stationPos = scene->_actionCard2->_stationPos;
- scene->_discardedPlatformCard._card.postInit();
- scene->_discardedPlatformCard._card.hide();
- scene->_discardedPlatformCard._card._flags = OBJFLAG_HIDING;
-
- scene->discardCard(&scene->_discardedPlatformCard);
- break;
- default:
- break;
- }
-}
-
-void Scene1337::Action8::signal() {
- Scene1337 *scene = (Scene1337 *)R2_GLOBALS._sceneManager._scene;
-
- switch (_actionIndex++) {
- case 0: {
- scene->_availableCardsPile[scene->_currentDiscardIndex] = scene->_actionCard2->_cardId;
- scene->_currentDiscardIndex--;
-
- scene->_actionCard2->_cardId = scene->_actionCard1->_cardId;
- scene->_actionCard1->_card.remove();
-
- scene->_animatedCard._card.setPosition(scene->_actionCard1->_stationPos, 0);
- scene->_animatedCard._card.show();
-
- NpcMover *mover = new NpcMover();
- scene->_animatedCard._card.addMover(mover, &scene->_actionCard2->_stationPos, this);
- }
- break;
- case 1:
- scene->_animatedCard._card.hide();
-
- if (scene->_actionCard1 == &scene->_selectedCard) {
- scene->setCursorData(5, 1, 4);
- scene->subC4CEC();
- }
- scene->setAnimationInfo(scene->_actionCard2);
- scene->_aSound1.play(58);
- scene->discardCard(scene->_actionCard2);
- break;
- default:
- break;
- }
-}
-
-// Play delay card
-void Scene1337::Action9::signal() {
- Scene1337 *scene = (Scene1337 *)R2_GLOBALS._sceneManager._scene;
-
- switch (_actionIndex++) {
- case 0: {
- scene->_actionCard2->_cardId = scene->_actionCard1->_cardId;
- scene->_actionCard2->_card.postInit();
- scene->_actionCard2->_card.hide();
- scene->_actionCard2->_card.setVisage(1332);
- scene->_actionCard2->_card.setPosition(scene->_actionCard2->_stationPos, 0);
- scene->_actionCard2->_card.fixPriority(170);
-
- scene->_actionCard1->_cardId = 0;
- scene->_actionCard1->_card.remove();
-
- scene->_animatedCard._card.setPosition(scene->_actionCard1->_stationPos, 0);
- scene->_animatedCard._card.show();
-
- NpcMover *mover = new NpcMover();
- scene->_animatedCard._card.addMover(mover, &scene->_actionCard2->_stationPos, this);
- }
- break;
- case 1:
- scene->_animatedCard._card.hide();
- scene->setAnimationInfo(scene->_actionCard2);
- scene->_aSound1.play(57);
-
- if (scene->_actionCard1 == &scene->_selectedCard) {
- scene->setCursorData(5, 1, 4);
- scene->subC4CEC();
- }
-
- scene->handleNextTurn();
- break;
- default:
- break;
- }
-}
-
-// Counter a trick with a card
-void Scene1337::Action10::signal() {
- Scene1337 *scene = (Scene1337 *)R2_GLOBALS._sceneManager._scene;
-
- switch (_actionIndex++) {
- case 0: {
- scene->_actionCard3->_card.postInit();
- scene->_actionCard3->_card.hide();
- scene->_actionCard3->_card.setVisage(1332);
- scene->_actionCard3->_card.setPosition(scene->_actionCard3->_stationPos, 0);
- scene->_actionCard3->_card.fixPriority(170);
- scene->_actionCard3->_cardId = scene->_actionCard1->_cardId;
-
- scene->_actionCard1->_cardId = 0;
- scene->_actionCard1->_card.remove();
-
- if (scene->_actionCard1 == &scene->_selectedCard) {
- scene->setCursorData(5, 1, 4);
- scene->subC4CEC();
- }
-
- scene->_animatedCard._card.setPosition(scene->_actionCard1->_stationPos, 0);
- scene->_animatedCard._card.show();
- NpcMover *mover = new NpcMover();
- scene->_animatedCard._card.addMover(mover, &scene->_actionCard3->_stationPos, this);
- }
- break;
- case 1: {
- scene->_animatedCard._card.hide();
- scene->setAnimationInfo(scene->_actionCard3);
- scene->_aSound1.play(57);
-
- bool found = false;
- int indexFound = -1;
-
- switch (scene->_actionIdx1) {
- case 0:
- for (indexFound = 0; indexFound < 3; indexFound++) {
- if (scene->_gameBoardSide[0]._handCard[indexFound]._cardId == 29) {
- found = true;
- break;
- }
- }
- break;
- case 1:
- for (indexFound = 0; indexFound < 3; indexFound++) {
- if (scene->_gameBoardSide[1]._handCard[indexFound]._cardId == 29) {
- found = true;
- break;
- }
- }
- break;
- case 2:
- for (indexFound = 0; indexFound < 3; indexFound++) {
- if (scene->_gameBoardSide[2]._handCard[indexFound]._cardId == 29) {
- found = true;
- break;
- }
- }
- break;
- case 3:
- for (indexFound = 0; indexFound < 3; indexFound++) {
- if (scene->_gameBoardSide[3]._handCard[indexFound]._cardId == 29) {
- found = true;
- break;
- }
- }
- break;
- default:
- break;
- }
-
- bool found2 = false;
-
- if (found) {
- switch (scene->_actionIdx1) {
- case 0:
- scene->subC51A0(&scene->_gameBoardSide[0]._handCard[indexFound], scene->_actionCard3);
- found2 = true;
- break;
- case 1:
- scene->subC51A0(&scene->_gameBoardSide[1]._handCard[indexFound], scene->_actionCard3);
- found2 = true;
- break;
- case 2:
- scene->subC4CD2();
- if (MessageDialog::show(USE_INTERCEPTOR, NO_MSG, YES_MSG) == 0)
- scene->subC4CEC();
- else {
- scene->subC51A0(&scene->_gameBoardSide[2]._handCard[indexFound], scene->_actionCard3);
- found2 = true;
- }
- break;
- case 3:
- scene->subC51A0(&scene->_gameBoardSide[3]._handCard[indexFound], scene->_actionCard3);
- found2 = true;
- break;
- default:
- break;
- }
- }
-
- if (!found2)
- break;
-
- if (scene->_actionIdx1 == 2) {
- int j = 0;
- for (int i = 0; i <= 7; i++) {
- if (scene->_gameBoardSide[2]._outpostStation[i]._cardId != 0)
- ++j;
- }
-
- if (j <= 1) {
- for (int i = 0; i <= 7; i++) {
- if (scene->_gameBoardSide[2]._outpostStation[i]._cardId != 0) {
- scene->_actionCard2 = &scene->_gameBoardSide[2]._outpostStation[i];
- break;
- }
- }
- } else {
- scene->subC4CD2();
-
- found2 = false;
- while (!found2) {
- scene->actionDisplay(1330, 130, 159, 10, 1, 200, 0, 7, 0, 154, 154);
-
- // Wait for a mouse or keypress
- Event event;
- while (!g_globals->_events.getEvent(event, EVENT_BUTTON_DOWN | EVENT_KEYPRESS) && !g_vm->shouldQuit()) {
- g_globals->_scenePalette.signalListeners();
- R2_GLOBALS._sceneObjects->draw();
- g_globals->_events.delay(g_globals->_sceneHandler->_delayTicks);
- }
-
- scene->_selectedCard._stationPos = event.mousePos;
-
- for (int i = 0; i <= 7; i++) {
- if (scene->_gameBoardSide[2]._outpostStation[i].isIn(scene->_selectedCard._stationPos) && (scene->_gameBoardSide[2]._outpostStation[i]._cardId != 0)) {
- scene->_actionCard2 = &scene->_gameBoardSide[2]._outpostStation[0];
- found2 = true;
- break;
- }
- }
- }
- scene->subC4CEC();
- }
- }
-
- scene->_availableCardsPile[scene->_currentDiscardIndex] = scene->_actionCard2->_cardId;
- scene->_currentDiscardIndex--;
- scene->_actionCard2->_cardId = 0;
- scene->_actionCard2->_card.remove();
-
- scene->_animatedCard._card.setPosition(scene->_actionCard2->_stationPos, 0);
- scene->_animatedCard._card.show();
-
- NpcMover *mover = new NpcMover();
- scene->_animatedCard._card.addMover(mover, &scene->_actionCard3->_stationPos, this);
- }
- break;
- case 2:
- scene->_animatedCard._card.hide();
- scene->discardCard(scene->_actionCard3);
- break;
- default:
- break;
- }
-}
-
-// Use trick (card #25 - thieft ?) and pick a card from the opponent
-void Scene1337::Action11::signal() {
- Scene1337 *scene = (Scene1337 *)R2_GLOBALS._sceneManager._scene;
-
- switch (_actionIndex++) {
- case 0: {
- scene->_actionCard2->_card.postInit();
- scene->_actionCard2->_card.hide();
- scene->_actionCard2->_card.setVisage(1332);
- scene->_actionCard2->_card.setPosition(scene->_actionCard2->_stationPos, 0);
- scene->_actionCard2->_card.fixPriority(170);
- scene->_actionCard2->_cardId = 25;
-
- if (scene->_actionIdx1 == 2) {
- scene->_animatedCard._card.setPosition(scene->_actionCard2->_stationPos, 0);
- scene->setCursorData(5, 1, 4);
- } else {
- scene->_actionCard1->_cardId = 0;
- scene->_actionCard1->_card.remove();
- scene->_animatedCard._card.setPosition(scene->_actionCard1->_stationPos, 0);
- }
- scene->_animatedCard._card.show();
-
- NpcMover *mover = new NpcMover();
- scene->_animatedCard._card.addMover(mover, &scene->_actionCard2->_stationPos, this);
- }
- break;
- case 1: {
- scene->_animatedCard._card.hide();
- scene->setAnimationInfo(scene->_actionCard2);
- scene->_aSound1.play(57);
-
- bool found = false;
- bool noAction = true;
-
- int i = -1;
-
- switch (scene->_actionIdx2) {
- case 0:
- for (i = 0; i <= 3; i++) {
- if (scene->_gameBoardSide[0]._handCard[i]._cardId == 27) {
- found = true;
- break;
- }
- }
-
- if ((found) && (scene->getFreeHandCard(scene->_actionIdx1) != -1)) {
- scene->_actionCard1 = &scene->_gameBoardSide[0]._handCard[i];
- scene->_actionCard2 = &scene->_gameBoardSide[0]._emptyStationPos;
- if (scene->_actionIdx1 != 0) {
- int tmpVal = scene->getFreeHandCard(scene->_actionIdx1);
- scene->_actionCard3 = &scene->_gameBoardSide[scene->_actionIdx1]._handCard[tmpVal];
- }
- scene->_actionItem.setAction(&scene->_action12);
- noAction = false;
- }
- break;
- case 1:
- for (i = 0; i <= 3; i++) {
- if (scene->_gameBoardSide[1]._handCard[i]._cardId == 27) {
- found = true;
- break;
- }
- }
-
- if ((found) && (scene->getFreeHandCard(scene->_actionIdx1) != -1)) {
- scene->_actionCard1 = &scene->_gameBoardSide[1]._handCard[i];
- scene->_actionCard2 = &scene->_gameBoardSide[1]._emptyStationPos;
- if (scene->_actionIdx1 != 1) {
- int tmpVal = scene->getFreeHandCard(scene->_actionIdx1);
- scene->_actionCard3 = &scene->_gameBoardSide[scene->_actionIdx1]._handCard[tmpVal];
- }
- scene->_actionItem.setAction(&scene->_action12);
- noAction = false;
- }
- break;
- case 2:
- for (i = 0; i <= 3; i++) {
- if (scene->_gameBoardSide[2]._handCard[i]._cardId == 27) {
- found = true;
- break;
- }
- }
-
- if ((found) && (scene->getFreeHandCard(scene->_actionIdx1) != -1)) {
- scene->subC4CD2();
- if (MessageDialog::show(USE_DOUBLE_AGENT, NO_MSG, YES_MSG) == 0)
- scene->subC4CEC();
- else {
- scene->subC4CEC();
- scene->_actionCard1 = &scene->_gameBoardSide[2]._handCard[i];
- scene->_actionCard2 = &scene->_gameBoardSide[2]._emptyStationPos;
- if (scene->_actionIdx1 != 2) {
- int tmpVal = scene->getFreeHandCard(scene->_actionIdx1);
- scene->_actionCard3 = &scene->_gameBoardSide[scene->_actionIdx1]._handCard[tmpVal];
- }
- scene->_actionItem.setAction(&scene->_action12);
- noAction = false;
- }
- }
- break;
- case 3:
- for (i = 0; i <= 3; i++) {
- if (scene->_gameBoardSide[3]._handCard[i]._cardId == 27) {
- found = true;
- break;
- }
- }
-
- if ((found) && (scene->getFreeHandCard(scene->_actionIdx1) != -1)) {
- scene->_actionCard1 = &scene->_gameBoardSide[3]._handCard[i];
- scene->_actionCard2 = &scene->_gameBoardSide[3]._emptyStationPos;
- if (scene->_actionIdx1 != 3) {
- int tmpVal = scene->getFreeHandCard(scene->_actionIdx1);
- scene->_actionCard3 = &scene->_gameBoardSide[scene->_actionIdx1]._handCard[tmpVal];
- }
- scene->_actionItem.setAction(&scene->_action12);
- noAction = false;
- }
- break;
- default:
- break;
- }
-
- if (!noAction)
- return;
-
- if (scene->_actionIdx1 == 2) {
- int count = 0;
- if (scene->_actionIdx2 != 2) {
- for (i = 0; i <= 3; i++) {
- if (scene->_gameBoardSide[scene->_actionIdx2]._handCard[i]._cardId == 0)
- ++count;
- }
- }
-
- if (count > 1) {
- scene->subC4CD2();
-
- found = false;
- while (!found) {
- switch (scene->_actionIdx2) {
- case 0:
- scene->actionDisplay(1330, 131, 159, 10, 1, 200, 0, 7, 0, 154, 154);
- break;
- case 1:
- scene->actionDisplay(1330, 132, 159, 10, 1, 200, 0, 7, 0, 154, 154);
- break;
- case 3:
- scene->actionDisplay(1330, 133, 159, 10, 1, 200, 0, 7, 0, 154, 154);
- break;
- default:
- break;
- }
-
- Event event;
- while (!g_globals->_events.getEvent(event, EVENT_BUTTON_DOWN | EVENT_KEYPRESS) && !g_vm->shouldQuit()) {
- g_globals->_scenePalette.signalListeners();
- R2_GLOBALS._sceneObjects->draw();
- g_globals->_events.delay(g_globals->_sceneHandler->_delayTicks);
- }
-
- scene->_selectedCard._stationPos = event.mousePos;
-
- found = false;
-
- if (scene->_actionIdx2 != 2) {
- for (i = 0; i <= 3; i++) {
- if (scene->_gameBoardSide[scene->_actionIdx2]._handCard[i].isIn(scene->_selectedCard._stationPos) && (scene->_gameBoardSide[scene->_actionIdx2]._handCard[i]._cardId != 0)) {
- scene->_actionCard3 = &scene->_gameBoardSide[scene->_actionIdx2]._handCard[i];
- found = true;
- break;
- }
- }
- }
- } // while
- scene->_displayHelpFl = true;
- scene->subC4CEC();
- } else if (scene->_actionIdx2 != 2) {
- int tmpVal = scene->getFreeHandCard(scene->_actionIdx2);
- scene->_actionCard3 = &scene->_gameBoardSide[scene->_actionIdx2]._handCard[tmpVal];
- }
- }
-
- scene->_actionCard1->_card.postInit();
- scene->_actionCard1->_card.hide();
- scene->_actionCard1->_card.setVisage(1332);
- scene->_actionCard1->_card.setPosition(scene->_actionCard1->_stationPos, 0);
- scene->_actionCard1->_card.fixPriority(170);
- scene->_actionCard1->_card.setStrip2(1);
- scene->_actionCard1->_cardId = scene->_actionCard3->_cardId;
-
- scene->_actionCard3->_cardId = 0;
- scene->_actionCard3->_card.remove();
-
- scene->_animatedCard._card.setPosition(scene->_actionCard3->_stationPos, 0);
- scene->_animatedCard._card.show();
-
- NpcMover *mover = new NpcMover();
- scene->_animatedCard._card.addMover(mover, &scene->_actionCard1->_stationPos, this);
- }
- break;
- case 2:
- scene->_animatedCard._card.hide();
- switch (scene->_actionIdx1) {
- case 0:
- scene->_actionCard1->_card.setFrame2(2);
- scene->_actionCard1->_card.show();
- break;
- case 1:
- scene->_actionCard1->_card.setFrame2(4);
- scene->_actionCard1->_card.show();
- break;
- case 3:
- scene->_actionCard1->_card.setFrame2(3);
- scene->_actionCard1->_card.show();
- break;
- default:
- scene->setAnimationInfo(scene->_actionCard1);
- break;
- }
-
- scene->_currentPlayerNumb--;
- scene->_showPlayerTurn = false;
- scene->discardCard(scene->_actionCard2);
- break;
- default:
- break;
- }
-}
-
-// Pick a card in opponent hand
-void Scene1337::Action12::signal() {
- Scene1337 *scene = (Scene1337 *)R2_GLOBALS._sceneManager._scene;
-
- switch (_actionIndex++) {
- case 0:
- signal();
- break;
- case 1: {
- scene->_availableCardsPile[scene->_currentDiscardIndex] = scene->_actionCard2->_cardId;
- scene->_currentDiscardIndex++;
- scene->_actionCard2->_cardId = scene->_actionCard1->_cardId;
- scene->_actionCard1->_cardId = 0;
- scene->_actionCard1->_card.remove();
- scene->_animatedCard._card.setPosition(scene->_actionCard1->_stationPos, 0);
- scene->_animatedCard._card.show();
-
- NpcMover *mover = new NpcMover();
- scene->_animatedCard._card.addMover(mover, &scene->_actionCard2->_stationPos, this);
- }
- break;
- case 2:
- scene->_animatedCard._card.hide();
- scene->setAnimationInfo(scene->_actionCard2);
- scene->_aSound1.play(58);
- if (scene->_actionIdx2 == 2) {
- int count = 0;
- int i = -1;
- switch (scene->_actionIdx1) {
- case 0:
- for (i = 0; i <= 3; i++) {
- if (scene->_gameBoardSide[0]._handCard[i]._cardId != 0)
- ++count;
- }
- break;
- case 1:
- for (i = 0; i <= 3; i++) {
- // The original game was counting in the hand of player 3, which is obviously wrong
- if (scene->_gameBoardSide[1]._handCard[i]._cardId != 0)
- ++count;
- }
- break;
- case 3:
- for (i = 0; i <= 3; i++) {
- if (scene->_gameBoardSide[3]._handCard[i]._cardId != 0)
- ++count;
- }
- break;
- default:
- break;
- }
-
- if (count > 1) {
- scene->subC4CD2();
-
- bool found = false;
-
- while (!found) {
- switch (scene->_actionIdx1) {
- case 0:
- scene->actionDisplay(1330, 131, 159, 10, 1, 200, 0, 7, 0, 154, 154);
- break;
- case 1:
- scene->actionDisplay(1330, 132, 159, 10, 1, 200, 0, 7, 0, 154, 154);
- break;
- case 3:
- scene->actionDisplay(1330, 133, 159, 10, 1, 200, 0, 7, 0, 154, 154);
- break;
- default:
- break;
- }
-
- Event event;
- while (!g_globals->_events.getEvent(event, EVENT_BUTTON_DOWN | EVENT_KEYPRESS) && !g_vm->shouldQuit()) {
- g_globals->_scenePalette.signalListeners();
- R2_GLOBALS._sceneObjects->draw();
- g_globals->_events.delay(g_globals->_sceneHandler->_delayTicks);
- }
-
- scene->_selectedCard._stationPos = event.mousePos;
-
- if (scene->_actionIdx1 == 0) {
- for (i = 0; i <= 3; i++) {
- if (scene->_gameBoardSide[0]._handCard[i].isIn(scene->_selectedCard._stationPos) && (scene->_gameBoardSide[0]._handCard[i]._cardId != 0)) {
- found = true;
- scene->_actionCard3 = &scene->_gameBoardSide[0]._handCard[i];
- break;
- }
- }
- }
-
- if (scene->_actionIdx1 == 3) {
- for (i = 0; i <= 3; i++) {
- if (scene->_gameBoardSide[3]._handCard[i].isIn(scene->_selectedCard._stationPos) && (scene->_gameBoardSide[3]._handCard[i]._cardId != 0)) {
- found = true;
- scene->_actionCard3 = &scene->_gameBoardSide[3]._handCard[i];
- break;
- }
- }
- }
-
- if (scene->_actionIdx1 == 1) {
- for (i = 0; i <= 3; i++) {
- if (scene->_gameBoardSide[1]._handCard[i].isIn(scene->_selectedCard._stationPos) && (scene->_gameBoardSide[1]._handCard[i]._cardId != 0)) {
- found = true;
- scene->_actionCard3 = &scene->_gameBoardSide[1]._handCard[i];
- break;
- }
- }
- }
- }
- scene->subC4CEC();
- } else if (scene->_actionIdx1 != 1) {
- switch (scene->_actionIdx1) {
- case 0:
- scene->_actionCard3 = &scene->_gameBoardSide[0]._handCard[scene->getFreeHandCard(0)];
- break;
- case 3:
- scene->_actionCard3 = &scene->_gameBoardSide[3]._handCard[scene->getFreeHandCard(3)];
- break;
- default:
- break;
- }
- } else {
- scene->_actionCard3 = &scene->_gameBoardSide[1]._handCard[scene->getFreeHandCard(1)];
- }
-
- scene->_actionCard1->_card.postInit();
- scene->_actionCard1->_card.hide();
- scene->_actionCard1->_card.setVisage(1332);
- scene->_actionCard1->_card.setPosition(scene->_actionCard1->_stationPos);
- scene->_actionCard1->_card.fixPriority(170);
- scene->_actionCard1->_card.setStrip2(1);
- scene->_actionCard1->_cardId = scene->_actionCard3->_cardId;
-
- scene->_actionCard3->_cardId = 0;
- scene->_actionCard3->_card.remove();
-
- scene->_animatedCard._card.setPosition(scene->_actionCard3->_stationPos);
- scene->_animatedCard._card.show();
- scene->_aSound1.play(57);
-
- NpcMover *mover = new NpcMover();
- scene->_animatedCard._card.addMover(mover, &scene->_actionCard1->_stationPos, this);
- }
- break;
- case 3:
- scene->_animatedCard._card.hide();
- switch (scene->_actionIdx2) {
- case 0:
- scene->_actionCard1->_card.setFrame2(2);
- scene->_actionCard1->_card.show();
- break;
- case 1:
- scene->_actionCard1->_card.setFrame2(4);
- scene->_actionCard1->_card.show();
- break;
- case 3:
- scene->_actionCard1->_card.setFrame2(3);
- scene->_actionCard1->_card.show();
- break;
- default:
- scene->setAnimationInfo(scene->_actionCard1);
- break;
- }
- scene->discardCard(scene->_actionCard2);
- scene->handleNextTurn();
- break;
- default:
- break;
- }
-}
-
-void Scene1337::Action13::signal() {
- Scene1337 *scene = (Scene1337 *)R2_GLOBALS._sceneManager._scene;
-
- switch (_actionIndex++) {
- case 0: {
- scene->_availableCardsPile[scene->_currentDiscardIndex] = scene->_actionCard2->_cardId;
- scene->_currentDiscardIndex--;
-
- scene->_actionCard2->_cardId = scene->_actionCard1->_cardId;
-
- scene->_actionCard1->_cardId = 0;
- scene->_actionCard1->_card.remove();
-
- scene->_animatedCard._card.setPosition(scene->_actionCard1->_stationPos, 0);
- scene->_animatedCard._card.show();
-
- NpcMover *mover = new NpcMover();
- scene->_animatedCard._card.addMover(mover, &scene->_actionCard2->_stationPos, this);
- }
- break;
- case 1:
- scene->_animatedCard._card.hide();
- scene->setAnimationInfo(scene->_actionCard2);
- scene->_aSound1.play(58);
- signal();
- break;
- case 2:
- scene->discardCard(scene->_actionCard2);
- break;
- default:
- break;
- }
-}
-
-void Scene1337::postInit(SceneObjectList *OwnerList) {
-// In the original, may be found in subPostInit.
-// Without it, enableControl asserts
- loadScene(1330);
- R2_GLOBALS._uiElements._active = false;
- SceneExt::postInit();
-//
-
- // Hide the user interface
- BF_GLOBALS._interfaceY = SCREEN_HEIGHT;
- R2_GLOBALS._uiElements._visible = false;
-
- R2_GLOBALS._player.enableControl();
- R2_GLOBALS._player._canWalk = false;
- R2_GLOBALS._player._uiEnabled = false;
-
- _delayedFunction = nullptr;
-
- _actionCard1 = nullptr;
- _actionCard2 = nullptr;
- _actionCard3 = nullptr;
-
- _gameBoardSide[2]._handCard[0]._stationPos = Common::Point(10, 174);
- _gameBoardSide[2]._handCard[1]._stationPos = Common::Point(37, 174);
- _gameBoardSide[2]._handCard[2]._stationPos = Common::Point(64, 174);
- _gameBoardSide[2]._handCard[3]._stationPos = Common::Point(91, 174);
-
- _gameBoardSide[2]._outpostStation[0]._stationPos = Common::Point(119, 174);
- _gameBoardSide[2]._outpostStation[1]._stationPos = Common::Point(119, 148);
- _gameBoardSide[2]._outpostStation[2]._stationPos = Common::Point(119, 122);
- _gameBoardSide[2]._outpostStation[3]._stationPos = Common::Point(145, 122);
- _gameBoardSide[2]._outpostStation[4]._stationPos = Common::Point(171, 122);
- _gameBoardSide[2]._outpostStation[5]._stationPos = Common::Point(171, 148);
- _gameBoardSide[2]._outpostStation[6]._stationPos = Common::Point(171, 174);
- _gameBoardSide[2]._outpostStation[7]._stationPos = Common::Point(145, 174);
-
- _gameBoardSide[2]._delayCard._stationPos = Common::Point(199, 174);
-
- _gameBoardSide[2]._emptyStationPos._stationPos = Common::Point(145, 148);
-
- _gameBoardSide[2]._card1Pos = Common::Point(10, 174);
- _gameBoardSide[2]._card2Pos = Common::Point(37, 174);
- _gameBoardSide[2]._card3Pos = Common::Point(64, 174);
- _gameBoardSide[2]._card4Pos = Common::Point(91, 174);
- _gameBoardSide[2]._frameNum = 2;
-
- _gameBoardSide[3]._handCard[0]._stationPos = Common::Point(14, 14);
- _gameBoardSide[3]._handCard[1]._stationPos = Common::Point(14, 36);
- _gameBoardSide[3]._handCard[2]._stationPos = Common::Point(14, 58);
- _gameBoardSide[3]._handCard[3]._stationPos = Common::Point(14, 80);
-
- _gameBoardSide[3]._outpostStation[0]._stationPos = Common::Point(37, 66);
- _gameBoardSide[3]._outpostStation[1]._stationPos = Common::Point(63, 66);
- _gameBoardSide[3]._outpostStation[2]._stationPos = Common::Point(89, 66);
- _gameBoardSide[3]._outpostStation[3]._stationPos = Common::Point(89, 92);
- _gameBoardSide[3]._outpostStation[4]._stationPos = Common::Point(89, 118);
- _gameBoardSide[3]._outpostStation[5]._stationPos = Common::Point(63, 118);
- _gameBoardSide[3]._outpostStation[6]._stationPos = Common::Point(37, 118);
- _gameBoardSide[3]._outpostStation[7]._stationPos = Common::Point(37, 92);
-
- _gameBoardSide[3]._delayCard._stationPos = Common::Point(37, 145);
-
- _gameBoardSide[3]._emptyStationPos._stationPos = Common::Point(63, 92);
-
- _gameBoardSide[3]._card1Pos = Common::Point(14, 14);
- _gameBoardSide[3]._card2Pos = Common::Point(14, 36);
- _gameBoardSide[3]._card3Pos = Common::Point(14, 58);
- _gameBoardSide[3]._card4Pos = Common::Point(14, 80);
- _gameBoardSide[3]._frameNum = 3;
-
- _gameBoardSide[0]._handCard[0]._stationPos = Common::Point(280, 5);
- _gameBoardSide[0]._handCard[1]._stationPos = Common::Point(253, 5);
- _gameBoardSide[0]._handCard[2]._stationPos = Common::Point(226, 5);
- _gameBoardSide[0]._handCard[3]._stationPos = Common::Point(199, 5);
-
- _gameBoardSide[0]._outpostStation[0]._stationPos = Common::Point(171, 16);
- _gameBoardSide[0]._outpostStation[1]._stationPos = Common::Point(171, 42);
- _gameBoardSide[0]._outpostStation[2]._stationPos = Common::Point(171, 68);
- _gameBoardSide[0]._outpostStation[3]._stationPos = Common::Point(145, 68);
- _gameBoardSide[0]._outpostStation[4]._stationPos = Common::Point(119, 68);
- _gameBoardSide[0]._outpostStation[5]._stationPos = Common::Point(119, 42);
- _gameBoardSide[0]._outpostStation[6]._stationPos = Common::Point(119, 16);
- _gameBoardSide[0]._outpostStation[7]._stationPos = Common::Point(145, 16);
-
- _gameBoardSide[0]._delayCard._stationPos = Common::Point(91, 16);
-
- _gameBoardSide[0]._emptyStationPos._stationPos = Common::Point(145, 42);
-
- _gameBoardSide[0]._card1Pos = Common::Point(280, 5);
- _gameBoardSide[0]._card2Pos = Common::Point(253, 5);
- _gameBoardSide[0]._card3Pos = Common::Point(226, 5);
- _gameBoardSide[0]._card4Pos = Common::Point(199, 5);
- _gameBoardSide[0]._frameNum = 2;
-
- _gameBoardSide[1]._handCard[0]._stationPos = Common::Point(283, 146);
- _gameBoardSide[1]._handCard[1]._stationPos = Common::Point(283, 124);
- _gameBoardSide[1]._handCard[2]._stationPos = Common::Point(283, 102);
- _gameBoardSide[1]._handCard[3]._stationPos = Common::Point(283, 80);
-
- _gameBoardSide[1]._outpostStation[0]._stationPos = Common::Point(253, 122);
- _gameBoardSide[1]._outpostStation[1]._stationPos = Common::Point(227, 122);
- _gameBoardSide[1]._outpostStation[2]._stationPos = Common::Point(201, 122);
- _gameBoardSide[1]._outpostStation[3]._stationPos = Common::Point(201, 96);
- _gameBoardSide[1]._outpostStation[4]._stationPos = Common::Point(201, 70);
- _gameBoardSide[1]._outpostStation[5]._stationPos = Common::Point(227, 70);
- _gameBoardSide[1]._outpostStation[6]._stationPos = Common::Point(253, 70);
- _gameBoardSide[1]._outpostStation[7]._stationPos = Common::Point(253, 96);
-
- _gameBoardSide[1]._delayCard._stationPos = Common::Point(253, 43);
-
- _gameBoardSide[1]._emptyStationPos._stationPos = Common::Point(227, 96);
-
- _gameBoardSide[1]._card1Pos = Common::Point(283, 146);
- _gameBoardSide[1]._card2Pos = Common::Point(283, 124);
- _gameBoardSide[1]._card3Pos = Common::Point(283, 102);
- _gameBoardSide[1]._card4Pos = Common::Point(283, 80);
- _gameBoardSide[1]._frameNum = 4;
-
- subPostInit();
-
- _stockPile.postInit();
-}
-
-void Scene1337::remove() {
- if (R2_GLOBALS._v57709 > 1) {
- subD1917();
- subD1940(false);
- }
-
- R2_GLOBALS._uiElements._active = true;
- R2_GLOBALS._uiElements._visible = true;
- SceneExt::remove();
-}
-
-void Scene1337::process(Event &event) {
- if (event.eventType == EVENT_BUTTON_DOWN) {
- if (event.btnState == BTNSHIFT_RIGHT) {
- updateCursorId(R2_GLOBALS._mouseCursorId, true);
- event.handled = true;
- } else if (_delayedFunction) {
- FunctionPtrType tmpFctPtr = _delayedFunction;
- _delayedFunction = nullptr;
- (this->*tmpFctPtr)();
- event.handled = true;
- }
- } else if (event.eventType == EVENT_KEYPRESS) {
- if (event.kbd.keycode == Common::KEYCODE_SPACE) {
- if (_delayedFunction) {
- FunctionPtrType tmpFctPtr = _delayedFunction;
- _delayedFunction = nullptr;
- (this->*tmpFctPtr)();
- event.handled = true;
- }
- } else
- warning("Fixme: Find proper keycode value");
- }
-
- if (!event.handled)
- Scene::process(event);
-}
-
-void Scene1337::dispatch() {
- if (!_instructionsDisplayedFl) {
- ++_instructionsWaitCount;
- if (_instructionsWaitCount == 4) {
- _instructionsDisplayedFl = true;
- suggestInstructions();
- }
- }
-
- // The following code is in the original in sceneHandler::process(),
- // which is terrible as it's checked in every scene of the game.
- setCursorData(5, _cursorCurStrip, _cursorCurFrame);
- //
-
- Scene::dispatch();
-}
-
-void Scene1337::actionDisplay(int resNum, int lineNum, int x, int y, int keepOnScreen, int width, int textMode, int fontNum, int colFG, int colBGExt, int colFGExt) {
- // TODO: Check if it's normal that arg5 is unused and replaced by an hardcoded 0 value
- // May hide an original bug
-
- SceneItem::display(resNum, lineNum, SET_X, x, SET_Y, y, SET_KEEP_ONSCREEN, 0,
- SET_WIDTH, width, SET_POS_MODE, -1, SET_TEXT_MODE, textMode,
- SET_FONT, fontNum, SET_FG_COLOR, colFG, SET_EXT_BGCOLOR, colBGExt,
- SET_EXT_FGCOLOR, colFGExt, LIST_END);
-}
-
-void Scene1337::setAnimationInfo(Card *card) {
- if (!card)
- return;
-
- if (card->_cardId > 25) {
- card->_card.setStrip2(4);
- card->_card.setFrame(card->_cardId - 25);
- } else if (card->_cardId > 9) {
- card->_card.setStrip2(3);
- card->_card.setFrame(card->_cardId - 9);
- } else {
- card->_card.setStrip2(2);
- card->_card.setFrame(card->_cardId);
- }
-
- card->_card.show();
- R2_GLOBALS._sceneObjects->draw();
-}
-
-void Scene1337::handleNextTurn() {
- switch (_winnerId) {
- case -1:
- ++_currentPlayerNumb;
- if (_currentPlayerNumb > 3)
- _currentPlayerNumb = 0;
-
- if (_showPlayerTurn) {
- _currentPlayerArrow.show();
- switch (_currentPlayerNumb) {
- case 0:
- _currentPlayerArrow.setStrip(3);
- break;
- case 1:
- _currentPlayerArrow.setStrip(4);
- break;
- case 2:
- subD1975(174, 107);
- _currentPlayerArrow.setStrip(1);
- break;
- case 3:
- subC4CEC();
- _currentPlayerArrow.setStrip(2);
- break;
- default:
- break;
- }
-
- if (!_autoplay)
- _delayedFunction = &Scene1337::handlePlayerTurn;
- else
- handlePlayerTurn();
- } else {
- handlePlayerTurn();
- }
- break;
- case 0:
- _aSound2.play(62);
- actionDisplay(1330, 135, 159, 10, 1, 200, 0, 7, 0, 154, 154);
- actionDisplay(1330, 121, 20, 99, 1, 136, 0, 7, 0, 172, 172);
- actionDisplay(1330, 122, 300, 99, 1, 136, 0, 7, 0, 117, 117);
- R2_GLOBALS._sceneObjects->draw();
- actionDisplay(1330, 123, 159, 134, 1, 200, 0, 7, 0, 105, 105);
- break;
- case 1:
- _aSound2.play(62);
- actionDisplay(1330, 151, 300, 99, 1, 136, 0, 7, 0, 117, 117);
- actionDisplay(1330, 118, 20, 99, 1, 136, 0, 7, 0, 172, 172);
- actionDisplay(1330, 119, 159, 10, 1, 200, 0, 7, 0, 154, 154);
- R2_GLOBALS._sceneObjects->draw();
- actionDisplay(1330, 120, 159, 134, 1, 200, 0, 7, 0, 105, 105);
- break;
- case 2:
- _aSound2.play(62);
- actionDisplay(1330, 134, 159, 134, 1, 200, 0, 7, 0, 105, 105);
- actionDisplay(1330, 124, 20, 99, 1, 136, 0, 7, 0, 172, 172);
- actionDisplay(1330, 126, 159, 10, 1, 200, 0, 7, 0, 154, 154);
- R2_GLOBALS._sceneObjects->draw();
- actionDisplay(1330, 125, 300, 99, 1, 136, 0, 7, 0, 117, 117);
- break;
- case 3:
- _aSound2.play(62);
- actionDisplay(1330, 150, 20, 99, 1, 136, 0, 7, 0, 172, 172);
- actionDisplay(1330, 115, 300, 99, 1, 136, 0, 7, 0, 117, 117);
- actionDisplay(1330, 116, 159, 10, 1, 200, 0, 7, 0, 154, 154);
- R2_GLOBALS._sceneObjects->draw();
- actionDisplay(1330, 117, 159, 134, 1, 200, 0, 7, 0, 105, 105);
- break;
- default:
- break;
- }
-
- if (_winnerId != -1)
- R2_GLOBALS._sceneManager.changeScene(125);
-
-}
-
-void Scene1337::handlePlayerTurn() {
- if (_showPlayerTurn)
- _currentPlayerArrow.hide();
-
- switch (_currentPlayerNumb) {
- case 2:
- subC4CD2();
- if (_displayHelpFl)
- actionDisplay(1330, 114, 159, 10, 1, 200, 0, 7, 0, 154, 154);
- _displayHelpFl = false;
- // No break on purpose
- case 0:
- // No break on purpose
- case 1:
- // No break on purpose
- case 3:
- _actionItem.setAction(&_action4);
- default:
- break;
- }
-
- _showPlayerTurn = true;
-
-}
-
-bool Scene1337::isStationCard(int cardId) {
- switch (cardId) {
- case 10:
- // No break on purpose
- case 12:
- // No break on purpose
- case 15:
- // No break on purpose
- case 17:
- // No break on purpose
- case 18:
- // No break on purpose
- case 19:
- // No break on purpose
- case 20:
- // No break on purpose
- case 21:
- return true;
- default:
- return false;
- }
-}
-
-bool Scene1337::isStopConstructionCard(int cardId) {
- switch (cardId) {
- case 11:
- // No break on purpose
- case 14:
- // No break on purpose
- case 16:
- // No break on purpose
- case 24:
- return true;
- default:
- return false;
- }
-}
-
-int Scene1337::getStationId(int playerId, int handCardId) {
- if ((_gameBoardSide[playerId]._handCard[handCardId]._cardId > 1) && (_gameBoardSide[playerId]._handCard[handCardId]._cardId <= 9))
- return handCardId;
-
- return -1;
-}
-
-int Scene1337::findPlatformCardInHand(int playerId) {
- for (int i = 0; i <= 3; i++) {
- if (_gameBoardSide[playerId]._handCard[i]._cardId == 1)
- return i;
- }
-
- return -1;
-}
-
-int Scene1337::findCard13InHand(int playerId) {
- for (int i = 0; i <= 3; i++) {
- if (_gameBoardSide[playerId]._handCard[i]._cardId == 13)
- return i;
- }
-
- return -1;
-}
-
-int Scene1337::checkThieftCard(int playerId) {
- for (int i = 0; i <= 3; i++) {
- if (_gameBoardSide[playerId]._handCard[i]._cardId == 25)
- return i;
- }
-
- return -1;
-}
-
-int Scene1337::isDelayCard(int cardId) {
- switch (cardId) {
- case 11:
- // No break on purpose
- case 14:
- // No break on purpose
- case 16:
- // No break on purpose
- case 24:
- return cardId;
- break;
- default:
- return -1;
- break;
- }
-}
-
-int Scene1337::getStationCardId(int cardId) {
- switch (cardId) {
- case 10:
- // No break on purpose
- case 12:
- // No break on purpose
- case 15:
- // No break on purpose
- case 17:
- // No break on purpose
- case 18:
- // No break on purpose
- case 19:
- // No break on purpose
- case 20:
- // No break on purpose
- case 21:
- return cardId;
- default:
- return -1;
- }
-}
-
-void Scene1337::handlePlayer01Discard(int playerId) {
- switch (playerId) {
- case 0:
- for (int i = 0; i <= 3; i++) {
- if (getStationCardId(_gameBoardSide[playerId]._handCard[i]._cardId) != -1) {
- discardCard(&_gameBoardSide[playerId]._handCard[i]);
- return;
- }
- }
-
- for (int i = 0; i <= 3; i++) {
- if (isDelayCard(_gameBoardSide[playerId]._handCard[i]._cardId) != -1) {
- discardCard(&_gameBoardSide[playerId]._handCard[i]);
- return;
- }
- }
-
- for (int i = 0; i <= 3; i++) {
- if ((_gameBoardSide[playerId]._handCard[i]._cardId > 1) && (_gameBoardSide[playerId]._handCard[i]._cardId <= 9)) {
- discardCard(&_gameBoardSide[playerId]._handCard[i]);
- return;
- }
- }
-
- for (int i = 0; i <= 3; i++) {
- if ((_gameBoardSide[playerId]._handCard[i]._cardId >= 26) && (_gameBoardSide[playerId]._handCard[i]._cardId <= 33)) {
- discardCard(&_gameBoardSide[playerId]._handCard[i]);
- return;
- }
- }
-
- for (int i = 0; i <= 3; i++) {
- if (_gameBoardSide[playerId]._handCard[i]._cardId == 1) {
- discardCard(&_gameBoardSide[playerId]._handCard[i]);
- return;
- }
- }
-
- for (int i = 0; i <= 3; i++) {
- if (_gameBoardSide[playerId]._handCard[i]._cardId == 25) {
- discardCard(&_gameBoardSide[playerId]._handCard[i]);
- return;
- }
- }
-
- for (int i = 0; i <= 3; i++) {
- if (_gameBoardSide[playerId]._handCard[i]._cardId == 13) {
- discardCard(&_gameBoardSide[playerId]._handCard[i]);
- return;
- }
- }
- break;
- case 1:
- for (int i = 0; i <= 3; i++) {
- if ((_gameBoardSide[playerId]._handCard[i]._cardId >= 26) && (_gameBoardSide[playerId]._handCard[i]._cardId <= 33)) {
- discardCard(&_gameBoardSide[playerId]._handCard[i]);
- return;
- }
- }
-
- for (int i = 0; i <= 3; i++) {
- if (_gameBoardSide[playerId]._handCard[i]._cardId == 1) {
- discardCard(&_gameBoardSide[playerId]._handCard[i]);
- return;
- }
- }
-
- for (int i = 0; i <= 3; i++) {
- if ((_gameBoardSide[playerId]._handCard[i]._cardId > 1) && (_gameBoardSide[playerId]._handCard[i]._cardId <= 9)) {
- discardCard(&_gameBoardSide[playerId]._handCard[i]);
- return;
- }
- }
-
- for (int i = 0; i <= 3; i++) {
- if (getStationCardId(_gameBoardSide[playerId]._handCard[i]._cardId) != -1) {
- discardCard(&_gameBoardSide[playerId]._handCard[i]);
- return;
- }
- }
-
- for (int i = 0; i <= 3; i++) {
- if (isDelayCard(_gameBoardSide[playerId]._handCard[i]._cardId) != -1) {
- discardCard(&_gameBoardSide[playerId]._handCard[i]);
- return;
- }
- }
-
- for (int i = 0; i <= 3; i++) {
- if (_gameBoardSide[playerId]._handCard[i]._cardId == 25) {
- discardCard(&_gameBoardSide[playerId]._handCard[i]);
- return;
- }
- }
-
- for (int i = 0; i <= 3; i++) {
- if (_gameBoardSide[playerId]._handCard[i]._cardId == 13) {
- discardCard(&_gameBoardSide[playerId]._handCard[i]);
- return;
- }
- }
-
- break;
- default:
- break;
- }
-}
-
-void Scene1337::playThieftCard(int playerId, Card *card, int victimId) {
- _actionIdx1 = playerId;
- _actionIdx2 = victimId;
-
- int randIndx;
-
- for (;;) {
- randIndx = R2_GLOBALS._randomSource.getRandomNumber(3);
- if (_gameBoardSide[victimId]._handCard[randIndx]._cardId != 0)
- break;
- }
-
- _actionCard1 = card;
- _actionCard2 = &_gameBoardSide[victimId]._emptyStationPos;
- _actionCard3 = &_gameBoardSide[victimId]._handCard[randIndx];
-
- _actionItem.setAction(&_action11);
-}
-
-int Scene1337::getPreventionCardId(int cardId) {
- int retVal;
-
- switch (cardId) {
- case 10:
- retVal = 2;
- break;
- case 12:
- retVal = 3;
- break;
- case 15:
- retVal = 5;
- break;
- case 17:
- retVal = 9;
- break;
- case 18:
- retVal = 6;
- break;
- case 19:
- retVal = 4;
- break;
- case 20:
- retVal = 8;
- break;
- case 21:
- retVal = 7;
- break;
- default:
- retVal = -1;
- }
-
- return retVal;
-}
-
-bool Scene1337::isAttackPossible(int victimId, int cardId) {
- if (victimId < 0 || victimId >= ARRAYSIZE(_gameBoardSide))
- error("Scene1337::isAttackPossible() victimId:%d out of range 0 to %d", victimId, ARRAYSIZE(_gameBoardSide)-1);
-
- for (int i = 0; i <= 7; i++) {
- if (_gameBoardSide[victimId]._outpostStation[i]._cardId != 0) {
- if (getPreventionCardId(cardId) == _gameBoardSide[victimId]._outpostStation[i]._cardId)
- return false;
- }
- }
- return true;
-}
-
-int Scene1337::getPlayerWithOutpost(int playerId) {
- int randPlayerId = R2_GLOBALS._randomSource.getRandomNumber(3);
-
- for (int i = 0; i <= 3; i++) {
- if (randPlayerId != playerId) {
- for (int j = 0; j <= 7; j++) {
- if (_gameBoardSide[randPlayerId]._outpostStation[j]._cardId != 0)
- return randPlayerId;
- }
- }
-
- if (playerId == 1) {
- randPlayerId--;
- if (randPlayerId < 0)
- randPlayerId = 3;
- } else {
- ++randPlayerId;
- if (randPlayerId > 3)
- randPlayerId = 0;
- }
- }
-
- return -1;
-}
-
-bool Scene1337::checkAntiDelayCard(int delayCardId, int cardId) {
- if ((delayCardId == 11) && (cardId == 26))
- return true;
-
- if ((delayCardId == 14) && (cardId == 30))
- return true;
-
- if ((delayCardId == 16) && (cardId == 32))
- return true;
-
- if ((delayCardId == 24) && (cardId == 28))
- return true;
-
- return false;
-}
-
-void Scene1337::playStationCard(Card *station, Card *platform) {
- _actionCard1 = station;
- _actionCard2 = platform;
- _actionItem.setAction(&_action7);
-}
-
-int Scene1337::getFreeHandCard(int playerId) {
- if ( (_gameBoardSide[playerId]._handCard[0]._cardId == 0)
- && (_gameBoardSide[playerId]._handCard[1]._cardId == 0)
- && (_gameBoardSide[playerId]._handCard[2]._cardId == 0)
- && (_gameBoardSide[playerId]._handCard[3]._cardId == 0))
- return -1;
-
- int randIndx;
- for (;;) {
- randIndx = R2_GLOBALS._randomSource.getRandomNumber(3);
- if (_gameBoardSide[playerId]._handCard[randIndx]._cardId == 0)
- break;
- }
-
- return randIndx;
-}
-
-void Scene1337::playPlatformCard(Card *card, Card *dest) {
- _actionCard1 = card;
- _actionCard2 = dest;
-
- _actionItem.setAction(&_action6);
-}
-
-void Scene1337::playDelayCard(Card *card, Card *dest) {
- _actionCard1 = card;
- _actionCard2 = dest;
-
- _actionItem.setAction(&_action9);
-}
-
-void Scene1337::playAntiDelayCard(Card *card, Card *dest) {
- _actionCard1 = card;
- _actionCard2 = dest;
-
- _actionItem.setAction(&_action8);
-
- handleNextTurn();
-}
-
-
-Scene1337::Card *Scene1337::getStationCard(int playerId) {
- for (int i = 0; i <= 7; i++) {
- if ((_gameBoardSide[playerId]._outpostStation[i]._cardId >= 1) && (_gameBoardSide[playerId]._outpostStation[i]._cardId <= 9))
- return &_gameBoardSide[playerId]._outpostStation[i];
- }
-
- return nullptr;
-}
-
-void Scene1337::playCounterTrickCard(Card *card, int playerId) {
- _actionCard1 = card;
- _actionCard2 = getStationCard(playerId);
- _actionCard3 = &_gameBoardSide[playerId]._emptyStationPos;
- _actionIdx1 = playerId;
- _actionItem.setAction(&_action10);
- handleNextTurn();
-}
-
-void Scene1337::discardCard(Card *card) {
- _actionCard1 = card;
-
- _actionItem.setAction(&_action5);
-}
-
-void Scene1337::subC4CD2() {
- if (R2_GLOBALS._v57709 > 0) {
- subD1917();
- subD1940(false); // _v5780C--
- }
-}
-
-void Scene1337::subC4CEC() {
- if (R2_GLOBALS._v57709 == 0) {
- subD18F5();
- subD1940(true); // _v5780C++
- }
-}
-
-void Scene1337::subC51A0(Card *subObj1, Card *subObj2) {
- _actionCard1 = subObj1;
- _actionCard2 = subObj2;
-
- _actionItem.setAction(&_action13);
-}
-
-void Scene1337::displayDialog(int dialogNumb) {
- switch (dialogNumb - 1) {
- case 0:
- actionDisplay(1330, 53, 159, 10, 1, 200, 0, 7, 0, 154, 154);
- break;
- case 1:
- actionDisplay(1330, 57, 159, 10, 1, 200, 0, 7, 0, 154, 154);
- break;
- case 2:
- actionDisplay(1330, 58, 159, 10, 1, 200, 0, 7, 0, 154, 154);
- break;
- case 3:
- actionDisplay(1330, 59, 159, 10, 1, 200, 0, 7, 0, 154, 154);
- break;
- case 4:
- actionDisplay(1330, 60, 159, 10, 1, 200, 0, 7, 0, 154, 154);
- break;
- case 5:
- actionDisplay(1330, 61, 159, 10, 1, 200, 0, 7, 0, 154, 154);
- break;
- case 6:
- actionDisplay(1330, 62, 159, 10, 1, 200, 0, 7, 0, 154, 154);
- break;
- case 7:
- actionDisplay(1330, 63, 159, 10, 1, 200, 0, 7, 0, 154, 154);
- break;
- case 8:
- actionDisplay(1330, 64, 159, 10, 1, 200, 0, 7, 0, 154, 154);
- break;
- case 9:
- actionDisplay(1330, 65, 159, 10, 1, 200, 0, 7, 0, 154, 154);
- break;
- case 10:
- actionDisplay(1330, 67, 159, 10, 1, 200, 0, 7, 0, 154, 154);
- break;
- case 11:
- actionDisplay(1330, 69, 159, 10, 1, 200, 0, 7, 0, 154, 154);
- break;
- case 12:
- actionDisplay(1330, 71, 159, 10, 1, 200, 0, 7, 0, 154, 154);
- actionDisplay(1330, 72, 159, 10, 1, 200, 0, 7, 0, 154, 154);
- actionDisplay(1330, 73, 159, 10, 1, 200, 0, 7, 0, 154, 154);
- break;
- case 13:
- actionDisplay(1330, 79, 159, 10, 1, 200, 0, 7, 0, 154, 154);
- break;
- case 14:
- actionDisplay(1330, 81, 159, 10, 1, 200, 0, 7, 0, 154, 154);
- break;
- case 15:
- actionDisplay(1330, 83, 159, 10, 1, 200, 0, 7, 0, 154, 154);
- break;
- case 16:
- actionDisplay(1330, 85, 159, 10, 1, 200, 0, 7, 0, 154, 154);
- break;
- case 17:
- actionDisplay(1330, 87, 159, 10, 1, 200, 0, 7, 0, 154, 154);
- break;
- case 18:
- actionDisplay(1330, 89, 159, 10, 1, 200, 0, 7, 0, 154, 154);
- break;
- case 19:
- actionDisplay(1330, 91, 159, 10, 1, 200, 0, 7, 0, 154, 154);
- break;
- case 20:
- actionDisplay(1330, 93, 159, 10, 1, 200, 0, 7, 0, 154, 154);
- break;
- case 23:
- actionDisplay(1330, 95, 159, 10, 1, 200, 0, 7, 0, 154, 154);
- break;
- case 24:
- actionDisplay(1330, 97, 159, 10, 1, 200, 0, 7, 0, 154, 154);
- break;
- case 25:
- actionDisplay(1330, 104, 159, 10, 1, 200, 0, 7, 0, 154, 154);
- break;
- case 26:
- actionDisplay(1330, 105, 159, 10, 1, 200, 0, 7, 0, 154, 154);
- actionDisplay(1330, 106, 159, 10, 1, 200, 0, 7, 0, 154, 154);
- break;
- case 27:
- actionDisplay(1330, 110, 159, 10, 1, 200, 0, 7, 0, 154, 154);
- break;
- case 28:
- actionDisplay(1330, 108, 159, 10, 1, 200, 0, 7, 0, 154, 154);
- actionDisplay(1330, 109, 159, 10, 1, 200, 0, 7, 0, 154, 154);
- break;
- case 29:
- actionDisplay(1330, 111, 159, 10, 1, 200, 0, 7, 0, 154, 154);
- break;
- case 31:
- actionDisplay(1330, 112, 159, 10, 1, 200, 0, 7, 0, 154, 154);
- break;
- default:
- break;
- }
-}
-
-void Scene1337::subPostInit() {
- R2_GLOBALS._v57709 = 0;
- R2_GLOBALS._v5780C = 0;
- updateCursorId(1, false);
- subD1940(true); // _v5780C++
- subD18F5();
-
-// loadScene(1330);
-// SceneExt::postInit();
-
- R2_GLOBALS._scenePalette.addRotation(224, 235, 1);
-
- _availableCardsPile[0] = 1;
- _availableCardsPile[1] = 1;
- _availableCardsPile[2] = 1;
- _availableCardsPile[3] = 1;
- _availableCardsPile[4] = 1;
- _availableCardsPile[5] = 1;
- _availableCardsPile[6] = 1;
- _availableCardsPile[7] = 1;
- _availableCardsPile[8] = 26;
- _availableCardsPile[9] = 2;
- _availableCardsPile[10] = 2;
- _availableCardsPile[11] = 2;
- _availableCardsPile[12] = 2;
- _availableCardsPile[13] = 2;
- _availableCardsPile[14] = 26;
- _availableCardsPile[15] = 3;
- _availableCardsPile[16] = 3;
- _availableCardsPile[17] = 3;
- _availableCardsPile[18] = 3;
- _availableCardsPile[19] = 3;
- _availableCardsPile[20] = 28;
- _availableCardsPile[21] = 4;
- _availableCardsPile[22] = 4;
- _availableCardsPile[23] = 4;
- _availableCardsPile[24] = 4;
- _availableCardsPile[25] = 4;
- _availableCardsPile[26] = 28;
- _availableCardsPile[27] = 5;
- _availableCardsPile[28] = 5;
- _availableCardsPile[29] = 5;
- _availableCardsPile[30] = 5;
- _availableCardsPile[31] = 5;
- _availableCardsPile[32] = 30;
- _availableCardsPile[33] = 6;
- _availableCardsPile[34] = 6;
- _availableCardsPile[35] = 6;
- _availableCardsPile[36] = 6;
- _availableCardsPile[37] = 6;
- _availableCardsPile[38] = 30;
- _availableCardsPile[39] = 7;
- _availableCardsPile[40] = 7;
- _availableCardsPile[41] = 7;
- _availableCardsPile[42] = 7;
- _availableCardsPile[43] = 7;
- _availableCardsPile[44] = 32;
- _availableCardsPile[45] = 8;
- _availableCardsPile[46] = 8;
- _availableCardsPile[47] = 8;
- _availableCardsPile[48] = 8;
- _availableCardsPile[49] = 8;
- _availableCardsPile[50] = 32;
- _availableCardsPile[51] = 9;
- _availableCardsPile[52] = 9;
- _availableCardsPile[53] = 9;
- _availableCardsPile[54] = 9;
- _availableCardsPile[55] = 9;
- _availableCardsPile[56] = 10;
- _availableCardsPile[57] = 11;
- _availableCardsPile[58] = 12;
- _availableCardsPile[59] = 13;
- _availableCardsPile[60] = 13;
- _availableCardsPile[61] = 14;
- _availableCardsPile[62] = 15;
- _availableCardsPile[63] = 16;
- _availableCardsPile[64] = 17;
- _availableCardsPile[65] = 18;
- _availableCardsPile[66] = 19;
- _availableCardsPile[67] = 20;
- _availableCardsPile[68] = 21;
- _availableCardsPile[69] = 26;
- _availableCardsPile[70] = 28;
- _availableCardsPile[71] = 24;
- _availableCardsPile[72] = 25;
- _availableCardsPile[73] = 25;
- _availableCardsPile[74] = 25;
- _availableCardsPile[75] = 25;
- _availableCardsPile[76] = 26;
- _availableCardsPile[77] = 26;
- _availableCardsPile[78] = 26;
- _availableCardsPile[79] = 27;
- _availableCardsPile[80] = 27;
- _availableCardsPile[81] = 28;
- _availableCardsPile[82] = 28;
- _availableCardsPile[83] = 28;
- _availableCardsPile[84] = 29;
- _availableCardsPile[85] = 29;
- _availableCardsPile[86] = 29;
- _availableCardsPile[87] = 30;
- _availableCardsPile[88] = 30;
- _availableCardsPile[89] = 30;
- _availableCardsPile[90] = 30;
- _availableCardsPile[91] = 32;
- _availableCardsPile[92] = 1;
- _availableCardsPile[93] = 32;
- _availableCardsPile[94] = 32;
- _availableCardsPile[95] = 32;
- _availableCardsPile[96] = 1;
- _availableCardsPile[97] = 1;
- _availableCardsPile[98] = 1;
- _availableCardsPile[99] = 0;
-
- _cardsAvailableNumb = 98;
- _currentDiscardIndex = 98; // CHECKME: Would make more sense at pos 99
-
- _discardPile._cardId = 0;
- _discardPile._stationPos = Common::Point(128, 95);
-
- _stockCard._cardId = 0;
- _stockCard._stationPos = Common::Point(162, 95);
-
- _selectedCard._cardId = 0;
-
- _animatedCard._card.postInit();
- _animatedCard._card.setVisage(1332);
- _animatedCard._card.setStrip(5);
- _animatedCard._card.setFrame(1);
- _animatedCard._card._moveDiff = Common::Point(10, 10);
- _animatedCard._card.fixPriority(400);
- _animatedCard._card.setPosition(Common::Point(128, 95), 0);
- _animatedCard._card.animate(ANIM_MODE_2, NULL);
- _animatedCard._card.hide();
-
- _currentPlayerArrow.postInit();
- _currentPlayerArrow.setVisage(1334);
- _currentPlayerArrow.setStrip(1);
- _currentPlayerArrow.setFrame(1);
- _currentPlayerArrow._numFrames = 12;
- _currentPlayerArrow.fixPriority(500);
- _currentPlayerArrow.setPosition(Common::Point(174, 107), 0);
- _currentPlayerArrow.animate(ANIM_MODE_2, NULL);
- _currentPlayerArrow.hide();
-
- _showPlayerTurn = true;
- _displayHelpFl = false;
- _winnerId = -1;
-
- _helpIcon.postInit();
- _helpIcon.setup(9531, 1, 1);
- _helpIcon.setPosition(Common::Point(249, 168));
- _helpIcon.setPriority(155);
- _helpIcon._effect = EFFECT_NONE;
- _helpIcon.show();
-
- _autoplay = false;
- _instructionsDisplayedFl = false;
- _instructionsWaitCount = 0;
-}
-
-void Scene1337::suggestInstructions() {
- if (R2_GLOBALS._v57709 > 0)
- subD1917();
-
- if (MessageDialog::show(NEED_INSTRUCTIONS, NO_MSG, YES_MSG) == 0) {
- if (R2_GLOBALS._v57709 == 0)
- subD18F5();
- dealCards();
- } else {
- if (R2_GLOBALS._v57709 == 0)
- subD18F5();
- displayInstructions();
- }
-}
-
-void Scene1337::displayInstructions() {
- _actionItem.setAction(&_action1);
-}
-
-void Scene1337::shuffleCards() {
- R2_GLOBALS._sceneObjects->draw();
-
- // Remove holes in card pile
- for (int i = 0; i <= 98; i++) {
- if (_availableCardsPile[i] == 0) {
- for (int j = i + 1; j <= 98; j ++) {
- if (_availableCardsPile[j] != 0) {
- _availableCardsPile[i] = _availableCardsPile[j];
- _availableCardsPile[j] = 0;
- break;
- }
- }
- }
- }
-
- // Compute the number of available cards
- for (int i = 0; i <= 99; i ++) {
- if (_availableCardsPile[i] == 0) {
- // CHECKME: This will fail if i == 0, which shouldn't happen
- // as we don't shuffle cards when no card is available.
- _cardsAvailableNumb = i - 1;
- _currentDiscardIndex = 98; // CHECKME: Would make more sense at pos 99
- break;
- }
- }
-
- for (int i = 0; i < 2000; i ++) {
- int randIndx = R2_GLOBALS._randomSource.getRandomNumber(_cardsAvailableNumb);
- int swap = _availableCardsPile[0];
- _availableCardsPile[0] = _availableCardsPile[randIndx];
- _availableCardsPile[randIndx] = swap;
- }
-
- _shuffleEndedFl = false;
-
- // Shuffle cards
- _animatedCard._card.setAction(&_action2);
-
- while(!_shuffleEndedFl && !g_vm->shouldQuit()) {
- g_globals->_sceneObjects->recurse(SceneHandler::dispatchObject);
- g_globals->_scenePalette.signalListeners();
- R2_GLOBALS._sceneObjects->draw();
- g_globals->_events.delay(g_globals->_sceneHandler->_delayTicks);
- }
-}
-
-void Scene1337::dealCards() {
- _animatedCard._card._moveDiff = Common::Point(30, 30);
- shuffleCards();
-
- // Deal cards
- _actionItem.setAction(&_action3);
-}
-
-void Scene1337::showOptionsDialog() {
- // Display menu with "Auto Play", "New Game", "Quit" and "Continue"
- OptionsDialog::show();
-}
-
-void Scene1337::handleClick(int arg1, Common::Point pt) {
- int curReg = R2_GLOBALS._sceneRegions.indexOf(g_globals->_events._mousePos);
-
- if (arg1 == 3) {
- bool found = false;
- int i;
- for (i = 0; i <= 7; i++) {
- if ( _gameBoardSide[2]._outpostStation[i].isIn(pt)
- || _gameBoardSide[0]._outpostStation[i].isIn(pt)
- || _gameBoardSide[1]._outpostStation[i].isIn(pt)
- || _gameBoardSide[3]._outpostStation[i].isIn(pt) ) {
- found = true;
- break;
- }
- }
-
- if (found) {
- switch (curReg) {
- case 5:
- if (_gameBoardSide[2]._outpostStation[i]._cardId != 0)
- displayDialog(_gameBoardSide[2]._outpostStation[i]._cardId);
- else
- actionDisplay(1330, 20, 159, 10, 1, 200, 0, 7, 0, 154, 154);
- break;
- case 10:
- if (_gameBoardSide[3]._outpostStation[i]._cardId != 0)
- displayDialog(_gameBoardSide[3]._outpostStation[i]._cardId);
- else
- actionDisplay(1330, 22, 159, 10, 1, 200, 0, 7, 0, 154, 154);
- break;
- case 15:
- if (_gameBoardSide[0]._outpostStation[i]._cardId != 0)
- displayDialog(_gameBoardSide[0]._outpostStation[i]._cardId);
- else
- actionDisplay(1330, 21, 159, 10, 1, 200, 0, 7, 0, 154, 154);
- break;
- case 20:
- if (_gameBoardSide[1]._outpostStation[i]._cardId != 0)
- displayDialog(_gameBoardSide[1]._outpostStation[i]._cardId);
- else
- actionDisplay(1330, 23, 159, 10, 1, 200, 0, 7, 0, 154, 154);
- break;
- default:
- break;
- }
- } else if ( _gameBoardSide[2]._delayCard.isIn(pt)
- || _gameBoardSide[0]._delayCard.isIn(pt)
- || _gameBoardSide[1]._delayCard.isIn(pt)
- || _gameBoardSide[3]._delayCard.isIn(pt) ) {
- switch (curReg) {
- case 5:
- if (_gameBoardSide[2]._delayCard._cardId != 0)
- displayDialog(_gameBoardSide[2]._delayCard._cardId);
- else
- actionDisplay(1330, 10, 159, 10, 1, 200, 0, 7, 0, 154, 154);
- break;
- case 10:
- if (_gameBoardSide[3]._delayCard._cardId != 0)
- displayDialog(_gameBoardSide[3]._delayCard._cardId);
- else
- actionDisplay(1330, 16, 159, 10, 1, 200, 0, 7, 0, 154, 154);
- break;
- case 15:
- if (_gameBoardSide[0]._delayCard._cardId != 0)
- displayDialog(_gameBoardSide[0]._delayCard._cardId);
- else
- actionDisplay(1330, 13, 159, 10, 1, 200, 0, 7, 0, 154, 154);
- break;
- case 20:
- if (_gameBoardSide[1]._delayCard._cardId != 0)
- displayDialog(_gameBoardSide[1]._delayCard._cardId);
- else
- actionDisplay(1330, 18, 159, 10, 1, 200, 0, 7, 0, 154, 154);
- break;
- default:
- break;
- }
- } else if (_discardPile.isIn(pt)) {
- if (_discardPile._cardId != 0)
- displayDialog(_discardPile._cardId);
- else
- actionDisplay(1330, 7, 159, 10, 1, 200, 0, 7, 0, 154, 154);
- } else if (_helpIcon._bounds.contains(pt))
- actionDisplay(1330, 43, 159, 10, 1, 200, 0, 7, 0, 154, 154);
- else if (_stockCard.isIn(pt))
- actionDisplay(1330, 4, 159, 10, 1, 200, 0, 7, 0, 154, 154);
- else if ( (_gameBoardSide[2]._emptyStationPos.isIn(pt))
- || (_gameBoardSide[3]._emptyStationPos.isIn(pt))
- || (_gameBoardSide[0]._emptyStationPos.isIn(pt))
- || (_gameBoardSide[1]._emptyStationPos.isIn(pt)) )
- actionDisplay(1330, 32, 159, 10, 1, 200, 0, 7, 0, 154, 154);
- else if (_gameBoardSide[2]._handCard[0].isIn(pt))
- displayDialog(_gameBoardSide[2]._handCard[0]._cardId);
- else if (_gameBoardSide[2]._handCard[1].isIn(pt))
- displayDialog(_gameBoardSide[2]._handCard[1]._cardId);
- else if (_gameBoardSide[2]._handCard[2].isIn(pt))
- displayDialog(_gameBoardSide[2]._handCard[2]._cardId);
- else if (_gameBoardSide[2]._handCard[3].isIn(pt))
- displayDialog(_gameBoardSide[2]._handCard[3]._cardId);
- else if ((curReg >= 6) && (curReg <= 9))
- actionDisplay(1330, 29, 159, 10, 1, 200, 0, 7, 0, 154, 154);
- else if ((curReg >= 11) && (curReg <= 14))
- actionDisplay(1330, 31, 159, 10, 1, 200, 0, 7, 0, 154, 154);
- else if ((curReg >= 16) && (curReg <= 19))
- actionDisplay(1330, 30, 159, 10, 1, 200, 0, 7, 0, 154, 154);
- else {
- switch (curReg) {
- case 0:
- actionDisplay(1330, 2, 159, 134, 1, 200, 0, 7, 0, 105, 105);
- break;
- case 5:
- actionDisplay(1330, 25, 159, 10, 1, 200, 0, 7, 0, 154, 154);
- break;
- case 10:
- actionDisplay(1330, 27, 159, 10, 1, 200, 0, 7, 0, 154, 154);
- break;
- case 15:
- actionDisplay(1330, 26, 159, 10, 1, 200, 0, 7, 0, 154, 154);
- break;
- case 20:
- actionDisplay(1330, 28, 159, 10, 1, 200, 0, 7, 0, 154, 154);
- break;
- case 21:
- actionDisplay(1330, 24, 159, 10, 1, 200, 0, 7, 0, 154, 154);
- break;
- default:
- break;
- }
- }
- }
-
- if (arg1 != 1)
- return;
-
- for (int i = 0; i <= 7; i++) {
- if (_gameBoardSide[2]._outpostStation[i].isIn(pt)) {
- switch (_gameBoardSide[2]._outpostStation[i]._cardId) {
- case 0:
- actionDisplay(1330, 11, 159, 10, 1, 200, 0, 7, 0, 154, 154);
- break;
- case 1:
- actionDisplay(1330, 54, 159, 10, 1, 200, 0, 7, 0, 154, 154);
- break;
- default:
- actionDisplay(1330, 34, 159, 10, 1, 200, 0, 7, 0, 154, 154);
- break;
- }
- return;
- }
- if (_gameBoardSide[0]._outpostStation[i].isIn(pt)) {
- switch (_gameBoardSide[0]._outpostStation[i]._cardId) {
- case 0:
- actionDisplay(1330, 11, 159, 10, 1, 200, 0, 7, 0, 154, 154);
- break;
- default:
- actionDisplay(1330, 1, 159, 10, 1, 200, 0, 7, 0, 154, 154);
- break;
- }
- return;
- }
- if (_gameBoardSide[1]._outpostStation[i].isIn(pt)) {
- switch (_gameBoardSide[1]._outpostStation[i]._cardId) {
- case 0:
- actionDisplay(1330, 146, 300, 99, 1, 136, 0, 7, 0, 117, 117);
- break;
- default:
- actionDisplay(1330, 144, 300, 99, 1, 136, 0, 7, 0, 117, 117);
- break;
- }
- return;
- }
- if (_gameBoardSide[3]._outpostStation[i].isIn(pt)) {
- switch (_gameBoardSide[3]._outpostStation[i]._cardId) {
- case 0:
- actionDisplay(1330, 147, 20, 99, 1, 136, 0, 7, 0, 172, 172);
- break;
- default:
- actionDisplay(1330, 145, 20, 99, 1, 136, 0, 7, 0, 172, 172);
- break;
- }
- return;
- }
- }
-
- if (_gameBoardSide[2]._delayCard.isIn(pt)) {
- // The original uses _gameBoardSide[0], which is obviously a bug.
- if (_gameBoardSide[2]._delayCard._cardId != 0)
- actionDisplay(1330, 39, 159, 10, 1, 200, 0, 7, 0, 154, 154);
- else
- actionDisplay(1330, 11, 159, 10, 1, 200, 0, 7, 0, 154, 154);
-
- return;
- }
- if (_gameBoardSide[3]._delayCard.isIn(pt)) {
- if (_gameBoardSide[3]._delayCard._cardId != 0)
- actionDisplay(1330, 145, 20, 99, 1, 136, 0, 7, 0, 172, 172);
- else
- actionDisplay(1330, 147, 20, 99, 1, 136, 0, 7, 0, 172, 172);
-
- return;
- }
- if (_gameBoardSide[1]._delayCard.isIn(pt)) {
- if (_gameBoardSide[1]._delayCard._cardId != 0)
- actionDisplay(1330, 144, 300, 99, 1, 136, 0, 7, 0, 117, 117);
- else
- actionDisplay(1330, 146, 300, 99, 1, 136, 0, 7, 0, 117, 117);
-
- return;
- }
- if (_gameBoardSide[0]._delayCard.isIn(pt)) {
- if (_gameBoardSide[0]._delayCard._cardId != 0)
- actionDisplay(1330, 1, 159, 10, 1, 200, 0, 7, 0, 154, 154);
- else
- actionDisplay(1330, 11, 159, 10, 1, 200, 0, 7, 0, 154, 154);
-
- return;
- }
- if (_gameBoardSide[3]._emptyStationPos.isIn(pt)) {
- actionDisplay(1330, 147, 20, 99, 1, 136, 0, 7, 0, 172, 172);
- return;
- }
- if (_gameBoardSide[1]._emptyStationPos.isIn(pt)) {
- actionDisplay(1330, 146, 300, 99, 1, 136, 0, 7, 0, 117, 117);
- return;
- }
- if (_gameBoardSide[0]._emptyStationPos.isIn(pt)) {
- actionDisplay(1330, 11, 159, 10, 1, 200, 0, 7, 0, 154, 154);
- return;
- }
-
- if (_helpIcon._bounds.contains(pt)) {
- showOptionsDialog();
- return;
- }
-
- if (_discardPile.isIn(pt))
- actionDisplay(1330, 9, 159, 10, 1, 200, 0, 7, 0, 154, 154);
- else if (_stockCard.isIn(pt))
- actionDisplay(1330, 5, 159, 10, 1, 200, 0, 7, 0, 154, 154);
- else {
- switch (curReg) {
- case 0:
- actionDisplay(1330, 3, 159, 10, 1, 200, 0, 7, 0, 154, 154);
- break;
- case 6:
- // no break on purpose
- case 7:
- // no break on purpose
- case 8:
- // no break on purpose
- case 9:
- actionDisplay(1330, 145, 20, 99, 1, 136, 0, 7, 0, 172, 172);
- break;
- case 10:
- actionDisplay(1330, 147, 20, 99, 1, 136, 0, 7, 0, 172, 172);
- break;
- case 11:
- // no break on purpose
- case 12:
- // no break on purpose
- case 13:
- // no break on purpose
- case 14:
- actionDisplay(1330, 1, 159, 10, 1, 200, 0, 7, 0, 154, 154);
- break;
- case 16:
- // no break on purpose
- case 17:
- // no break on purpose
- case 18:
- // no break on purpose
- case 19:
- actionDisplay(1330, 144, 300, 99, 1, 136, 0, 7, 0, 117, 117);
- break;
- case 20:
- actionDisplay(1330, 146, 300, 99, 1, 136, 0, 7, 0, 117, 117);
- break;
- default:
- actionDisplay(1330, 11, 159, 10, 1, 200, 0, 7, 0, 154, 154);
- break;
- }
- }
-}
-
-void Scene1337::handlePlayer0() {
- if (_gameBoardSide[0]._delayCard._cardId != 0) {
- switch (_gameBoardSide[0]._delayCard._cardId) {
- case 10:
- //No break on purpose
- case 12:
- //No break on purpose
- case 15:
- //No break on purpose
- case 17:
- //No break on purpose
- case 18:
- //No break on purpose
- case 19:
- //No break on purpose
- case 20:
- //No break on purpose
- case 21:
- discardCard(&_gameBoardSide[0]._delayCard);
- break;
- default:
- for (int i = 0; i <= 3; i++) {
- if (checkAntiDelayCard(_gameBoardSide[0]._delayCard._cardId, _gameBoardSide[0]._handCard[i]._cardId)) {
- playAntiDelayCard(&_gameBoardSide[0]._handCard[i], &_gameBoardSide[0]._delayCard);
- return;
- }
- }
-
- break;
- }
- }
-
- for (int i = 0; i <= 3; i++) {
- int tmpVal = getStationId(0, i);
-
- if (tmpVal != -1) {
- bool stationAlreadyPresentFl = false;
- for (int j = 0; j <= 7; j++) {
- if (_gameBoardSide[0]._outpostStation[j]._cardId == _gameBoardSide[0]._handCard[tmpVal]._cardId) {
- stationAlreadyPresentFl = true;
- break;
- }
- }
-
- if (!stationAlreadyPresentFl) {
- for (int j = 0; j <= 7; j++) {
- if ((_gameBoardSide[0]._outpostStation[j]._cardId == 1) && !isStopConstructionCard(_gameBoardSide[0]._delayCard._cardId)) {
- int stationCount = 0;
- for (int k = 0; k <= 7; k++) {
- if ((_gameBoardSide[0]._outpostStation[k]._cardId > 1) && (_gameBoardSide[0]._outpostStation[k]._cardId <= 9)) {
- ++stationCount;
- }
- }
-
- if (stationCount == 7)
- _winnerId = 0;
-
- playStationCard(&_gameBoardSide[0]._handCard[tmpVal], &_gameBoardSide[0]._outpostStation[j]);
- return;
- }
- }
- }
- }
- }
-
- int tmpVal = findPlatformCardInHand(0);
-
- if (tmpVal != -1) {
- for (int i = 0; i <= 7; i++) {
- if ((_gameBoardSide[0]._outpostStation[i]._cardId == 0) && !isStopConstructionCard(_gameBoardSide[0]._delayCard._cardId)) {
- playPlatformCard(&_gameBoardSide[0]._handCard[tmpVal], &_gameBoardSide[0]._outpostStation[i]);
- return;
- }
- }
- }
-
- int card13Id = findCard13InHand(0);
- if (card13Id != -1) {
- for (int i = 0; i <= 7; i++) {
- if (_gameBoardSide[2]._outpostStation[i]._cardId != 0) {
- playCounterTrickCard(&_gameBoardSide[0]._handCard[card13Id], 2);
- return;
- }
- }
- }
-
- int thieftId = checkThieftCard(0);
- if (thieftId != -1) {
- if ( (_gameBoardSide[2]._handCard[0]._cardId != 0)
- || (_gameBoardSide[2]._handCard[1]._cardId != 0)
- || (_gameBoardSide[2]._handCard[2]._cardId != 0)
- || (_gameBoardSide[2]._handCard[3]._cardId != 0) ) {
- playThieftCard(0, &_gameBoardSide[0]._handCard[thieftId], 2);
- return;
- }
- }
-
- for (int i = 0; i <= 3; i++) {
- if ((isDelayCard(_gameBoardSide[0]._handCard[i]._cardId) != -1)
- && (_gameBoardSide[2]._delayCard._cardId == 0)
- && isAttackPossible(2, _gameBoardSide[0]._handCard[i]._cardId)) {
- playDelayCard(&_gameBoardSide[0]._handCard[i], &_gameBoardSide[2]._delayCard);
- return;
- }
- }
-
- for (int i = 0; i <= 3; i++) {
- if ((getStationCardId(_gameBoardSide[0]._handCard[i]._cardId) != -1)
- && (_gameBoardSide[2]._delayCard._cardId == 0)
- && isAttackPossible(2, _gameBoardSide[0]._handCard[i]._cardId)) {
- playDelayCard(&_gameBoardSide[0]._handCard[i], &_gameBoardSide[2]._delayCard);
- return;
- }
- }
-
- card13Id = findCard13InHand(0);
- int victimPlayerId = getPlayerWithOutpost(0);
-
- if ((card13Id != -1) && (victimPlayerId != -1)) {
- playCounterTrickCard(&_gameBoardSide[0]._handCard[card13Id], victimPlayerId);
- return;
- }
-
- thieftId = checkThieftCard(0);
- if (thieftId != -1) {
- if ( (_gameBoardSide[1]._handCard[0]._cardId != 0)
- || (_gameBoardSide[1]._handCard[1]._cardId != 0)
- || (_gameBoardSide[1]._handCard[2]._cardId != 0)
- || (_gameBoardSide[1]._handCard[3]._cardId != 0) ) {
- playThieftCard(0, &_gameBoardSide[0]._handCard[thieftId], 1);
- return;
- }
- }
-
- for (int i = 0; i <= 3; i++) {
- if (getStationCardId(_gameBoardSide[0]._handCard[i]._cardId) != -1) {
- if ((_gameBoardSide[1]._delayCard._cardId == 0) && isAttackPossible(1, _gameBoardSide[0]._handCard[i]._cardId)) {
- playDelayCard(&_gameBoardSide[0]._handCard[i], &_gameBoardSide[1]._delayCard);
- return;
- }
-
- if ((_gameBoardSide[3]._delayCard._cardId == 0) && isAttackPossible(3, _gameBoardSide[0]._handCard[i]._cardId)) {
- playDelayCard(&_gameBoardSide[0]._handCard[i], &_gameBoardSide[3]._delayCard);
- return;
- }
- }
- }
-
- for (int i = 0; i <= 3; i++) {
- tmpVal = isDelayCard(_gameBoardSide[0]._handCard[i]._cardId);
- if (tmpVal != -1) {
- if ((_gameBoardSide[1]._delayCard._cardId == 0) && isAttackPossible(1, _gameBoardSide[0]._handCard[i]._cardId)) {
- playDelayCard(&_gameBoardSide[0]._handCard[i], &_gameBoardSide[1]._delayCard);
- return;
- }
-
- if ((_gameBoardSide[3]._delayCard._cardId == 0) && isAttackPossible(3, _gameBoardSide[0]._handCard[i]._cardId)) {
- playDelayCard(&_gameBoardSide[0]._handCard[i], &_gameBoardSide[3]._delayCard);
- return;
- }
- }
- }
-
- handlePlayer01Discard(0);
-}
-
-void Scene1337::handlePlayer1() {
- if (this->_gameBoardSide[1]._delayCard._cardId != 0) {
- switch (_gameBoardSide[1]._delayCard._cardId) {
- case 10:
- // No break on purpose
- case 12:
- // No break on purpose
- case 15:
- // No break on purpose
- case 17:
- // No break on purpose
- case 18:
- // No break on purpose
- case 19:
- // No break on purpose
- case 20:
- // No break on purpose
- case 21:
- discardCard(&_gameBoardSide[1]._delayCard);
- return;
- default:
- for (int i = 0; i <= 3; i++) {
- if (checkAntiDelayCard(_gameBoardSide[1]._delayCard._cardId, _gameBoardSide[1]._handCard[i]._cardId)) {
- playAntiDelayCard(&_gameBoardSide[1]._handCard[i], &_gameBoardSide[1]._delayCard);
- return;
- }
- }
- break;
- }
- }
-
- for (int i = 0; i <= 3; i++) {
- int tmpIndx = getStationId(1, i);
- if (tmpIndx == -1)
- break;
-
- int tmpVal = 0;
- for (int j = 0; j <= 7; j++) {
- if (_gameBoardSide[1]._outpostStation[j]._cardId == _gameBoardSide[1]._handCard[tmpIndx]._cardId) {
- tmpVal = 1;
- break;
- }
- }
-
- if (tmpVal == 0)
- break;
-
- for (int j = 0; j <= 7; j++) {
- if ((_gameBoardSide[1]._outpostStation[j]._cardId == 1) && !isStopConstructionCard(_gameBoardSide[1]._delayCard._cardId)) {
- int stationCount = 0;
- for (int k = 0; k <= 7; k++) {
- if ((_gameBoardSide[1]._outpostStation[k]._cardId > 1) && (_gameBoardSide[1]._outpostStation[k]._cardId <= 9))
- ++stationCount;
- }
-
- if (stationCount == 7)
- _winnerId = 1;
-
- playStationCard(&_gameBoardSide[1]._handCard[tmpIndx], &_gameBoardSide[1]._outpostStation[j]);
- return;
- }
- }
- }
-
- int normalCardId = findPlatformCardInHand(1);
- if (normalCardId != -1) {
- for (int i = 0; i <= 7; i++) {
- if ((_gameBoardSide[1]._outpostStation[i]._cardId == 0) && !isStopConstructionCard(_gameBoardSide[1]._delayCard._cardId)) {
- playPlatformCard(&_gameBoardSide[1]._handCard[normalCardId], &_gameBoardSide[1]._outpostStation[i]);
- return;
- }
- }
- }
-
- int card13Id = findCard13InHand(1);
- int tmpVal2 = getPlayerWithOutpost(1);
-
- if ((card13Id != -1) && (tmpVal2 != -1)) {
- playCounterTrickCard(&_gameBoardSide[1]._handCard[card13Id], tmpVal2);
- return;
- }
-
- int thieftId = checkThieftCard(1);
- if (thieftId != -1) {
- int playerIdFound = -1;
- int rndVal = R2_GLOBALS._randomSource.getRandomNumber(3);
- for (int i = 0; i <= 3; i++) {
- if (rndVal != 1) {
- if ( (_gameBoardSide[rndVal]._handCard[0]._cardId != 0)
- || (_gameBoardSide[rndVal]._handCard[1]._cardId != 0)
- || (_gameBoardSide[rndVal]._handCard[2]._cardId != 0)
- || (_gameBoardSide[rndVal]._handCard[3]._cardId == 0)) {
- playerIdFound = rndVal;
- break;
- }
- }
- // The original was only updating in the rndVal block,
- // which was a bug as the checks were stopping at this point
- rndVal--;
- if (rndVal < 0)
- rndVal = 3;
- }
-
- if (playerIdFound != -1) {
- playThieftCard(1, &_gameBoardSide[1]._handCard[thieftId], playerIdFound);
- return;
- }
- }
-
- int count = -1;
- int i;
- for (i = 0; i <= 3; i++) {
- int tmpVal = isDelayCard(_gameBoardSide[1]._handCard[i]._cardId);
- if (tmpVal != -1) {
- int rndVal = R2_GLOBALS._randomSource.getRandomNumber(3);
-
- for (int j = 0; j <= 3; j++) {
- //CHECKME: tmpVal or rndVal?
- // FIXME: This is probably meant to be rndVal, but not clear...
- if (tmpVal < 0 || tmpVal >= ARRAYSIZE(_gameBoardSide))
- error("Scene1337::handlePlayer1() tmpVal:%d out of range 0 to %d", tmpVal, ARRAYSIZE(_gameBoardSide)-1);
-
- if (tmpVal != 1) {
- if ((_gameBoardSide[tmpVal]._delayCard._cardId == 0) && isAttackPossible(tmpVal, _gameBoardSide[1]._handCard[i]._cardId))
- count = tmpVal;
- }
-
- if (count < 0 || count >= ARRAYSIZE(_gameBoardSide))
- error("Scene1337::handlePlayer1() count:%d out of range 0 to %d", count, ARRAYSIZE(_gameBoardSide)-1);
-
- if (count != -1) {
- playDelayCard(&_gameBoardSide[1]._handCard[i], &_gameBoardSide[count]._delayCard);
- return;
- } else {
- rndVal--;
- if (rndVal < 0)
- rndVal = 3;
- }
- }
- }
- }
-
- int j;
- for (j = 0; j <= 3; j++) {
- if (getStationCardId(_gameBoardSide[1]._handCard[j]._cardId) != -1) {
- count = -1;
- int rndVal = R2_GLOBALS._randomSource.getRandomNumber(3);
- for (int l = 0; l <= 3; l++) {
- if (rndVal != 1) {
- if ((_gameBoardSide[rndVal]._delayCard._cardId == 0) && (_gameBoardSide[1]._handCard[j]._cardId == 1))
- count = rndVal;
- }
- if (count != -1) {
- playDelayCard(&_gameBoardSide[1]._handCard[j], &_gameBoardSide[count]._delayCard);
- return;
- } else {
- rndVal--;
- if (rndVal < 0)
- rndVal = 3;
- }
- }
- }
- }
-
- handlePlayer01Discard(1);
-}
-
-void Scene1337::handlePlayer3() {
- if (_gameBoardSide[3]._delayCard._cardId != 0) {
- switch (_gameBoardSide[3]._delayCard._cardId) {
- case 10:
- // No break on purpose
- case 12:
- // No break on purpose
- case 15:
- // No break on purpose
- case 17:
- // No break on purpose
- case 18:
- // No break on purpose
- case 19:
- // No break on purpose
- case 20:
- // No break on purpose
- case 21:
- discardCard(&_gameBoardSide[3]._delayCard);
- return;
- default:
- for (int i = 0; i <= 3; i++) {
- if (checkAntiDelayCard(_gameBoardSide[3]._delayCard._cardId, _gameBoardSide[3]._handCard[i]._cardId)) {
- playAntiDelayCard(&_gameBoardSide[3]._handCard[i], &_gameBoardSide[3]._delayCard);
- return;
- }
- }
- break;
- }
- }
-
- int randIndx = R2_GLOBALS._randomSource.getRandomNumber(3);
-
- if (_gameBoardSide[3]._handCard[randIndx]._cardId == 1) {
- for (int i = 0; i <= 7; i++) {
- if ((_gameBoardSide[3]._outpostStation[i]._cardId == 0) && !isStopConstructionCard(_gameBoardSide[3]._delayCard._cardId)) {
- playPlatformCard(&_gameBoardSide[3]._handCard[randIndx], &_gameBoardSide[3]._outpostStation[i]);
- return;
- }
- }
- } else if (_gameBoardSide[3]._handCard[randIndx]._cardId <= 9) {
- for (int i = 0; i <= 7; i++) {
- if (_gameBoardSide[3]._outpostStation[i]._cardId == _gameBoardSide[3]._handCard[randIndx]._cardId) {
- discardCard(&_gameBoardSide[3]._handCard[randIndx]);
- return;
- }
- }
-
- for (int i = 0; i <= 7; i++) {
- if ((_gameBoardSide[3]._outpostStation[i]._cardId == 1) && !isStopConstructionCard(_gameBoardSide[3]._delayCard._cardId)) {
- int stationCount = 0;
- for (int j = 0; j <= 7; j++) {
- if ((_gameBoardSide[3]._outpostStation[j]._cardId > 1) && (_gameBoardSide[3]._outpostStation[j]._cardId <= 9))
- ++stationCount;
- }
-
- if (stationCount == 7)
- _winnerId = 3;
-
- playStationCard(&_gameBoardSide[3]._handCard[randIndx], &_gameBoardSide[3]._outpostStation[i]);
- return;
- }
- }
- } else if (_gameBoardSide[3]._handCard[randIndx]._cardId == 13) {
- int victimId = getPlayerWithOutpost(3);
-
- if (victimId != -1) {
- playCounterTrickCard(&_gameBoardSide[3]._handCard[randIndx], victimId);
- return;
- }
- } else if (_gameBoardSide[3]._handCard[randIndx]._cardId == 25) {
- int victimId = -1;
- int tmpRandIndx = R2_GLOBALS._randomSource.getRandomNumber(3);
-
- for (int i = 0; i <= 3; i++) {
- if ( (tmpRandIndx != 3)
- && ( (_gameBoardSide[tmpRandIndx]._handCard[0]._cardId != 0)
- || (_gameBoardSide[tmpRandIndx]._handCard[1]._cardId != 0)
- || (_gameBoardSide[tmpRandIndx]._handCard[2]._cardId != 0)
- || (_gameBoardSide[tmpRandIndx]._handCard[3]._cardId != 0) )) {
- victimId = tmpRandIndx;
- break;
- }
-
- ++tmpRandIndx;
- if (tmpRandIndx > 3)
- tmpRandIndx = 0;
- }
-
- if (victimId != -1) {
- playThieftCard(3, &_gameBoardSide[3]._handCard[randIndx], victimId);
- return;
- }
- } else {
- switch (_gameBoardSide[3]._handCard[randIndx]._cardId) {
- case 10:
- // No break on purpose
- case 11:
- // No break on purpose
- case 12:
- // No break on purpose
- case 14:
- // No break on purpose
- case 15:
- // No break on purpose
- case 16:
- // No break on purpose
- case 17:
- // No break on purpose
- case 18:
- // No break on purpose
- case 19:
- // No break on purpose
- case 20:
- // No break on purpose
- case 21:
- // No break on purpose
- case 24: {
- int victimId = -1;
- int tmpRandIndx = R2_GLOBALS._randomSource.getRandomNumber(3);
-
- for (int i = 0; i <= 3; i++) {
- if (tmpRandIndx != 3) {
- if ((_gameBoardSide[tmpRandIndx]._delayCard._cardId == 0)
- && isAttackPossible(tmpRandIndx, _gameBoardSide[3]._handCard[randIndx]._cardId))
- victimId = tmpRandIndx;
- }
-
- ++tmpRandIndx;
- if (tmpRandIndx > 3)
- tmpRandIndx = 0;
-
- if (victimId != -1)
- break;
- }
-
- if (victimId != -1) {
- // Useless second identical check skipped
- playDelayCard(&_gameBoardSide[3]._handCard[randIndx], &_gameBoardSide[victimId]._delayCard);
- return;
- }
- }
- default:
- break;
- }
- }
-
- discardCard(&_gameBoardSide[3]._handCard[randIndx]);
-}
-
-void Scene1337::handleAutoplayPlayer2() {
- if (getStationCardId(this->_gameBoardSide[2]._delayCard._cardId) == -1)
- _delayedFunction = &Scene1337::handlePlayer2;
- else
- discardCard(&_gameBoardSide[2]._delayCard);
-}
-
-void Scene1337::handlePlayer2() {
- _selectedCard._stationPos = g_globals->_events._mousePos;
-
- if (R2_GLOBALS._v57810 == 200) {
- // Hand
- int i;
- for (i = 0; i < 4; i++) {
- if ((_gameBoardSide[2]._handCard[i].isIn(_selectedCard._stationPos)) && (_gameBoardSide[2]._handCard[i]._cardId != 0)) {
- Card *handcard = &_gameBoardSide[2]._handCard[i];
- _selectedCard._cardId = handcard->_cardId;
- _selectedCard._stationPos = handcard->_stationPos;
- //warning("_selectedCard._actorName = handcard->_actorName;");
- //warning("_selectedCard._fieldE = handcard->_fieldE;");
- //warning("_selectedCard._field10 = handcard->_field10;");
- //warning("_selectedCard._field12 = handcard->_field12;");
- //warning("_selectedCard._field14 = handcard->_field14;");
- //warning("_selectedCard._field16 = handcard->_field16;");
- _selectedCard._sceneRegionId = handcard->_sceneRegionId;
- _selectedCard._position = handcard->_position;
- _selectedCard._yDiff = handcard->_yDiff;
- _selectedCard._bounds = handcard->_bounds;
- _selectedCard._resNum = handcard->_resNum;
- _selectedCard._lookLineNum = handcard->_lookLineNum;
- _selectedCard._talkLineNum = handcard->_talkLineNum;
- _selectedCard._useLineNum = handcard->_useLineNum;
- _selectedCard._action = handcard->_action;
- //warning("_selectedCard._field0 = handcard->_field0;");
- _selectedCard._card._updateStartFrame = handcard->_card._updateStartFrame;
- _selectedCard._card._walkStartFrame = handcard->_card._walkStartFrame;
- // _field2E is named _field3C in R2R
- _selectedCard._card._oldPosition = handcard->_card._oldPosition;
- _selectedCard._card._percent = handcard->_card._percent;
- _selectedCard._card._priority = handcard->_card._priority;
- _selectedCard._card._angle = handcard->_card._angle;
- _selectedCard._card._flags = handcard->_card._flags;
- _selectedCard._card._xe = handcard->_card._xe;
- _selectedCard._card._xs = handcard->_card._xs;
- _selectedCard._card._paneRects[0] = handcard->_card._paneRects[0];
- _selectedCard._card._paneRects[1] = handcard->_card._paneRects[1];
- _selectedCard._card._visage = handcard->_card._visage;
- _selectedCard._card._objectWrapper = handcard->_card._objectWrapper;
- _selectedCard._card._strip = handcard->_card._strip;
- _selectedCard._card._animateMode = handcard->_card._animateMode;
- _selectedCard._card._frame = handcard->_card._frame;
- _selectedCard._card._endFrame = handcard->_card._endFrame;
- // _field68 is named _field76 in R2R
- _selectedCard._card._loopCount = handcard->_card._loopCount;
- _selectedCard._card._frameChange = handcard->_card._frameChange;
- _selectedCard._card._numFrames = handcard->_card._numFrames;
- _selectedCard._card._regionIndex = handcard->_card._regionIndex;
- _selectedCard._card._mover = handcard->_card._mover;
- _selectedCard._card._moveDiff = handcard->_card._moveDiff;
- _selectedCard._card._moveRate = handcard->_card._moveRate;
- _selectedCard._card._actorDestPos = handcard->_card._actorDestPos;
- _selectedCard._card._endAction = handcard->_card._endAction;
- _selectedCard._card._regionBitList = handcard->_card._regionBitList;
- // _selectedCard._object1._actorName = handcard->_object1._actorName;
- //warning("_selectedCard._card._fieldE = handcard->_card._fieldE;");
- //warning("_selectedCard._card._field10 = handcard->_card._field10;");
- //warning("_selectedCard._card._field12 = handcard->_card._field12;");
- //warning("_selectedCard._card._field14 = handcard->_card._field14;");
- //warning("_selectedCard._card._field16 = handcard->_card._field16;");
-
- _gameBoardSide[2]._handCard[i]._cardId = 0;
- _gameBoardSide[2]._handCard[i]._card.remove();
- break;
- }
- }
-
- if (i == 4) {
- handleClick(1, _selectedCard._stationPos);
- handleAutoplayPlayer2();
- return;
- } else {
- setCursorData(1332, _selectedCard._card._strip, _selectedCard._card._frame);
- R2_GLOBALS._sceneObjects->draw();
- }
- } else if (R2_GLOBALS._v57810 == 300) {
- // Eye
- handleClick(3, _selectedCard._stationPos);
- handleAutoplayPlayer2();
- return;
- } else {
- // The original code is calling a function full of dead code.
- // Only this message remains after a cleanup.
- MessageDialog::show(WRONG_ANSWER_MSG, OK_BTN_STRING);
- //
- handleAutoplayPlayer2();
- return;
- }
-
- Event event;
- bool found;
- for (;;) {
- if ( ((g_globals->_events.getEvent(event, EVENT_BUTTON_DOWN)) && (event.btnState == BTNSHIFT_RIGHT))
- || (g_globals->_events.getEvent(event, EVENT_KEYPRESS)) ){
- _selectedCard._stationPos = g_globals->_events._mousePos;
- found = false;
-
- for (int i = 0; i <= 3; i ++) {
- if (_gameBoardSide[2]._handCard[i].isIn(Common::Point(_selectedCard._stationPos.x + 12, _selectedCard._stationPos.y + 12))) {
- if (_gameBoardSide[2]._handCard[i]._cardId == 0) {
- _gameBoardSide[2]._handCard[i]._cardId = _selectedCard._cardId;
- _gameBoardSide[2]._handCard[i]._card.postInit();
- _gameBoardSide[2]._handCard[i]._card.hide();
- _gameBoardSide[2]._handCard[i]._card.setVisage(1332);
- _gameBoardSide[2]._handCard[i]._card.setPosition(_gameBoardSide[2]._handCard[i]._stationPos, 0);
- _gameBoardSide[2]._handCard[i]._card.fixPriority(170);
- setAnimationInfo(&_gameBoardSide[2]._handCard[i]);
- setCursorData(5, 1, 4);
- _currentPlayerNumb--;
- _showPlayerTurn = false;
- handleNextTurn();
- return;
- } else {
- actionDisplay(1330, 127, 159, 10, 1, 200, 0, 7, 0, 154, 154);
- found = true;
- }
- break;
- }
- }
-
- if (!found) {
- if (_discardPile.isIn(Common::Point(_selectedCard._stationPos.x + 12, _selectedCard._stationPos.y + 12))) {
- discardCard(&_selectedCard);
- return;
- } else if (_selectedCard._cardId == 1) {
- bool isInCardFl = false;
- int i;
- for (i = 0; i <= 7; i++) {
- if (_gameBoardSide[2]._outpostStation[i].isIn(Common::Point(_selectedCard._stationPos.x + 12, _selectedCard._stationPos.y + 12))) {
- isInCardFl = true;
- break;
- }
- }
-
- if ((isInCardFl) && (_gameBoardSide[2]._outpostStation[i]._cardId == 0)) {
- if (isDelayCard(_gameBoardSide[2]._delayCard._cardId) != -1) {
- actionDisplay(1330, 55, 159, 10, 1, 200, 0, 7, 0, 154, 154);
- } else {
- playPlatformCard(&_selectedCard, &_gameBoardSide[2]._outpostStation[i]);
- return;
- }
- } else {
- actionDisplay(1330, 56, 159, 10, 1, 200, 0, 7, 0, 154, 154);
- }
- } else if (_selectedCard._cardId <= 9) {
- bool isInCardFl = false;
- int i;
- for (i = 0; i <= 7; i++) {
- if (_gameBoardSide[2]._outpostStation[i].isIn(Common::Point(_selectedCard._stationPos.x + 12, _selectedCard._stationPos.y + 12))) {
- isInCardFl = true;
- break;
- }
- }
- if ((isInCardFl) && (_gameBoardSide[2]._outpostStation[i]._cardId == 1)) {
- isInCardFl = false;
- for (int j = 0; j <= 7; j++) {
- if (_selectedCard._cardId == _gameBoardSide[2]._outpostStation[j]._cardId) {
- isInCardFl = true;
- break;
- }
- }
- if (isInCardFl) {
- // This station is already in place
- actionDisplay(1330, 34, 159, 10, 1, 200, 0, 7, 0, 154, 154);
- } else if (isDelayCard(_gameBoardSide[2]._delayCard._cardId) != -1) {
- // You must eliminate your delay before you can play a station
- actionDisplay(1330, 35, 159, 10, 1, 200, 0, 7, 0, 154, 154);
- } else {
- int stationCount = 0;
- for (int k = 0; k <= 7; k++) {
- if ((_gameBoardSide[2]._outpostStation[k]._cardId > 1) && (_gameBoardSide[2]._outpostStation[k]._cardId <= 9))
- ++stationCount;
- }
-
- if (stationCount == 7)
- _winnerId = 2;
-
- playStationCard(&_selectedCard, &_gameBoardSide[2]._outpostStation[i]);
- return;
- }
- } else {
- actionDisplay(1330, 37, 159, 10, 1, 200, 0, 7, 0, 154, 154);
- }
- } else if ((_selectedCard._cardId == 26) || (_selectedCard._cardId == 30) ||(_selectedCard._cardId == 32) || (_selectedCard._cardId == 28)) {
- // Check anti-delay card
- if (_gameBoardSide[2]._delayCard.isIn(Common::Point(_selectedCard._stationPos.x + 12, _selectedCard._stationPos.y + 12))) {
- actionDisplay(1330, 42, 159, 10, 1, 200, 0, 7, 0, 154, 154);
- } else if (checkAntiDelayCard(_gameBoardSide[2]._delayCard._cardId, _selectedCard._cardId)) {
- playAntiDelayCard(&_selectedCard, &_gameBoardSide[2]._delayCard);
- return;
- } else {
- if (_gameBoardSide[2]._delayCard._cardId != 0) {
- switch (_gameBoardSide[2]._delayCard._cardId) {
- case 11:
- actionDisplay(1330, 68, 159, 10, 1, 200, 0, 7, 0, 154, 154);
- break;
- case 14:
- actionDisplay(1330, 80, 159, 10, 1, 200, 0, 7, 0, 154, 154);
- break;
- case 16:
- actionDisplay(1330, 84, 159, 10, 1, 200, 0, 7, 0, 154, 154);
- break;
- case 24:
- actionDisplay(1330, 96, 159, 10, 1, 200, 0, 7, 0, 154, 154);
- break;
- default:
- break;
- }
- } else {
- actionDisplay(1330, 41, 159, 10, 1, 200, 0, 7, 0, 154, 154);
- }
- }
- } else if ((getStationCardId(_selectedCard._cardId) == -1) && (isDelayCard(_selectedCard._cardId) == -1)) {
- if (_selectedCard._cardId == 13) {
- if (_gameBoardSide[0]._emptyStationPos.isIn(Common::Point(_selectedCard._stationPos.x + 12, _selectedCard._stationPos.y + 12))) {
- for (int k = 0; k <= 7; k++) {
- if (_gameBoardSide[0]._outpostStation[k]._cardId != 0) {
- playCounterTrickCard(&_selectedCard, 0);
- return;
- }
- }
- actionDisplay(1330, 74, 159, 10, 1, 200, 0, 7, 0, 154, 154);
- } else if (_gameBoardSide[3]._emptyStationPos.isIn(Common::Point(_selectedCard._stationPos.x + 12, _selectedCard._stationPos.y + 12))) {
- for (int k = 0; k <= 7; k++) {
- if (_gameBoardSide[3]._outpostStation[k]._cardId != 0) {
- playCounterTrickCard(&_selectedCard, 3);
- return;
- }
- }
- actionDisplay(1330, 74, 159, 10, 1, 200, 0, 7, 0, 154, 154);
- } else if (_gameBoardSide[1]._emptyStationPos.isIn(Common::Point(_selectedCard._stationPos.x + 12, _selectedCard._stationPos.y + 12))) {
- for (int k = 0; k <= 7; k++) {
- if (_gameBoardSide[1]._outpostStation[k]._cardId == 0) {
- playCounterTrickCard(&_selectedCard, 1);
- return;
- }
- }
- actionDisplay(1330, 74, 159, 10, 1, 200, 0, 7, 0, 154, 154);
- } else {
- actionDisplay(1330, 128, 159, 10, 1, 200, 0, 7, 0, 154, 154);
- }
- } else if (_selectedCard._cardId == 25) {
- if (_gameBoardSide[0]._emptyStationPos.isIn(Common::Point(_selectedCard._stationPos.x + 12, _selectedCard._stationPos.y + 12))) {
- if ( (_gameBoardSide[0]._handCard[0]._cardId != 0)
- || (_gameBoardSide[0]._handCard[1]._cardId != 0)
- || (_gameBoardSide[0]._handCard[2]._cardId != 0)
- || (_gameBoardSide[0]._handCard[3]._cardId != 0) ) {
- int k;
- for (k = 0; k <= 3; k++){
- if (_gameBoardSide[2]._handCard[k]._cardId == 0)
- break;
- }
- playThieftCard(2, &_gameBoardSide[2]._handCard[k], 0);
- return;
- } else {
- actionDisplay(1330, 99, 159, 10, 1, 200, 0, 7, 0, 154, 154);
- }
- } else if (_gameBoardSide[1]._emptyStationPos.isIn(Common::Point(_selectedCard._stationPos.x + 12, _selectedCard._stationPos.y + 12))) {
- if ( (_gameBoardSide[1]._handCard[0]._cardId != 0)
- || (_gameBoardSide[1]._handCard[1]._cardId != 0)
- || (_gameBoardSide[1]._handCard[2]._cardId != 0)
- || (_gameBoardSide[1]._handCard[3]._cardId != 0) ) {
- int k;
- for (k = 0; k <= 3; k++){
- if (_gameBoardSide[2]._handCard[k]._cardId == 0)
- break;
- }
- playThieftCard(2, &_gameBoardSide[2]._handCard[k], 1);
- return;
- } else {
- actionDisplay(1330, 99, 159, 10, 1, 200, 0, 7, 0, 154, 154);
- }
- }
-
- if (_gameBoardSide[3]._emptyStationPos.isIn(Common::Point(_selectedCard._stationPos.x + 12, _selectedCard._stationPos.y + 12))) {
- if ( (_gameBoardSide[3]._handCard[0]._cardId != 0)
- || (_gameBoardSide[3]._handCard[1]._cardId != 0)
- || (_gameBoardSide[3]._handCard[2]._cardId != 0)
- || (_gameBoardSide[3]._handCard[3]._cardId != 0) ) {
- int k;
- for (k = 0; k <= 3; k++){
- if (_gameBoardSide[2]._handCard[k]._cardId == 0)
- break;
- }
- playThieftCard(2, &_gameBoardSide[2]._handCard[k], 3);
- return;
- } else {
- actionDisplay(1330, 99, 159, 10, 1, 200, 0, 7, 0, 154, 154);
- }
- } else {
- actionDisplay(1330, 129, 159, 10, 1, 200, 0, 7, 0, 154, 154);
- }
- } else if (_selectedCard._cardId == 29) {
- // Interceptor cards are used to prevent collision
- actionDisplay(1330, 136, 159, 10, 1, 200, 0, 7, 0, 154, 154);
- } else if (_selectedCard._cardId == 27) {
- actionDisplay(1330, 137, 159, 10, 1, 200, 0, 7, 0, 154, 154);
- }
- } else if (_gameBoardSide[0]._delayCard.isIn(Common::Point(_selectedCard._stationPos.x + 12, _selectedCard._stationPos.y + 12))) {
- if (_gameBoardSide[0]._delayCard._cardId != 0) {
- actionDisplay(1330, 15, 159, 10, 1, 200, 0, 7, 0, 154, 154);
- } else if (!isAttackPossible(0, _selectedCard._cardId)) {
- switch (_selectedCard._cardId) {
- case 10:
- actionDisplay(1330, 66, 159, 10, 1, 200, 0, 7, 0, 154, 154);
- break;
- case 12:
- actionDisplay(1330, 70, 159, 10, 1, 200, 0, 7, 0, 154, 154);
- break;
- case 15:
- actionDisplay(1330, 82, 159, 10, 1, 200, 0, 7, 0, 154, 154);
- break;
- case 17:
- actionDisplay(1330, 86, 159, 10, 1, 200, 0, 7, 0, 154, 154);
- break;
- case 18:
- actionDisplay(1330, 88, 159, 10, 1, 200, 0, 7, 0, 154, 154);
- break;
- case 19:
- actionDisplay(1330, 90, 159, 10, 1, 200, 0, 7, 0, 154, 154);
- break;
- case 20:
- actionDisplay(1330, 92, 159, 10, 1, 200, 0, 7, 0, 154, 154);
- break;
- case 21:
- actionDisplay(1330, 94, 159, 10, 1, 200, 0, 7, 0, 154, 154);
- break;
- default:
- break;
- }
- } else {
- playDelayCard(&_selectedCard, &_gameBoardSide[0]._delayCard);
- return;
- }
- } else if (_gameBoardSide[3]._delayCard.isIn(Common::Point(_selectedCard._stationPos.x + 12, _selectedCard._stationPos.y + 12))) {
- if (_gameBoardSide[3]._delayCard._cardId != 0) {
- actionDisplay(1330, 17, 159, 10, 1, 200, 0, 7, 0, 154, 154);
- } else if (!isAttackPossible(3, _selectedCard._cardId)) {
- switch (_selectedCard._cardId) {
- case 10:
- actionDisplay(1330, 66, 159, 10, 1, 200, 0, 7, 0, 154, 154);
- break;
- case 12:
- actionDisplay(1330, 70, 159, 10, 1, 200, 0, 7, 0, 154, 154);
- break;
- case 15:
- actionDisplay(1330, 82, 159, 10, 1, 200, 0, 7, 0, 154, 154);
- break;
- case 17:
- actionDisplay(1330, 86, 159, 10, 1, 200, 0, 7, 0, 154, 154);
- break;
- case 18:
- actionDisplay(1330, 88, 159, 10, 1, 200, 0, 7, 0, 154, 154);
- break;
- case 19:
- actionDisplay(1330, 90, 159, 10, 1, 200, 0, 7, 0, 154, 154);
- break;
- case 20:
- actionDisplay(1330, 92, 159, 10, 1, 200, 0, 7, 0, 154, 154);
- break;
- case 21:
- actionDisplay(1330, 94, 159, 10, 1, 200, 0, 7, 0, 154, 154);
- break;
- default:
- break;
- }
- } else {
- playDelayCard(&_selectedCard, &_gameBoardSide[3]._delayCard);
- return;
- }
- } else if (_gameBoardSide[1]._delayCard.isIn(Common::Point(_selectedCard._stationPos.x + 12, _selectedCard._stationPos.y + 12))) {
- if (_gameBoardSide[1]._delayCard._cardId != 0) {
- actionDisplay(1330, 19, 159, 10, 1, 200, 0, 7, 0, 154, 154);
- } else if (!isAttackPossible(1, _selectedCard._cardId)) {
- switch (_selectedCard._cardId) {
- case 10:
- actionDisplay(1330, 66, 159, 10, 1, 200, 0, 7, 0, 154, 154);
- break;
- case 12:
- actionDisplay(1330, 70, 159, 10, 1, 200, 0, 7, 0, 154, 154);
- break;
- case 15:
- actionDisplay(1330, 82, 159, 10, 1, 200, 0, 7, 0, 154, 154);
- break;
- case 17:
- actionDisplay(1330, 86, 159, 10, 1, 200, 0, 7, 0, 154, 154);
- break;
- case 18:
- actionDisplay(1330, 88, 159, 10, 1, 200, 0, 7, 0, 154, 154);
- break;
- case 19:
- actionDisplay(1330, 90, 159, 10, 1, 200, 0, 7, 0, 154, 154);
- break;
- case 20:
- actionDisplay(1330, 92, 159, 10, 1, 200, 0, 7, 0, 154, 154);
- break;
- case 21:
- actionDisplay(1330, 94, 159, 10, 1, 200, 0, 7, 0, 154, 154);
- break;
- default:
- break;
- }
- } else {
- playDelayCard(&_selectedCard, &_gameBoardSide[1]._delayCard);
- return;
- }
- } else {
- actionDisplay(1330, 38, 159, 10, 1, 200, 0, 7, 0, 154, 154);
- }
- }
- } else {
- g_globals->_scenePalette.signalListeners();
- R2_GLOBALS._sceneObjects->draw();
- g_globals->_events.delay(g_globals->_sceneHandler->_delayTicks);
- }
-
- g_globals->_sceneObjects->recurse(SceneHandler::dispatchObject);
- }
-}
-
-void Scene1337::updateCursorId(int cursorId, bool updateFl) {
- if ((R2_GLOBALS._v57709 != 0) || (R2_GLOBALS._v5780C != 0))
- return;
-
- R2_GLOBALS._mouseCursorId = cursorId;
-
- if (updateFl) {
- R2_GLOBALS._mouseCursorId++;
-
- if (R2_GLOBALS._mouseCursorId < 1)
- R2_GLOBALS._mouseCursorId = 2;
-
- if (R2_GLOBALS._mouseCursorId > 2)
- R2_GLOBALS._mouseCursorId = 1;
- }
-
- // The original was using an intermediate function to call setCursorData.
- // It has been removed to improve readability
- if (R2_GLOBALS._mouseCursorId == 1) {
- R2_GLOBALS._v57810 = 200;
- setCursorData(5, 1, 4);
- } else if (R2_GLOBALS._mouseCursorId == 2) {
- R2_GLOBALS._v57810 = 300;
- setCursorData(5, 1, 5);
- } else {
- R2_GLOBALS._v57810 = 0;
- setCursorData(5, 0, 0);
- }
-}
-
-void Scene1337::setCursorData(int resNum, int rlbNum, int frameNum) {
- _cursorCurRes = resNum;
- _cursorCurStrip = rlbNum;
- _cursorCurFrame = frameNum;
-
- if (!frameNum) {
- // Should be a hardcoded cursor displaying only a dot.
- // FIXME: Use another cursor when possible
- R2_GLOBALS._events.setCursor(CURSOR_CROSSHAIRS);
- } else {
- // TODO: The original was using some ressource caching, which was useless and complex
- // and which has been removed. This cursor behavior clearly made intensive use of this caching...
- // We now have to find a way to cache these cursor pointers and avoid loading them multiple times per seconds
- uint size;
- byte *cursor = g_resourceManager->getSubResource(resNum, rlbNum, frameNum, &size);
- // Decode the cursor
- GfxSurface s = surfaceFromRes(cursor);
-
- Graphics::Surface surface = s.lockSurface();
- const byte *cursorData = (const byte *)surface.getPixels();
- CursorMan.replaceCursor(cursorData, surface.w, surface.h, s._centroid.x, s._centroid.y, s._transColor);
- s.unlockSurface();
-
- DEALLOCATE(cursor);
- }
-}
-
-void Scene1337::subD18F5() {
- if (R2_GLOBALS._v57709 == 0)
- R2_GLOBALS._events.setCursor(CURSOR_CROSSHAIRS);
-
- ++R2_GLOBALS._v57709;
-}
-
-void Scene1337::subD1917() {
- if (R2_GLOBALS._v57709 != 0) {
- R2_GLOBALS._v57709--;
- if (R2_GLOBALS._v57709 != 0) {
- // The original was using an intermediate function to call setCursorData.
- // It has been removed to improve readability
- setCursorData(5, _cursorCurStrip, _cursorCurFrame);
- }
- }
-}
-
-void Scene1337::subD1940(bool flag) {
- if (flag)
- ++R2_GLOBALS._v5780C;
- else if (R2_GLOBALS._v5780C != 0)
- --R2_GLOBALS._v5780C;
-}
-
-void Scene1337::subD1975(int arg1, int arg2) {
- warning("STUBBED lvl2 Scene1337::subD1975()");
-}
-
-void Scene1337::OptionsDialog::show() {
- OptionsDialog *dlg = new OptionsDialog();
- dlg->draw();
-
- // Show the dialog
- GfxButton *btn = dlg->execute(NULL);
-
- // Figure out the new selected character
- if (btn == &dlg->_quitGame)
- R2_GLOBALS._sceneManager.changeScene(125);
- else if (btn == &dlg->_restartGame)
- R2_GLOBALS._sceneManager.changeScene(1330);
-
- // Remove the dialog
- dlg->remove();
- delete dlg;
-}
-
-Scene1337::OptionsDialog::OptionsDialog() {
- // Set the elements text
- Scene1337 *scene = (Scene1337 *)R2_GLOBALS._sceneManager._scene;
- _autoplay.setText(scene->_autoplay ? AUTO_PLAY_ON : AUTO_PLAY_OFF);
- _restartGame.setText(START_NEW_CARD_GAME);
- _quitGame.setText(QUIT_CARD_GAME);
- _continueGame.setText(CONTINUE_CARD_GAME);
-
- // Set position of the elements
- _autoplay._bounds.moveTo(5, 2);
- _restartGame._bounds.moveTo(5, _autoplay._bounds.bottom + 2);
- _quitGame._bounds.moveTo(5, _restartGame._bounds.bottom + 2);
- _continueGame._bounds.moveTo(5, _quitGame._bounds.bottom + 2);
-
- // Add the items to the dialog
- addElements(&_autoplay, &_restartGame, &_quitGame, &_continueGame, NULL);
-
- // Set the dialog size and position
- frame();
- _bounds.collapse(-6, -6);
- setCenter(160, 100);
-}
-
-GfxButton *Scene1337::OptionsDialog::execute(GfxButton *defaultButton) {
- _gfxManager.activate();
-
- // Event loop
- GfxButton *selectedButton = NULL;
-
- bool breakFlag = false;
- while (!g_vm->shouldQuit() && !breakFlag) {
- Event event;
- while (g_globals->_events.getEvent(event) && !breakFlag) {
- // Adjust mouse positions to be relative within the dialog
- event.mousePos.x -= _gfxManager._bounds.left;
- event.mousePos.y -= _gfxManager._bounds.top;
-
- for (GfxElementList::iterator i = _elements.begin(); i != _elements.end(); ++i) {
- if ((*i)->process(event))
- selectedButton = static_cast<GfxButton *>(*i);
- }
-
- if (selectedButton == &_autoplay) {
- // Toggle Autoplay
- selectedButton = NULL;
- Scene1337 *scene = (Scene1337 *)R2_GLOBALS._sceneManager._scene;
- scene->_autoplay = !scene->_autoplay;
-
- _autoplay.setText(scene->_autoplay ? AUTO_PLAY_ON : AUTO_PLAY_OFF);
- _autoplay.draw();
- } else if (selectedButton) {
- breakFlag = true;
- break;
- } else if (!event.handled) {
- if ((event.eventType == EVENT_KEYPRESS) && (event.kbd.keycode == Common::KEYCODE_ESCAPE)) {
- selectedButton = NULL;
- breakFlag = true;
- break;
- }
- }
- }
-
- g_system->delayMillis(10);
- GLOBALS._screenSurface.updateScreen();
- }
-
- _gfxManager.deactivate();
- return selectedButton;
-}
-
-/*--------------------------------------------------------------------------
* Scene 1500 - Cutscene: Ship landing
*
*--------------------------------------------------------------------------*/
@@ -13433,1796 +7970,5 @@ void Scene1945::signal() {
R2_GLOBALS._player._canWalk = false;
}
-/*--------------------------------------------------------------------------
- * Scene 1950 - Flup Tube Corridor Maze
- *
- *--------------------------------------------------------------------------*/
-
-Scene1950::KeypadWindow::KeypadWindow() {
- _buttonIndex = 0;
-}
-
-void Scene1950::KeypadWindow::synchronize(Serializer &s) {
- SceneArea::synchronize(s);
-
- s.syncAsSint16LE(_buttonIndex);
-}
-
-Scene1950::KeypadWindow::KeypadButton::KeypadButton() {
- _buttonIndex = 0;
- _pressed = false;
- _toggled = false;
-}
-
-void Scene1950::KeypadWindow::KeypadButton::synchronize(Serializer &s) {
- SceneActor::synchronize(s);
-
- s.syncAsSint16LE(_buttonIndex);
- s.syncAsSint16LE(_pressed);
- s.syncAsSint16LE(_toggled);
-}
-
-void Scene1950::KeypadWindow::KeypadButton::init(int indx) {
- Scene1950 *scene = (Scene1950 *)R2_GLOBALS._sceneManager._scene;
-
- _buttonIndex = indx;
- _pressed = false;
- _toggled = false;
-
- postInit();
- setup(1971, 2, 1);
- fixPriority(249);
- setPosition(Common::Point(((_buttonIndex % 4) * 22) + 127, ((_buttonIndex / 4) * 19) + 71));
- scene->_sceneAreas.push_front(this);
-}
-
-void Scene1950::KeypadWindow::KeypadButton::process(Event &event) {
- if ((event.eventType == EVENT_BUTTON_DOWN) && (R2_GLOBALS._events.getCursor() == CURSOR_USE)
- && (_bounds.contains(event.mousePos)) && !_pressed) {
- R2_GLOBALS._sound2.play(227);
- if (!_toggled) {
- setFrame(2);
- _toggled = true;
- } else {
- setFrame(1);
- _toggled = false;
- }
- _pressed = true;
- event.handled = true;
- }
-
- if ((event.eventType == EVENT_BUTTON_UP) && _pressed) {
- _pressed = false;
- event.handled = true;
- Scene1950 *scene = (Scene1950 *)R2_GLOBALS._sceneManager._scene;
- scene->doButtonPress(_buttonIndex);
- }
-}
-
-bool Scene1950::KeypadWindow::KeypadButton::startAction(CursorType action, Event &event) {
- if (action == CURSOR_USE)
- return false;
- return SceneActor::startAction(action, event);
-}
-
-void Scene1950::KeypadWindow::remove() {
- Scene1950 *scene = (Scene1950 *)R2_GLOBALS._sceneManager._scene;
- for (_buttonIndex = 0; _buttonIndex < 16; ++_buttonIndex) {
- scene->_sceneAreas.remove(&_buttons[_buttonIndex]);
- _buttons[_buttonIndex].remove();
- }
-
- ModalWindow::remove();
-
- if (!R2_GLOBALS.getFlag(37))
- R2_GLOBALS._sound2.play(278);
-
- R2_GLOBALS._player.disableControl(CURSOR_WALK);
- scene->_eastExit._enabled = true;
-
- if (!R2_GLOBALS.getFlag(37)) {
- if (R2_GLOBALS.getFlag(36)) {
- scene->_sceneMode = 1964;
- scene->setAction(&scene->_sequenceManager, scene, 1964, &R2_GLOBALS._player, NULL);
- } else {
- scene->_sceneMode = 1965;
- scene->setAction(&scene->_sequenceManager, scene, 1965, &R2_GLOBALS._player, NULL);
- }
- }
-}
-
-void Scene1950::KeypadWindow::setup2(int visage, int stripFrameNum, int frameNum, int posX, int posY) {
- Scene1950 *scene = (Scene1950 *)R2_GLOBALS._sceneManager._scene;
-
- if (R2_GLOBALS._player._mover)
- R2_GLOBALS._player.addMover(NULL);
- R2_GLOBALS._player._canWalk = false;
-
- ModalWindow::setup2(visage, stripFrameNum, frameNum, posX, posY);
-
- _object1.fixPriority(248);
- scene->_eastExit._enabled = false;
- setup3(1950, 27, 28, 27);
-
- for (_buttonIndex = 0; _buttonIndex < 16; _buttonIndex++)
- _buttons[_buttonIndex].init(_buttonIndex);
-}
-
-void Scene1950::KeypadWindow::setup3(int resNum, int lookLineNum, int talkLineNum, int useLineNum) {
- // Copy of Scene1200::LaserPanel::proc13()
- _areaActor.setDetails(resNum, lookLineNum, talkLineNum, useLineNum, 2, (SceneItem *) NULL);
-}
-
-/*--------------------------------------------------------------------------*/
-
-bool Scene1950::Keypad::startAction(CursorType action, Event &event) {
- if ((action != CURSOR_USE) || (R2_GLOBALS.getFlag(37)))
- return SceneHotspot::startAction(action, event);
-
- Scene1950 *scene = (Scene1950 *)R2_GLOBALS._sceneManager._scene;
-
- R2_GLOBALS._player.disableControl();
- if (R2_GLOBALS.getFlag(36)) {
- scene->_sceneMode = 1962;
- scene->setAction(&scene->_sequenceManager, scene, 1962, &R2_GLOBALS._player, NULL);
- } else {
- scene->_sceneMode = 1963;
- scene->setAction(&scene->_sequenceManager, scene, 1963, &R2_GLOBALS._player, NULL);
- }
- return true;
-}
-
-bool Scene1950::Door::startAction(CursorType action, Event &event) {
- if (action != R2_SCRITH_KEY)
- return SceneActor::startAction(action, event);
-
- Scene1950 *scene = (Scene1950 *)R2_GLOBALS._sceneManager._scene;
-
- R2_GLOBALS._player.disableControl();
- R2_INVENTORY.setObjectScene(R2_SCRITH_KEY, 0);
- scene->_sceneMode = 1958;
- scene->setAction(&scene->_sequenceManager, scene, 1958, &R2_GLOBALS._player, &scene->_door, NULL);
- return true;
-}
-
-bool Scene1950::Scrolls::startAction(CursorType action, Event &event) {
- if ((action != CURSOR_USE) || (R2_INVENTORY.getObjectScene(R2_ANCIENT_SCROLLS) != 1950))
- return SceneActor::startAction(action, event);
-
- Scene1950 *scene = (Scene1950 *)R2_GLOBALS._sceneManager._scene;
-
- R2_GLOBALS._player.disableControl();
- scene->_sceneMode = 1968;
- scene->setAction(&scene->_sequenceManager, scene, 1968, &R2_GLOBALS._player, NULL);
-
- return true;
-}
-
-bool Scene1950::Gem::startAction(CursorType action, Event &event) {
- if ((action != CURSOR_USE) || (!R2_GLOBALS.getFlag(37)))
- return SceneActor::startAction(action, event);
-
- Scene1950 *scene = (Scene1950 *)R2_GLOBALS._sceneManager._scene;
-
- R2_GLOBALS._player.disableControl();
- scene->_sceneMode = 1967;
- scene->setAction(&scene->_sequenceManager, scene, 1967, &R2_GLOBALS._player, NULL);
-
- return true;
-}
-
-/*--------------------------------------------------------------------------*/
-
-Scene1950::Vampire::Vampire() {
- _deadPosition = Common::Point(0, 0);
- _deltaX = 0;
- _deltaY = 0;
- _vampireMode = 0;
-}
-
-void Scene1950::Vampire::synchronize(Serializer &s) {
- SceneActor::synchronize(s);
-
- s.syncAsSint16LE(_deadPosition.x);
- s.syncAsSint16LE(_deadPosition.y);
- s.syncAsSint16LE(_deltaX);
- s.syncAsSint16LE(_deltaY);
- s.syncAsSint16LE(_vampireMode);
-}
-
-void Scene1950::Vampire::signal() {
- Scene1950 *scene = (Scene1950 *)R2_GLOBALS._sceneManager._scene;
-
- switch (_vampireMode) {
- case 19: {
- _vampireMode = 0;
- setVisage(1960);
- if (R2_GLOBALS._flubMazeEntryDirection == 3)
- setStrip(2);
- else
- setStrip(1);
-
- NpcMover *mover = new NpcMover();
- addMover(mover, &scene->_vampireDestPos, scene);
- }
- break;
- case 20: {
- // Non fatal shot
- _vampireMode = 19;
- R2_GLOBALS._player.setVisage(22);
- if (R2_GLOBALS._flubMazeEntryDirection == 3)
- R2_GLOBALS._player.setStrip(1);
- else
- R2_GLOBALS._player.setStrip(2);
- R2_GLOBALS._player.animate(ANIM_MODE_1, NULL);
- R2_GLOBALS._vampireData[scene->_vampireIndex - 1]._shotsRequired--;
-
- if (R2_GLOBALS._flubMazeEntryDirection == 3)
- _deadPosition.x = _position.x + 10;
- else
- _deadPosition.x = _position.x - 10;
- _deadPosition.y = _position.y - 4;
-
- setVisage(1961);
-
- if (R2_GLOBALS._flubMazeEntryDirection == 3)
- setStrip(2);
- else
- setStrip(1);
-
- animate(ANIM_MODE_2, NULL);
- Common::Point pt = _deadPosition;
- PlayerMover *mover = new PlayerMover();
- addMover(mover, &pt, this);
-
- R2_GLOBALS._player.enableControl();
- }
- break;
- case 21: {
- // Fatal shot
- R2_GLOBALS._player.setVisage(22);
- if (R2_GLOBALS._flubMazeEntryDirection == 3)
- R2_GLOBALS._player.setStrip(1);
- else
- R2_GLOBALS._player.setStrip(2);
- R2_GLOBALS._player.animate(ANIM_MODE_1, NULL);
-
- setVisage(1961);
- if (R2_GLOBALS._flubMazeEntryDirection == 3)
- setStrip(4);
- else
- setStrip(3);
- setDetails(1950, 15, -1, 17, 2, (SceneItem *) NULL);
- addMover(NULL);
- _numFrames = 8;
- R2_GLOBALS._sound2.play(226);
- animate(ANIM_MODE_5, NULL);
- fixPriority(10);
-
- R2_GLOBALS._vampireData[scene->_vampireIndex - 1]._isAlive = false;
- R2_GLOBALS._vampireData[scene->_vampireIndex - 1]._shotsRequired--;
- R2_GLOBALS._vampireData[scene->_vampireIndex - 1]._position = _position;
- _deltaX = (_position.x - R2_GLOBALS._player._position.x) / 2;
- _deltaY = (_position.y - R2_GLOBALS._player._position.y) / 2;
-
- byte vampireCount = 0;
- for (byte i = 0; i < 18; ++i) {
- if (!R2_GLOBALS._vampireData[i]._isAlive)
- ++vampireCount;
- }
-
- if (vampireCount == 18) {
- R2_GLOBALS.setFlag(36);
- _vampireMode = 23;
- Common::Point pt(R2_GLOBALS._player._position.x + _deltaX, R2_GLOBALS._player._position.y + _deltaY);
- NpcMover *mover = new NpcMover();
- R2_GLOBALS._player.addMover(mover, &pt, this);
- } else if (vampireCount == 1) {
- _vampireMode = 22;
- Common::Point pt(R2_GLOBALS._player._position.x + _deltaX, R2_GLOBALS._player._position.y + _deltaY);
- NpcMover *mover = new NpcMover();
- R2_GLOBALS._player.addMover(mover, &pt, this);
- } else {
- R2_GLOBALS._player.enableControl(CURSOR_WALK);
- }
-
- if (R2_GLOBALS._flubMazeEntryDirection == 3)
- scene->_eastExit._enabled = true;
- else
- scene->_westExit._enabled = true;
-
- scene->_vampireActive = false;
- }
- break;
- case 22:
- SceneItem::display(1950, 18, 0, 280, 1, 160, 9, 1, 2, 20, 7, 7, LIST_END);
- R2_GLOBALS._player.enableControl(CURSOR_WALK);
- break;
- case 23:
- SceneItem::display(1950, 25, 0, 280, 1, 160, 9, 1, 2, 20, 7, 7, LIST_END);
- scene->_sceneMode = R2_GLOBALS._flubMazeEntryDirection;
- scene->setAction(&scene->_sequenceManager, scene, 1960, &R2_GLOBALS._player, NULL);
- break;
- default:
- break;
- }
-}
-
-bool Scene1950::Vampire::startAction(CursorType action, Event &event) {
- Scene1950 *scene = (Scene1950 *)R2_GLOBALS._sceneManager._scene;
-
- if (!R2_GLOBALS._vampireData[scene->_vampireIndex - 1]._isAlive ||
- (action != R2_PHOTON_STUNNER))
- return SceneActor::startAction(action, event);
-
- R2_GLOBALS._player.disableControl();
-
- if (R2_GLOBALS._vampireData[scene->_vampireIndex - 1]._shotsRequired <= 1)
- _vampireMode = 21;
- else
- _vampireMode = 20;
-
- R2_GLOBALS._player.setVisage(25);
- if (R2_GLOBALS._flubMazeEntryDirection == 3)
- R2_GLOBALS._player.setStrip(2);
- else
- R2_GLOBALS._player.setStrip(1);
- R2_GLOBALS._player.animate(ANIM_MODE_5, this);
- R2_GLOBALS._sound3.play(99);
-
- return true;
-}
-
-/*--------------------------------------------------------------------------*/
-
-void Scene1950::NorthExit::changeScene() {
- Scene1950 *scene = (Scene1950 *)R2_GLOBALS._sceneManager._scene;
-
- _enabled = false;
- R2_GLOBALS._player.disableControl(CURSOR_WALK);
- R2_GLOBALS._flubMazeEntryDirection = 1;
- scene->_sceneMode = 11;
-
- Common::Point pt(160, 127);
- PlayerMover *mover = new PlayerMover();
- R2_GLOBALS._player.addMover(mover, &pt, scene);
-}
-
-void Scene1950::UpExit::changeScene() {
- Scene1950 *scene = (Scene1950 *)R2_GLOBALS._sceneManager._scene;
-
- _enabled = false;
- R2_GLOBALS._player.disableControl(CURSOR_WALK);
- R2_GLOBALS._flubMazeEntryDirection = 2;
- scene->_sceneMode = 12;
-
- if (!scene->_upExitStyle) {
- if (R2_GLOBALS.getFlag(36))
- scene->setAction(&scene->_sequenceManager, scene, 1953, &R2_GLOBALS._player, NULL);
- else
- scene->setAction(&scene->_sequenceManager, scene, 1970, &R2_GLOBALS._player, NULL);
- } else {
- if (R2_GLOBALS.getFlag(36))
- scene->setAction(&scene->_sequenceManager, scene, 1952, &R2_GLOBALS._player, NULL);
- else
- scene->setAction(&scene->_sequenceManager, scene, 1969, &R2_GLOBALS._player, NULL);
- }
-}
-
-void Scene1950::EastExit::changeScene() {
- Scene1950 *scene = (Scene1950 *)R2_GLOBALS._sceneManager._scene;
-
- _enabled = false;
- R2_GLOBALS._player.disableControl(CURSOR_WALK);
- R2_GLOBALS._flubMazeEntryDirection = 3;
- scene->_sceneMode = 13;
-
- if (scene->_vampireActive)
- R2_GLOBALS._player.animate(ANIM_MODE_9);
-
- Common::Point pt(340, 160);
- NpcMover *mover = new NpcMover();
- R2_GLOBALS._player.addMover(mover, &pt, scene);
-}
-
-void Scene1950::DownExit::changeScene() {
- Scene1950 *scene = (Scene1950 *)R2_GLOBALS._sceneManager._scene;
-
- _enabled = false;
- R2_GLOBALS._player.disableControl(CURSOR_WALK);
- R2_GLOBALS._flubMazeEntryDirection = 4;
- scene->_sceneMode = 14;
-
- if (R2_GLOBALS.getFlag(36))
- scene->setAction(&scene->_sequenceManager, scene, 1956, &R2_GLOBALS._player, NULL);
- else
- scene->setAction(&scene->_sequenceManager, scene, 1973, &R2_GLOBALS._player, NULL);
-}
-
-void Scene1950::SouthExit::changeScene() {
- Scene1950 *scene = (Scene1950 *)R2_GLOBALS._sceneManager._scene;
-
- _enabled = false;
- R2_GLOBALS._player.disableControl(CURSOR_WALK);
- R2_GLOBALS._flubMazeEntryDirection = 5;
- scene->_sceneMode = 15;
-
- Common::Point pt(160, 213);
- NpcMover *mover = new NpcMover();
- R2_GLOBALS._player.addMover(mover, &pt, scene);
-}
-
-void Scene1950::WestExit::changeScene() {
- Scene1950 *scene = (Scene1950 *)R2_GLOBALS._sceneManager._scene;
-
- _enabled = false;
- R2_GLOBALS._player.disableControl(CURSOR_WALK);
- R2_GLOBALS._flubMazeEntryDirection = 6;
-
- if (R2_GLOBALS._flubMazeArea == 2) {
- // In the very first corridor area after the Scrith Door
- if ((R2_GLOBALS.getFlag(36)) && (R2_INVENTORY.getObjectScene(R2_SAPPHIRE_BLUE) == 2) && (R2_INVENTORY.getObjectScene(R2_ANCIENT_SCROLLS) == 2)) {
- scene->_sceneMode = 1961;
- Common::Point pt(-20, 160);
- NpcMover *mover = new NpcMover();
- R2_GLOBALS._player.addMover(mover, &pt, scene);
- } else {
- if (!R2_GLOBALS.getFlag(36))
- SceneItem::display(1950, 33, 0, 280, 1, 160, 9, 1, 2, 20, 7, 7, LIST_END);
- if ((R2_INVENTORY.getObjectScene(R2_SAPPHIRE_BLUE) == 1950) || (R2_INVENTORY.getObjectScene(R2_ANCIENT_SCROLLS) == 1950))
- SceneItem::display(1950, 34, 0, 280, 1, 160, 9, 1, 2, 20, 7, 7, LIST_END);
- scene->_sceneMode = 0;
- Common::Point pt(30, 160);
- NpcMover *mover = new NpcMover();
- R2_GLOBALS._player.addMover(mover, &pt, scene);
- }
- } else {
- if (scene->_vampireActive)
- R2_GLOBALS._player.animate(ANIM_MODE_9);
-
- scene->_sceneMode = 16;
- Common::Point pt(-20, 160);
- NpcMover *mover = new NpcMover();
- R2_GLOBALS._player.addMover(mover, &pt, scene);
- }
-}
-
-void Scene1950::ShaftExit::changeScene() {
- Scene1950 *scene = (Scene1950 *)R2_GLOBALS._sceneManager._scene;
-
- _enabled = false;
- R2_GLOBALS._player.disableControl(CURSOR_WALK);
- R2_GLOBALS._flubMazeEntryDirection = 0;
- scene->_sceneMode = 1951;
- scene->setAction(&scene->_sequenceManager, scene, 1951, &R2_GLOBALS._player, NULL);
-}
-
-void Scene1950::DoorExit::changeScene() {
- Scene1950 *scene = (Scene1950 *)R2_GLOBALS._sceneManager._scene;
-
- _enabled = false;
- R2_GLOBALS._player.disableControl(CURSOR_WALK);
- R2_GLOBALS._flubMazeEntryDirection = 3;
- if (R2_GLOBALS._player._visage == 22) {
- scene->_sceneMode = 1975;
- scene->setAction(&scene->_sequenceManager, scene, 1975, &R2_GLOBALS._player, NULL);
- } else {
- SceneItem::display(1950, 22, 0, 280, 1, 160, 9, 1, 2, 20, 7, 7, LIST_END);
- R2_GLOBALS._flubMazeEntryDirection = 0;
- scene->_sceneMode = 0;
- Common::Point pt(250, 150);
- NpcMover *mover = new NpcMover();
- R2_GLOBALS._player.addMover(mover, &pt, scene);
- _enabled = true;
- }
-}
-
-/*--------------------------------------------------------------------------*/
-
-Scene1950::Scene1950() {
- _upExitStyle = false;
- _removeFlag = false;
- _vampireActive = false;
- _vampireDestPos = Common::Point(0, 0);
- _vampireIndex = 0;
-}
-
-void Scene1950::synchronize(Serializer &s) {
- SceneExt::synchronize(s);
-
- s.syncAsSint16LE(_upExitStyle);
- s.syncAsSint16LE(_removeFlag);
- s.syncAsSint16LE(_vampireActive);
- s.syncAsSint16LE(_vampireDestPos.x);
- s.syncAsSint16LE(_vampireDestPos.y);
- s.syncAsSint16LE(_vampireIndex);
-}
-
-void Scene1950::initArea() {
- _northExit._enabled = false;
- _upExit._enabled = false;
- _eastExit._enabled = false;
- _downExit._enabled = false;
- _southExit._enabled = false;
- _westExit._enabled = false;
- _shaftExit._enabled = false;
- _doorExit._enabled = false;
- _northExit._insideArea = false;
- _upExit._insideArea = false;
- _eastExit._insideArea = false;
- _downExit._insideArea = false;
- _southExit._insideArea = false;
- _westExit._insideArea = false;
- _shaftExit._insideArea = false;
- _doorExit._insideArea = false;
- _northExit._moving = false;
- _upExit._moving = false;
- _eastExit._moving = false;
- _downExit._moving = false;
- _southExit._moving = false;
- _westExit._moving = false;
- _shaftExit._moving = false;
- _doorExit._moving = false;
- _upExitStyle = false;
-
- switch (R2_GLOBALS._flubMazeArea - 1) {
- case 0:
- loadScene(1948);
- break;
- case 1:
- // No break on purpose
- case 8:
- // No break on purpose
- case 10:
- // No break on purpose
- case 12:
- // No break on purpose
- case 16:
- // No break on purpose
- case 19:
- // No break on purpose
- case 23:
- // No break on purpose
- case 30:
- // No break on purpose
- case 44:
- // No break on purpose
- case 72:
- // No break on purpose
- case 74:
- // No break on purpose
- case 86:
- // No break on purpose
- case 96:
- // No break on purpose
- case 103:
- loadScene(1950);
- break;
- case 2:
- // No break on purpose
- case 29:
- loadScene(1965);
- break;
- case 3:
- // No break on purpose
- case 9:
- // No break on purpose
- case 11:
- // No break on purpose
- case 15:
- // No break on purpose
- case 24:
- // No break on purpose
- case 39:
- // No break on purpose
- case 45:
- // No break on purpose
- case 71:
- // No break on purpose
- case 73:
- // No break on purpose
- case 75:
- // No break on purpose
- case 79:
- // No break on purpose
- case 85:
- // No break on purpose
- case 87:
- // No break on purpose
- case 95:
- loadScene(1955);
- break;
- case 4:
- // No break on purpose
- case 6:
- // No break on purpose
- case 13:
- // No break on purpose
- case 27:
- // No break on purpose
- case 41:
- // No break on purpose
- case 48:
- // No break on purpose
- case 50:
- // No break on purpose
- case 54:
- // No break on purpose
- case 76:
- // No break on purpose
- case 80:
- // No break on purpose
- case 90:
- // No break on purpose
- case 104:
- loadScene(1975);
- break;
- case 5:
- // No break on purpose
- case 7:
- // No break on purpose
- case 14:
- // No break on purpose
- case 28:
- // No break on purpose
- case 32:
- // No break on purpose
- case 47:
- // No break on purpose
- case 53:
- loadScene(1997);
- break;
- case 17:
- // No break on purpose
- case 20:
- // No break on purpose
- case 25:
- // No break on purpose
- case 31:
- // No break on purpose
- case 33:
- // No break on purpose
- case 46:
- loadScene(1995);
- break;
- case 18:
- // No break on purpose
- case 22:
- // No break on purpose
- case 26:
- // No break on purpose
- case 36:
- // No break on purpose
- case 38:
- // No break on purpose
- case 43:
- // No break on purpose
- case 51:
- // No break on purpose
- case 70:
- // No break on purpose
- case 78:
- // No break on purpose
- case 84:
- // No break on purpose
- case 89:
- // No break on purpose
- case 101:
- loadScene(1970);
- break;
- case 21:
- // No break on purpose
- case 34:
- // No break on purpose
- case 57:
- // No break on purpose
- case 58:
- // No break on purpose
- case 59:
- // No break on purpose
- case 62:
- // No break on purpose
- case 65:
- loadScene(1980);
- break;
- case 35:
- // No break on purpose
- case 61:
- // No break on purpose
- case 77:
- // No break on purpose
- case 83:
- loadScene(1982);
- break;
- case 37:
- // No break on purpose
- case 52:
- // No break on purpose
- case 82:
- // No break on purpose
- case 88:
- // No break on purpose
- case 92:
- // No break on purpose
- case 97:
- // No break on purpose
- case 100:
- loadScene(1962);
- break;
- case 40:
- // No break on purpose
- case 102:
- loadScene(1960);
- break;
- case 42:
- // No break on purpose
- case 55:
- // No break on purpose
- case 60:
- // No break on purpose
- case 66:
- // No break on purpose
- case 68:
- // No break on purpose
- case 69:
- // No break on purpose
- case 93:
- // No break on purpose
- case 98:
- loadScene(1990);
- break;
- case 49:
- // No break on purpose
- case 81:
- // No break on purpose
- case 91:
- // No break on purpose
- case 94:
- // No break on purpose
- case 99:
- loadScene(1967);
- break;
- case 56:
- // No break on purpose
- case 63:
- // No break on purpose
- case 64:
- // No break on purpose
- case 67:
- loadScene(1985);
- _upExitStyle = true;
- break;
- default:
- break;
- }
-
- if (R2_GLOBALS._flubMazeArea != 1)
- R2_GLOBALS._walkRegions.load(1950);
-
- switch (R2_GLOBALS._flubMazeArea - 1) {
- case 0:
- _shaftExit._enabled = true;
- if ((R2_INVENTORY.getObjectScene(R2_SCRITH_KEY) == 0) && (R2_INVENTORY.getObjectScene(R2_SAPPHIRE_BLUE) == 1950))
- _doorExit._enabled = true;
- R2_GLOBALS._walkRegions.disableRegion(2);
- R2_GLOBALS._walkRegions.disableRegion(3);
- R2_GLOBALS._walkRegions.disableRegion(4);
- R2_GLOBALS._walkRegions.disableRegion(5);
- R2_GLOBALS._walkRegions.disableRegion(6);
- break;
- case 1:
- // No break on purpose
- case 2:
- // No break on purpose
- case 3:
- // No break on purpose
- case 8:
- // No break on purpose
- case 9:
- // No break on purpose
- case 10:
- // No break on purpose
- case 11:
- // No break on purpose
- case 12:
- // No break on purpose
- case 15:
- // No break on purpose
- case 16:
- // No break on purpose
- case 19:
- // No break on purpose
- case 23:
- // No break on purpose
- case 24:
- // No break on purpose
- case 29:
- // No break on purpose
- case 30:
- // No break on purpose
- case 39:
- // No break on purpose
- case 40:
- // No break on purpose
- case 44:
- // No break on purpose
- case 45:
- // No break on purpose
- case 71:
- // No break on purpose
- case 72:
- // No break on purpose
- case 73:
- // No break on purpose
- case 74:
- // No break on purpose
- case 75:
- // No break on purpose
- case 79:
- // No break on purpose
- case 85:
- // No break on purpose
- case 86:
- // No break on purpose
- case 87:
- // No break on purpose
- case 95:
- // No break on purpose
- case 96:
- // No break on purpose
- case 102:
- // No break on purpose
- case 103:
- _eastExit._enabled = true;
- _westExit._enabled = true;
- break;
- case 4:
- // No break on purpose
- case 6:
- // No break on purpose
- case 13:
- // No break on purpose
- case 17:
- // No break on purpose
- case 20:
- // No break on purpose
- case 25:
- // No break on purpose
- case 27:
- // No break on purpose
- case 31:
- // No break on purpose
- case 33:
- // No break on purpose
- case 37:
- // No break on purpose
- case 41:
- // No break on purpose
- case 46:
- // No break on purpose
- case 48:
- // No break on purpose
- case 50:
- // No break on purpose
- case 52:
- // No break on purpose
- case 54:
- // No break on purpose
- case 76:
- // No break on purpose
- case 80:
- // No break on purpose
- case 82:
- // No break on purpose
- case 88:
- // No break on purpose
- case 90:
- // No break on purpose
- case 92:
- // No break on purpose
- case 97:
- // No break on purpose
- case 100:
- // No break on purpose
- case 104:
- _westExit._enabled = true;
- R2_GLOBALS._walkRegions.disableRegion(6);
- R2_GLOBALS._walkRegions.disableRegion(9);
- break;
- case 5:
- // No break on purpose
- case 7:
- // No break on purpose
- case 14:
- // No break on purpose
- case 18:
- // No break on purpose
- case 22:
- // No break on purpose
- case 26:
- // No break on purpose
- case 28:
- // No break on purpose
- case 32:
- // No break on purpose
- case 36:
- // No break on purpose
- case 38:
- // No break on purpose
- case 43:
- // No break on purpose
- case 47:
- // No break on purpose
- case 49:
- // No break on purpose
- case 51:
- // No break on purpose
- case 53:
- // No break on purpose
- case 70:
- // No break on purpose
- case 78:
- // No break on purpose
- case 81:
- // No break on purpose
- case 84:
- // No break on purpose
- case 89:
- // No break on purpose
- case 91:
- // No break on purpose
- case 94:
- // No break on purpose
- case 99:
- // No break on purpose
- case 101:
- _eastExit._enabled = true;
- R2_GLOBALS._walkRegions.disableRegion(1);
- R2_GLOBALS._walkRegions.disableRegion(7);
- R2_GLOBALS._walkRegions.disableRegion(13);
- break;
- default:
- R2_GLOBALS._walkRegions.disableRegion(1);
- R2_GLOBALS._walkRegions.disableRegion(6);
- R2_GLOBALS._walkRegions.disableRegion(7);
- R2_GLOBALS._walkRegions.disableRegion(9);
- R2_GLOBALS._walkRegions.disableRegion(13);
- break;
- }
-
- _northDoorway.remove();
- _northDoorway.removeObject();
- _southDoorway.remove();
-
- switch (R2_GLOBALS._flubMazeArea - 4) {
- case 0:
- // No break on purpose
- case 3:
- // No break on purpose
- case 16:
- // No break on purpose
- case 22:
- // No break on purpose
- case 24:
- // No break on purpose
- case 32:
- // No break on purpose
- case 33:
- // No break on purpose
- case 45:
- // No break on purpose
- case 46:
- // No break on purpose
- case 48:
- // No break on purpose
- case 51:
- // No break on purpose
- case 56:
- // No break on purpose
- case 59:
- // No break on purpose
- case 67:
- // No break on purpose
- case 68:
- // No break on purpose
- case 70:
- // No break on purpose
- case 73:
- // No break on purpose
- case 82:
- // No break on purpose
- case 90:
- _northExit._enabled = true;
- _northDoorway.setup(1950, (R2_GLOBALS._flubMazeArea % 2) + 1, 1, 160, 137, 25);
- //visage,strip,frame,px,py,priority,effect
- _southDoorway.postInit();
- _southDoorway.setVisage(1950);
- _southDoorway.setStrip((((R2_GLOBALS._flubMazeArea - 1) / 35) % 2) + 1);
- _southDoorway.setFrame(2);
- _southDoorway.setPosition(Common::Point(160, 167));
- _southDoorway.fixPriority(220);
- R2_GLOBALS._walkRegions.disableRegion(3);
- R2_GLOBALS._walkRegions.disableRegion(4);
- break;
- case 7:
- // No break on purpose
- case 10:
- // No break on purpose
- case 23:
- // No break on purpose
- case 29:
- // No break on purpose
- case 31:
- // No break on purpose
- case 39:
- // No break on purpose
- case 40:
- // No break on purpose
- case 52:
- // No break on purpose
- case 53:
- // No break on purpose
- case 55:
- // No break on purpose
- case 63:
- // No break on purpose
- case 65:
- // No break on purpose
- case 66:
- // No break on purpose
- case 75:
- // No break on purpose
- case 77:
- // No break on purpose
- case 81:
- // No break on purpose
- case 87:
- // No break on purpose
- case 89:
- // No break on purpose
- case 97:
- _southExit._enabled = true;
-
- _southDoorway.postInit();
- _southDoorway.setVisage(1950);
- _southDoorway.setStrip((((R2_GLOBALS._flubMazeArea - 1) / 35) % 2) + 1);
- _southDoorway.setFrame(3);
- _southDoorway.setPosition(Common::Point(160, 167));
- _southDoorway.fixPriority(220);
- break;
- case 58:
- // No break on purpose
- case 74:
- // No break on purpose
- case 80:
- _northExit._enabled = true;
- _southExit._enabled = true;
-
- _northDoorway.setup(1950, (R2_GLOBALS._flubMazeArea % 2) + 1, 1, 160, 137, 25);
-
- _southDoorway.postInit();
- _southDoorway.setVisage(1950);
- _southDoorway.setStrip((((R2_GLOBALS._flubMazeArea - 1) / 35) % 2) + 1);
- _southDoorway.setFrame(3);
- _southDoorway.setPosition(Common::Point(160, 167));
- _southDoorway.fixPriority(220);
- R2_GLOBALS._walkRegions.disableRegion(3);
- R2_GLOBALS._walkRegions.disableRegion(4);
- break;
- default:
- _southDoorway.postInit();
- _southDoorway.setVisage(1950);
- _southDoorway.setStrip(((R2_GLOBALS._flubMazeArea - 1) / 35) % 2 + 1);
- _southDoorway.setFrame(2);
- _southDoorway.setPosition(Common::Point(160, 167));
- _southDoorway.fixPriority(220);
- break;
- }
-
- switch (R2_GLOBALS._flubMazeArea - 3) {
- case 0:
- // No break on purpose
- case 3:
- // No break on purpose
- case 5:
- // No break on purpose
- case 12:
- // No break on purpose
- case 15:
- // No break on purpose
- case 18:
- // No break on purpose
- case 19:
- // No break on purpose
- case 23:
- // No break on purpose
- case 26:
- // No break on purpose
- case 27:
- // No break on purpose
- case 29:
- // No break on purpose
- case 30:
- // No break on purpose
- case 31:
- // No break on purpose
- case 32:
- // No break on purpose
- case 44:
- // No break on purpose
- case 45:
- // No break on purpose
- case 51:
- // No break on purpose
- case 55:
- // No break on purpose
- case 56:
- // No break on purpose
- case 57:
- // No break on purpose
- case 60:
- // No break on purpose
- case 63:
- _upExit._enabled = true;
- break;
- case 54:
- // No break on purpose
- case 61:
- // No break on purpose
- case 62:
- // No break on purpose
- case 65:
- _upExit._enabled = true;
- // No break on purpose
- case 35:
- // No break on purpose
- case 38:
- // No break on purpose
- case 40:
- // No break on purpose
- case 47:
- // No break on purpose
- case 50:
- // No break on purpose
- case 53:
- // No break on purpose
- case 58:
- // No break on purpose
- case 64:
- // No break on purpose
- case 66:
- // No break on purpose
- case 67:
- // No break on purpose
- case 79:
- // No break on purpose
- case 80:
- // No break on purpose
- case 86:
- // No break on purpose
- case 89:
- // No break on purpose
- case 90:
- // No break on purpose
- case 91:
- // No break on purpose
- case 92:
- // No break on purpose
- case 95:
- // No break on purpose
- case 96:
- // No break on purpose
- case 97:
- // No break on purpose
- case 98:
- // No break on purpose
- case 100:
- _downExit._enabled = true;
- R2_GLOBALS._walkRegions.disableRegion(4);
- R2_GLOBALS._walkRegions.disableRegion(5);
- R2_GLOBALS._walkRegions.disableRegion(6);
- R2_GLOBALS._walkRegions.disableRegion(10);
- R2_GLOBALS._walkRegions.disableRegion(11);
- default:
- break;
- }
- R2_GLOBALS._uiElements.draw();
-}
-
-void Scene1950::enterArea() {
- R2_GLOBALS._player.disableControl();
- R2_GLOBALS._player.animate(ANIM_MODE_1, NULL);
-
- _vampire.remove();
- _door.remove();
- _scrolls.remove();
-
- _vampireActive = false;
- _vampireIndex = 0;
-
- // Certain areas have a vampire in them
- switch (R2_GLOBALS._flubMazeArea) {
- case 10:
- _vampireIndex = 1;
- break;
- case 13:
- _vampireIndex = 2;
- break;
- case 16:
- _vampireIndex = 3;
- break;
- case 17:
- _vampireIndex = 4;
- break;
- case 24:
- _vampireIndex = 5;
- break;
- case 25:
- _vampireIndex = 6;
- break;
- case 31:
- _vampireIndex = 7;
- break;
- case 40:
- _vampireIndex = 8;
- break;
- case 45:
- _vampireIndex = 9;
- break;
- case 46:
- _vampireIndex = 10;
- break;
- case 73:
- _vampireIndex = 11;
- break;
- case 75:
- _vampireIndex = 12;
- break;
- case 80:
- _vampireIndex = 13;
- break;
- case 87:
- _vampireIndex = 14;
- break;
- case 88:
- _vampireIndex = 15;
- break;
- case 96:
- _vampireIndex = 16;
- break;
- case 97:
- _vampireIndex = 17;
- break;
- case 104:
- _vampireIndex = 18;
- break;
- default:
- break;
- }
-
- if (_vampireIndex != 0) {
- _vampire.postInit();
- _vampire._numFrames = 6;
- _vampire._moveRate = 6;
- _vampire._moveDiff = Common::Point(3, 2);
- _vampire._effect = EFFECT_SHADED;
-
- if (!R2_GLOBALS._vampireData[_vampireIndex - 1]._isAlive) {
- // Show vampire ashes
- _vampire.setPosition(Common::Point(R2_GLOBALS._vampireData[_vampireIndex - 1]._position));
- _vampire.animate(ANIM_MODE_NONE, NULL);
- _vampire.addMover(NULL);
- _vampire.setVisage(1961);
- _vampire.setStrip(4);
- _vampire.setFrame(10);
- _vampire.fixPriority(10);
- _vampire.setDetails(1950, 15, -1, 17, 2, (SceneItem *) NULL);
- } else {
- // Start the vampire
- _vampire.setVisage(1960);
- _vampire.setPosition(Common::Point(160, 130));
- _vampire.animate(ANIM_MODE_2, NULL);
- _vampire.setDetails(1950, 12, -1, 14, 2, (SceneItem *) NULL);
- _vampireActive = true;
- }
- }
- if ((R2_GLOBALS._flubMazeArea == 1) && (R2_INVENTORY.getObjectScene(R2_SCRITH_KEY) != 0)) {
- // Show doorway at the right hand side of the very first flub corridor
- _door.postInit();
- _door.setVisage(1948);
- _door.setStrip(3);
- _door.setPosition(Common::Point(278, 155));
- _door.fixPriority(100);
- _door.setDetails(1950, 19, 20, 23, 2, (SceneItem *) NULL);
- }
-
- if (R2_GLOBALS._flubMazeArea == 102) {
- R2_GLOBALS._walkRegions.load(1951);
- R2_GLOBALS._walkRegions.disableRegion(1);
- R2_GLOBALS._walkRegions.disableRegion(5);
- R2_GLOBALS._walkRegions.disableRegion(6);
- R2_GLOBALS._walkRegions.disableRegion(7);
-
- _cube.postInit();
- _cube.setVisage(1970);
- _cube.setStrip(1);
- if (R2_GLOBALS.getFlag(37))
- _cube.setFrame(3);
- else
- _cube.setFrame(1);
- _cube.setPosition(Common::Point(193, 158));
- _cube.setDetails(1950, 3, 4, 5, 2, (SceneItem *) NULL);
-
- _pulsingLights.postInit();
- _pulsingLights.setVisage(1970);
- _pulsingLights.setStrip(3);
- _pulsingLights.animate(ANIM_MODE_2, NULL);
- _pulsingLights._numFrames = 6;
- _pulsingLights.setPosition(Common::Point(194, 158));
- _pulsingLights.fixPriority(159);
-
- _keypad.setDetails(Rect(188, 124, 199, 133), 1950, 27, 28, -1, 2, NULL);
-
- if (R2_INVENTORY.getObjectScene(R2_SAPPHIRE_BLUE) == 1950) {
- _gem.postInit();
- _gem.setVisage(1970);
- _gem.setStrip(1);
- _gem.setFrame(2);
- _gem.fixPriority(160);
- }
-
- if (R2_GLOBALS.getFlag(37)) {
- _gem.setPosition(Common::Point(192, 118));
- _gem.setDetails(1950, 9, 4, -1, 2, (SceneItem *) NULL);
- } else {
- _containmentField.postInit();
- _containmentField.setVisage(1970);
- _containmentField.setStrip(4);
- _containmentField._numFrames = 4;
- _containmentField.animate(ANIM_MODE_8, 0, NULL);
- _containmentField.setPosition(Common::Point(192, 121));
- _containmentField.fixPriority(159);
- _containmentField.setDetails(1950, 6, 7, 8, 2, (SceneItem *) NULL);
-
- _gem.setPosition(Common::Point(192, 109));
- _gem.setDetails(1950, 9, 7, 8, 2, (SceneItem *) NULL);
- }
-
- _scrolls.postInit();
- _scrolls.setVisage(1972);
- _scrolls.setStrip(1);
- _scrolls.setPosition(Common::Point(76, 94));
- _scrolls.fixPriority(25);
- _scrolls.setDetails(1950, 30, -1, -1, 2, (SceneItem *) NULL);
- if (R2_INVENTORY.getObjectScene(R2_ANCIENT_SCROLLS) == 2)
- _scrolls.setFrame(2);
- else
- _scrolls.setFrame(1);
-
- _removeFlag = true;
- } else if (_removeFlag) {
- _cube.remove();
- _containmentField.remove();
- _gem.remove();
- _pulsingLights.remove();
- _scrolls.remove();
-
- R2_GLOBALS._sceneItems.remove(&_background);
- _background.setDetails(Rect(0, 0, 320, 200), 1950, 0, 1, 2, 2, NULL);
-
- _removeFlag = false;
- }
-
- switch (R2_GLOBALS._flubMazeEntryDirection) {
- case 0:
- _sceneMode = 1950;
- if (R2_INVENTORY.getObjectScene(R2_SCRITH_KEY) == 0)
- // The original uses CURSOR_ARROW. CURSOR_WALK is much more coherent
- R2_GLOBALS._player.enableControl(CURSOR_WALK);
- else
- setAction(&_sequenceManager, this, 1950, &R2_GLOBALS._player, NULL);
-
- break;
- case 1: {
- _sceneMode = R2_GLOBALS._flubMazeEntryDirection;
- R2_GLOBALS._player.setPosition(Common::Point(160, 213));
- Common::Point pt(160, 160);
- NpcMover *mover = new NpcMover();
- R2_GLOBALS._player.addMover(mover, &pt, this);
- }
- break;
- case 2:
- _sceneMode = R2_GLOBALS._flubMazeEntryDirection;
- if (R2_GLOBALS.getFlag(36))
- setAction(&_sequenceManager, this, 1957, &R2_GLOBALS._player, NULL);
- else
- setAction(&_sequenceManager, this, 1974, &R2_GLOBALS._player, NULL);
- break;
- case 3:
- // Entering from the left
- if (!_vampireActive) {
- _sceneMode = R2_GLOBALS._flubMazeEntryDirection;
- R2_GLOBALS._player.setPosition(Common::Point(-20, 160));
- Common::Point pt(30, 160);
- NpcMover *mover = new NpcMover();
- R2_GLOBALS._player.addMover(mover, &pt, this);
- } else {
- _sceneMode = 18;
- _eastExit._enabled = false;
- _vampireDestPos = Common::Point(60, 152);
- R2_GLOBALS._player.enableControl(CURSOR_USE);
- R2_GLOBALS._player._canWalk = false;
-
- _vampire.setStrip(2);
- NpcMover *mover = new NpcMover();
- _vampire.addMover(mover, &_vampireDestPos, this);
-
- R2_GLOBALS._player.setPosition(Common::Point(-20, 160));
- Common::Point pt2(30, 160);
- NpcMover *mover2 = new NpcMover();
- R2_GLOBALS._player.addMover(mover2, &pt2, NULL);
- }
- break;
- case 4:
- _sceneMode = R2_GLOBALS._flubMazeEntryDirection;
- if (!_upExitStyle) {
- if (R2_GLOBALS.getFlag(36))
- setAction(&_sequenceManager, this, 1955, &R2_GLOBALS._player, NULL);
- else
- setAction(&_sequenceManager, this, 1972, &R2_GLOBALS._player, NULL);
- } else {
- if (R2_GLOBALS.getFlag(36))
- setAction(&_sequenceManager, this, 1954, &R2_GLOBALS._player, NULL);
- else
- setAction(&_sequenceManager, this, 1971, &R2_GLOBALS._player, NULL);
- }
- break;
- case 5: {
- _sceneMode = R2_GLOBALS._flubMazeEntryDirection;
- R2_GLOBALS._player.setPosition(Common::Point(160, 127));
- Common::Point pt(160, 160);
- NpcMover *mover = new NpcMover();
- R2_GLOBALS._player.addMover(mover, &pt, this);
- }
- break;
- case 6:
- // Entering from the right
- if (!_vampireActive) {
- _sceneMode = R2_GLOBALS._flubMazeEntryDirection;
- if (R2_GLOBALS._flubMazeArea == 1) {
- setAction(&_sequenceManager, this, 1961, &R2_GLOBALS._player, NULL);
- } else {
- R2_GLOBALS._player.setPosition(Common::Point(340, 160));
- Common::Point pt(289, 160);
- NpcMover *mover = new NpcMover();
- R2_GLOBALS._player.addMover(mover, &pt, this);
- }
- } else {
- _sceneMode = 17;
- _westExit._enabled = false;
- _vampireDestPos = Common::Point(259, 152);
-
- R2_GLOBALS._player.enableControl(CURSOR_USE);
- R2_GLOBALS._player._canWalk = false;
-
- _vampire.setStrip(1);
- NpcMover *mover = new NpcMover();
- _vampire.addMover(mover, &_vampireDestPos, this);
-
- R2_GLOBALS._player.setPosition(Common::Point(340, 160));
- Common::Point pt2(289, 160);
- NpcMover *mover2 = new NpcMover();
- R2_GLOBALS._player.addMover(mover2, &pt2, NULL);
- }
- break;
- default:
- break;
- }
-}
-
-void Scene1950::doButtonPress(int indx) {
- Scene1950 *scene = (Scene1950 *)R2_GLOBALS._sceneManager._scene;
- R2_GLOBALS._player.disableControl();
-
- int prevIndex = indx - 1;
- if ((indx / 4) == (prevIndex / 4)) {
- if (prevIndex < 0)
- prevIndex = 3;
- } else {
- prevIndex += 4;
- }
-
- assert(prevIndex >= 0 && prevIndex < 16);
- if (!_KeypadWindow._buttons[prevIndex]._toggled) {
- _KeypadWindow._buttons[prevIndex].setFrame(2);
- _KeypadWindow._buttons[prevIndex]._toggled = true;
- } else {
- _KeypadWindow._buttons[prevIndex].setFrame(1);
- _KeypadWindow._buttons[prevIndex]._toggled = false;
- }
-
- prevIndex = indx + 1;
- if ((indx / 4) == (prevIndex / 4)) {
- if (prevIndex > 15)
- prevIndex = 12;
- } else {
- prevIndex -= 4;
- }
-
- assert(prevIndex >= 0 && prevIndex < 16);
- if (!_KeypadWindow._buttons[prevIndex]._toggled) {
- _KeypadWindow._buttons[prevIndex].setFrame(2);
- _KeypadWindow._buttons[prevIndex]._toggled = true;
- } else {
- _KeypadWindow._buttons[prevIndex].setFrame(1);
- _KeypadWindow._buttons[prevIndex]._toggled = false;
- }
-
- prevIndex = indx - 4;
- if (prevIndex < 0)
- prevIndex += 16;
-
- assert(prevIndex >= 0 && prevIndex < 16);
- if (!_KeypadWindow._buttons[prevIndex]._toggled) {
- _KeypadWindow._buttons[prevIndex].setFrame(2);
- _KeypadWindow._buttons[prevIndex]._toggled = true;
- } else {
- _KeypadWindow._buttons[prevIndex].setFrame(1);
- _KeypadWindow._buttons[prevIndex]._toggled = false;
- }
-
- prevIndex = indx + 4;
- if (prevIndex > 15)
- prevIndex -= 16;
-
- assert(prevIndex >= 0 && prevIndex < 16);
- if (!_KeypadWindow._buttons[prevIndex]._toggled) {
- _KeypadWindow._buttons[prevIndex].setFrame(2);
- _KeypadWindow._buttons[prevIndex]._toggled = true;
- } else {
- _KeypadWindow._buttons[prevIndex].setFrame(1);
- _KeypadWindow._buttons[prevIndex]._toggled = false;
- }
-
- // Check whether all the buttons are highlighted
- int cpt = 0;
- for (prevIndex = 0; prevIndex < 16; prevIndex++) {
- if (_KeypadWindow._buttons[prevIndex]._toggled)
- ++cpt;
- }
-
- if (cpt != 16) {
- R2_GLOBALS._player.enableControl();
- R2_GLOBALS._player._canWalk = false;
- } else {
- R2_GLOBALS.setFlag(37);
- _sceneMode = 24;
- setAction(&_sequenceManager, scene, 1976, NULL);
- }
-}
-
-void Scene1950::postInit(SceneObjectList *OwnerList) {
- _upExitStyle = false;
- _removeFlag = false;
- _vampireActive = false;
- _vampireIndex = 0;
- if (R2_GLOBALS._sceneManager._previousScene == 300)
- R2_GLOBALS._flubMazeArea = 103;
-
- initArea();
- SceneExt::postInit();
- R2_GLOBALS._sound1.play(105);
-
- _northExit.setDetails(Rect(130, 46, 189, 135), SHADECURSOR_UP, 1950);
- _northExit.setDest(Common::Point(160, 145));
-
- _upExit.setDetails(Rect(208, 0, 255, 73), EXITCURSOR_N, 1950);
- _upExit.setDest(Common::Point(200, 151));
-
- _eastExit.setDetails(Rect(305, 95, 320, 147), EXITCURSOR_E, 1950);
- _eastExit.setDest(Common::Point(312, 160));
-
- _downExit.setDetails(Rect(208, 99, 255, 143), EXITCURSOR_S, 1950);
- _downExit.setDest(Common::Point(200, 151));
-
- _southExit.setDetails(Rect(113, 154, 206, 168), SHADECURSOR_DOWN, 1950);
- _southExit.setDest(Common::Point(160, 165));
-
- _westExit.setDetails(Rect(0, 95, 14, 147), EXITCURSOR_W, 1950);
- _westExit.setDest(Common::Point(7, 160));
-
- _shaftExit.setDetails(Rect(72, 54, 120, 128), EXITCURSOR_NW, 1950);
- _shaftExit.setDest(Common::Point(120, 140));
-
- _doorExit.setDetails(Rect(258, 60, 300, 145), EXITCURSOR_NE, 1950);
- _doorExit.setDest(Common::Point(268, 149));
-
- R2_GLOBALS._player.postInit();
- if ( (R2_INVENTORY.getObjectScene(R2_TANNER_MASK) == 0) && (R2_INVENTORY.getObjectScene(R2_PURE_GRAIN_ALCOHOL) == 0)
- && (R2_INVENTORY.getObjectScene(R2_SOAKED_FACEMASK) == 0) && (!R2_GLOBALS.getFlag(36)) )
- R2_GLOBALS._player.setVisage(22);
- else
- R2_GLOBALS._player.setVisage(20);
-
- R2_GLOBALS._player._moveDiff = Common::Point(5, 3);
- _background.setDetails(Rect(0, 0, 320, 200), 1950, 0, 1, 2, 1, NULL);
-
- enterArea();
-}
-
-void Scene1950::remove() {
- R2_GLOBALS._sound1.stop();
- R2_GLOBALS._sound2.fadeOut2(NULL);
- SceneExt::remove();
-}
-
-void Scene1950::signal() {
- switch (_sceneMode) {
- case 11:
- R2_GLOBALS._flubMazeArea += 7;
- initArea();
- enterArea();
- break;
- case 12:
- // Moving up a ladder within the Flub maze
- R2_GLOBALS._flubMazeArea += 35;
- initArea();
- enterArea();
- break;
- case 1975:
- SceneItem::display(1950, 21, SET_WIDTH, 280, SET_X, 160, SET_POS_MODE, 1,
- SET_Y, 20, SET_EXT_BGCOLOR, 7, LIST_END);
- // No break on purpose
- case 13:
- // Moving east within the Flub maze
- ++R2_GLOBALS._flubMazeArea;
- initArea();
- enterArea();
- break;
- case 14:
- // Moving down a ladder within the Flub maze
- R2_GLOBALS._flubMazeArea -= 35;
- initArea();
- enterArea();
- break;
- case 15:
- R2_GLOBALS._flubMazeArea -= 7;
- initArea();
- enterArea();
- break;
- case 16:
- // Moving west within the Flub maze
- // No break on purpose
- case 1961:
- --R2_GLOBALS._flubMazeArea;
- initArea();
- enterArea();
- break;
- case 17: {
- _sceneMode = 13;
- R2_GLOBALS._flubMazeEntryDirection = 3;
- _vampireActive = false;
- R2_GLOBALS._player.disableControl(CURSOR_WALK);
- R2_GLOBALS._player._canWalk = true;
- R2_GLOBALS._player.setVisage(22);
- R2_GLOBALS._player.animate(ANIM_MODE_9);
- Common::Point pt(340, 160);
- NpcMover *mover = new NpcMover();
- R2_GLOBALS._player.addMover(mover, &pt, this);
- Common::Point pt2(289, 160);
- NpcMover *mover2 = new NpcMover();
- _vampire.addMover(mover2, &pt2, NULL);
- }
- break;
- case 18: {
- _sceneMode = 16;
- R2_GLOBALS._flubMazeEntryDirection = 6;
- _vampireActive = false;
- R2_GLOBALS._player.disableControl(CURSOR_WALK);
- R2_GLOBALS._player._canWalk = true;
- R2_GLOBALS._player.setVisage(22);
- R2_GLOBALS._player.animate(ANIM_MODE_9);
- Common::Point pt(-20, 160);
- NpcMover *mover = new NpcMover();
- R2_GLOBALS._player.addMover(mover, &pt, this);
- Common::Point pt2(30, 160);
- NpcMover *mover2 = new NpcMover();
- _vampire.addMover(mover2, &pt2, NULL);
- }
- break;
- case 24:
- _KeypadWindow.remove();
- _sceneMode = 1966;
- _cube.setFrame(3);
- setAction(&_sequenceManager, this, 1966, &_containmentField, &_gem, NULL);
- break;
- case 1951:
- R2_GLOBALS._sound1.fadeOut2(NULL);
- R2_GLOBALS._sceneManager.changeScene(1945);
- break;
- case 1958:
- SceneItem::display(1950, 24, 0, 280, 1, 160, 9, 1, 2, 20, 7, 7, LIST_END);
- R2_GLOBALS._player.enableControl(CURSOR_WALK);
- _doorExit._enabled = true;
- break;
- case 1959:
- R2_INVENTORY.setObjectScene(R2_SOAKED_FACEMASK, 0);
- R2_GLOBALS._player.enableControl(CURSOR_WALK);
- _doorExit._enabled = true;
- break;
- case 1962:
- // No break on purpose
- case 1963:
- R2_GLOBALS._player.enableControl();
- _KeypadWindow.setup2(1971, 1, 1, 160, 135);
- break;
- case 1964:
- // No break on purpose
- case 1965:
- if (!R2_GLOBALS.getFlag(37))
- SceneItem::display(1950, 26, 0, 280, 1, 160, 9, 1, 2, 20, 7, 7, LIST_END);
-
- R2_GLOBALS._player.enableControl();
- break;
- case 1966:
- _containmentField.remove();
- if (R2_GLOBALS.getFlag(36)) {
- _sceneMode = 1964;
- setAction(&_sequenceManager, this, 1964, &R2_GLOBALS._player, NULL);
- } else {
- _sceneMode = 1965;
- setAction(&_sequenceManager, this, 1965, &R2_GLOBALS._player, NULL);
- }
- _gem.setDetails(1950, 9, -1, -1, 2, (SceneItem *) NULL);
- break;
- case 1967: {
- _sceneMode = 0;
- R2_INVENTORY.setObjectScene(R2_SAPPHIRE_BLUE, 2);
- _gem.remove();
- if (R2_GLOBALS.getFlag(36))
- R2_GLOBALS._player.setVisage(20);
- else
- R2_GLOBALS._player.setVisage(22);
-
- R2_GLOBALS._player.animate(ANIM_MODE_1, NULL);
- // This is a hack to work around a pathfinding issue. original destination is (218, 165)
- Common::Point pt(128, 165);
- NpcMover *mover = new NpcMover();
- R2_GLOBALS._player.addMover(mover, &pt, this);
- }
- break;
- case 1968:
- R2_GLOBALS._player.enableControl();
- R2_INVENTORY.setObjectScene(R2_ANCIENT_SCROLLS, 2);
- _scrolls.setFrame(2);
- if (R2_GLOBALS.getFlag(36))
- R2_GLOBALS._player.setVisage(20);
- else
- R2_GLOBALS._player.setVisage(22);
- R2_GLOBALS._player.animate(ANIM_MODE_1, NULL);
- break;
- default:
- R2_GLOBALS._player.enableControl(CURSOR_WALK);
- break;
- }
-}
-
-void Scene1950::process(Event &event) {
- if ( (event.eventType == EVENT_BUTTON_DOWN)
- && (R2_GLOBALS._player._uiEnabled)
- && (R2_GLOBALS._events.getCursor() == R2_SOAKED_FACEMASK)
- && (R2_GLOBALS._player._bounds.contains(event.mousePos))
- && (R2_INVENTORY.getObjectScene(R2_SCRITH_KEY) == 0)) {
- event.handled = true;
- R2_GLOBALS._player.disableControl();
- _shaftExit._enabled = false;
- _doorExit._enabled = false;
- _sceneMode = 1959;
- setAction(&_sequenceManager, this, 1959, &R2_GLOBALS._player, NULL);
- }
-
- Scene::process(event);
-}
-
} // End of namespace Ringworld2
} // End of namespace TsAGE
diff --git a/engines/tsage/ringworld2/ringworld2_scenes1.h b/engines/tsage/ringworld2/ringworld2_scenes1.h
index 91c4b88391..e6f5e0ab97 100644
--- a/engines/tsage/ringworld2/ringworld2_scenes1.h
+++ b/engines/tsage/ringworld2/ringworld2_scenes1.h
@@ -135,270 +135,6 @@ public:
virtual void saveCharacter(int characterIndex);
};
-class Scene1200 : public SceneExt {
- enum CrawlDirection { CRAWL_EAST = 1, CRAWL_WEST = 2, CRAWL_SOUTH = 3, CRAWL_NORTH = 4 };
-
- class LaserPanel: public ModalWindow {
- public:
- class Jumper : public SceneActorExt {
- public:
- void init(int state);
- virtual bool startAction(CursorType action, Event &event);
- };
-
- Jumper _jumper1;
- Jumper _jumper2;
- Jumper _jumper3;
-
- LaserPanel();
-
- virtual void postInit(SceneObjectList *OwnerList = NULL);
- virtual void remove();
- };
-
-public:
- NamedHotspot _item1;
- SceneActor _actor1;
- LaserPanel _laserPanel;
- MazeUI _mazeUI;
- SequenceManager _sequenceManager;
-
- int _nextCrawlDirection;
- int _field414;
- int _field416;
- int _field418;
- int _field41A;
- bool _fixupMaze;
-
- Scene1200();
- void synchronize(Serializer &s);
-
- void startCrawling(CrawlDirection dir);
-
- virtual void postInit(SceneObjectList *OwnerList = NULL);
- virtual void signal();
- virtual void process(Event &event);
- virtual void dispatch();
- virtual void saveCharacter(int characterIndex);
-};
-
-class Scene1337 : public SceneExt {
- class OptionsDialog: public GfxDialog {
- private:
- GfxButton _autoplay;
- GfxButton _restartGame;
- GfxButton _quitGame;
- GfxButton _continueGame;
-
- OptionsDialog();
- virtual ~OptionsDialog() {}
- virtual GfxButton *execute(GfxButton *defaultButton);
- public:
- static void show();
- };
-
- class Card: public SceneHotspot {
- public:
- SceneObject _card;
-
- int _cardId;
- Common::Point _stationPos;
-
- Card();
- void synchronize(Serializer &s);
- bool isIn(Common::Point pt);
- };
-
- class GameBoardSide: public SceneHotspot {
- public:
- Card _handCard[4];
- Card _outpostStation[8];
- Card _delayCard;
- Card _emptyStationPos;
-
- Common::Point _card1Pos;
- Common::Point _card2Pos;
- Common::Point _card3Pos;
- Common::Point _card4Pos;
- int _frameNum;
-
- GameBoardSide();
- void synchronize(Serializer &s);
- };
-
- class Action1337: public Action {
- public:
- void waitFrames(int32 frameCount);
- };
-
- class Action1: public Action1337 {
- public:
- void signal();
- };
- class Action2: public Action1337 {
- public:
- void signal();
- };
- class Action3: public Action1337 {
- public:
- void signal();
- };
- class Action4: public Action1337 {
- public:
- void signal();
- };
- class Action5: public Action1337 {
- public:
- void signal();
- };
- class Action6: public Action1337 {
- public:
- void signal();
- };
- class Action7: public Action1337 {
- public:
- void signal();
- };
- class Action8: public Action1337 {
- public:
- void signal();
- };
- class Action9: public Action1337 {
- public:
- void signal();
- };
- class Action10: public Action1337 {
- public:
- void signal();
- };
- class Action11: public Action1337 {
- public:
- void signal();
- };
- class Action12: public Action1337 {
- public:
- void signal();
- };
- class Action13: public Action1337 {
- public:
- void signal();
- };
-public:
- Action1 _action1;
- Action2 _action2;
- Action3 _action3;
- Action4 _action4;
- Action5 _action5;
- Action6 _action6;
- Action7 _action7;
- Action8 _action8;
- Action9 _action9;
- Action10 _action10;
- Action11 _action11;
- Action12 _action12;
- Action13 _action13;
-
- typedef void (Scene1337::*FunctionPtrType)();
- FunctionPtrType _delayedFunction;
-
- bool _autoplay;
- bool _shuffleEndedFl;
- bool _showPlayerTurn;
- bool _displayHelpFl;
- bool _instructionsDisplayedFl;
-
- // Discarded cards are put in the available cards pile, with an higher index so there no conflict
- int _currentDiscardIndex;
- int _availableCardsPile[100];
- int _cardsAvailableNumb;
- int _currentPlayerNumb;
- int _actionIdx1;
- int _actionIdx2;
- int _winnerId;
- int _instructionsWaitCount;
- int _cursorCurRes;
- int _cursorCurStrip;
- int _cursorCurFrame;
-
- ASound _aSound1;
- ASound _aSound2;
- GameBoardSide _gameBoardSide[4];
- SceneActor _helpIcon;
- SceneActor _stockPile;
- SceneItem _actionItem;
- SceneObject _currentPlayerArrow;
-
- Card *_actionCard1;
- Card *_actionCard2;
- Card *_actionCard3;
- Card _animatedCard;
- Card _shuffleAnimation;
- Card _discardedPlatformCard;
- Card _selectedCard;
- Card _discardPile;
- Card _stockCard;
-
- SceneObject _upperDisplayCard[8];
- SceneObject _lowerDisplayCard[8];
-
- Scene1337();
- virtual void synchronize(Serializer &s);
-
- void actionDisplay(int resNum, int lineNum, int x, int y, int keepOnScreen, int width, int textMode, int fontNum, int colFG, int colBGExt, int colFGExt);
- void setAnimationInfo(Card *card);
- void handleNextTurn();
- void handlePlayerTurn();
- bool isStationCard(int cardId);
- bool isStopConstructionCard(int cardId);
- int getStationId(int playerId, int handCardId);
- int findPlatformCardInHand(int playerId);
- int findCard13InHand(int playerId);
- int checkThieftCard(int playerId);
- int isDelayCard(int cardId);
- int getStationCardId(int cardId);
- void handlePlayer01Discard(int playerId);
- void playThieftCard(int playerId, Card *card, int victimId);
- int getPreventionCardId(int cardId);
- bool isAttackPossible(int victimId, int cardId);
- int getPlayerWithOutpost(int playerId);
- bool checkAntiDelayCard(int delayCardId, int cardId);
- void playStationCard(Card *station, Card *platform);
- void playDelayCard(Card *card, Card *dest);
- void playPlatformCard(Card *card, Card *dest);
- void playAntiDelayCard(Card *card, Card *dest);
- Card *getStationCard(int arg1);
- void playCounterTrickCard(Card *card, int playerId);
- int getFreeHandCard(int playerId);
- void discardCard(Card *card);
- void subC4CD2();
- void subC4CEC();
- void subC51A0(Card *subObj1, Card *subObj2);
- void displayDialog(int dialogNumb);
- void subPostInit();
- void displayInstructions();
- void suggestInstructions();
- void shuffleCards();
- void dealCards();
- void showOptionsDialog();
- void handleClick(int arg1, Common::Point pt);
- void handlePlayer0();
- void handlePlayer1();
- void handlePlayer2();
- void handlePlayer3();
- void handleAutoplayPlayer2();
- void updateCursorId(int arg1, bool arg2);
- void setCursorData(int resNum, int rlbNum, int frameNum);
- void subD18F5();
- void subD1917();
- void subD1940(bool flag);
- void subD1975(int arg1, int arg2);
-
- virtual void postInit(SceneObjectList *OwnerList = NULL);
- virtual void remove();
- virtual void process(Event &event);
- virtual void dispatch();
-};
-
class Scene1500 : public SceneExt {
public:
SceneActor _starship;
@@ -1097,143 +833,6 @@ public:
virtual void signal();
};
-class Scene1950 : public SceneExt {
- /* Windows */
- class KeypadWindow: public ModalWindow {
- public:
- class KeypadButton : public SceneActor {
- public:
- int _buttonIndex;
- bool _pressed;
- bool _toggled;
-
- KeypadButton();
- void synchronize(Serializer &s);
-
- void init(int indx);
- virtual void process(Event &event);
- virtual bool startAction(CursorType action, Event &event);
- };
-
- SceneActor _areaActor;
- KeypadButton _buttons[16];
-
- int _buttonIndex;
-
- KeypadWindow();
- virtual void synchronize(Serializer &s);
- virtual void remove();
- virtual void setup2(int visage, int stripFrameNum, int frameNum, int posX, int posY);
- virtual void setup3(int resNum, int lookLineNum, int talkLineNum, int useLineNum);
- };
-
- class Keypad : public NamedHotspot {
- public:
- virtual bool startAction(CursorType action, Event &event);
- };
-
- /* Actors */
- class Door : public SceneActor {
- public:
- virtual bool startAction(CursorType action, Event &event);
- };
- class Scrolls : public SceneActor {
- public:
- virtual bool startAction(CursorType action, Event &event);
- };
- class Gem : public SceneActor {
- public:
- virtual bool startAction(CursorType action, Event &event);
- };
- class Vampire : public SceneActor {
- public:
- Common::Point _deadPosition;
- int _deltaX;
- int _deltaY;
- int _vampireMode;
-
- Vampire();
- void synchronize(Serializer &s);
-
- virtual void signal();
- virtual bool startAction(CursorType action, Event &event);
- };
-
- /* Exits */
- class NorthExit : public SceneExit {
- public:
- virtual void changeScene();
- };
- class UpExit : public SceneExit {
- public:
- virtual void changeScene();
- };
- class EastExit : public SceneExit {
- public:
- virtual void changeScene();
- };
- class DownExit : public SceneExit {
- public:
- virtual void changeScene();
- };
- class SouthExit : public SceneExit {
- public:
- virtual void changeScene();
- };
- class WestExit : public SceneExit {
- public:
- virtual void changeScene();
- };
- class ShaftExit : public SceneExit {
- public:
- virtual void changeScene();
- };
- class DoorExit : public SceneExit {
- public:
- virtual void changeScene();
- };
-private:
- void initArea();
- void enterArea();
- void doButtonPress(int indx);
-public:
- NamedHotspot _background;
- Keypad _keypad;
- SceneActor _southDoorway;
- SceneObject _northDoorway;
- Door _door;
- Scrolls _scrolls;
- SceneActor _containmentField;
- Gem _gem;
- SceneActor _cube;
- SceneActor _pulsingLights;
- Vampire _vampire;
- KeypadWindow _KeypadWindow;
- NorthExit _northExit;
- UpExit _upExit;
- EastExit _eastExit;
- DownExit _downExit;
- SouthExit _southExit;
- WestExit _westExit;
- ShaftExit _shaftExit;
- DoorExit _doorExit;
- SequenceManager _sequenceManager;
-
- bool _upExitStyle;
- bool _removeFlag;
- bool _vampireActive;
- Common::Point _vampireDestPos;
- int _vampireIndex;
-
- Scene1950();
- void synchronize(Serializer &s);
-
- virtual void postInit(SceneObjectList *OwnerList = NULL);
- virtual void remove();
- virtual void signal();
- virtual void process(Event &event);
-};
-
} // End of namespace Ringworld2
} // End of namespace TsAGE
diff --git a/engines/tsage/ringworld2/ringworld2_scenes3.cpp b/engines/tsage/ringworld2/ringworld2_scenes3.cpp
index 9eaead630b..8610e0c8bc 100644
--- a/engines/tsage/ringworld2/ringworld2_scenes3.cpp
+++ b/engines/tsage/ringworld2/ringworld2_scenes3.cpp
@@ -3878,7 +3878,7 @@ void Scene3500::dispatch() {
Scene::dispatch();
// WORKAROUND: The _mazeUI wasn't originally added to the scene in postInit.
- // This is only needed to fix old savegames
+ // This is only needed to fix old savegames
if (!R2_GLOBALS._sceneObjects->contains(&_mazeUI))
_mazeUI.draw();
diff --git a/engines/tsage/ringworld2/ringworld2_vampire.cpp b/engines/tsage/ringworld2/ringworld2_vampire.cpp
new file mode 100644
index 0000000000..9d3b7f91a5
--- /dev/null
+++ b/engines/tsage/ringworld2/ringworld2_vampire.cpp
@@ -0,0 +1,1821 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public 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 "tsage/ringworld2/ringworld2_vampire.h"
+
+namespace TsAGE {
+
+namespace Ringworld2 {
+
+/*--------------------------------------------------------------------------
+ * Scene 1950 - Flup Tube Corridor Maze
+ *
+ *--------------------------------------------------------------------------*/
+
+Scene1950::KeypadWindow::KeypadWindow() {
+ _buttonIndex = 0;
+}
+
+void Scene1950::KeypadWindow::synchronize(Serializer &s) {
+ SceneArea::synchronize(s);
+
+ s.syncAsSint16LE(_buttonIndex);
+}
+
+Scene1950::KeypadWindow::KeypadButton::KeypadButton() {
+ _buttonIndex = 0;
+ _pressed = false;
+ _toggled = false;
+}
+
+void Scene1950::KeypadWindow::KeypadButton::synchronize(Serializer &s) {
+ SceneActor::synchronize(s);
+
+ s.syncAsSint16LE(_buttonIndex);
+ s.syncAsSint16LE(_pressed);
+ s.syncAsSint16LE(_toggled);
+}
+
+void Scene1950::KeypadWindow::KeypadButton::init(int indx) {
+ Scene1950 *scene = (Scene1950 *)R2_GLOBALS._sceneManager._scene;
+
+ _buttonIndex = indx;
+ _pressed = false;
+ _toggled = false;
+
+ postInit();
+ setup(1971, 2, 1);
+ fixPriority(249);
+ setPosition(Common::Point(((_buttonIndex % 4) * 22) + 127, ((_buttonIndex / 4) * 19) + 71));
+ scene->_sceneAreas.push_front(this);
+}
+
+void Scene1950::KeypadWindow::KeypadButton::process(Event &event) {
+ if ((event.eventType == EVENT_BUTTON_DOWN) && (R2_GLOBALS._events.getCursor() == CURSOR_USE)
+ && (_bounds.contains(event.mousePos)) && !_pressed) {
+ R2_GLOBALS._sound2.play(227);
+ if (!_toggled) {
+ setFrame(2);
+ _toggled = true;
+ } else {
+ setFrame(1);
+ _toggled = false;
+ }
+ _pressed = true;
+ event.handled = true;
+ }
+
+ if ((event.eventType == EVENT_BUTTON_UP) && _pressed) {
+ _pressed = false;
+ event.handled = true;
+ Scene1950 *scene = (Scene1950 *)R2_GLOBALS._sceneManager._scene;
+ scene->doButtonPress(_buttonIndex);
+ }
+}
+
+bool Scene1950::KeypadWindow::KeypadButton::startAction(CursorType action, Event &event) {
+ if (action == CURSOR_USE)
+ return false;
+ return SceneActor::startAction(action, event);
+}
+
+void Scene1950::KeypadWindow::remove() {
+ Scene1950 *scene = (Scene1950 *)R2_GLOBALS._sceneManager._scene;
+ for (_buttonIndex = 0; _buttonIndex < 16; ++_buttonIndex) {
+ scene->_sceneAreas.remove(&_buttons[_buttonIndex]);
+ _buttons[_buttonIndex].remove();
+ }
+
+ ModalWindow::remove();
+
+ if (!R2_GLOBALS.getFlag(37))
+ R2_GLOBALS._sound2.play(278);
+
+ R2_GLOBALS._player.disableControl(CURSOR_WALK);
+ scene->_eastExit._enabled = true;
+
+ if (!R2_GLOBALS.getFlag(37)) {
+ if (R2_GLOBALS.getFlag(36)) {
+ scene->_sceneMode = 1964;
+ scene->setAction(&scene->_sequenceManager, scene, 1964, &R2_GLOBALS._player, NULL);
+ } else {
+ scene->_sceneMode = 1965;
+ scene->setAction(&scene->_sequenceManager, scene, 1965, &R2_GLOBALS._player, NULL);
+ }
+ }
+}
+
+void Scene1950::KeypadWindow::setup2(int visage, int stripFrameNum, int frameNum, int posX, int posY) {
+ Scene1950 *scene = (Scene1950 *)R2_GLOBALS._sceneManager._scene;
+
+ if (R2_GLOBALS._player._mover)
+ R2_GLOBALS._player.addMover(NULL);
+ R2_GLOBALS._player._canWalk = false;
+
+ ModalWindow::setup2(visage, stripFrameNum, frameNum, posX, posY);
+
+ _object1.fixPriority(248);
+ scene->_eastExit._enabled = false;
+ setup3(1950, 27, 28, 27);
+
+ for (_buttonIndex = 0; _buttonIndex < 16; _buttonIndex++)
+ _buttons[_buttonIndex].init(_buttonIndex);
+}
+
+void Scene1950::KeypadWindow::setup3(int resNum, int lookLineNum, int talkLineNum, int useLineNum) {
+ // Copy of Scene1200::LaserPanel::proc13()
+ _areaActor.setDetails(resNum, lookLineNum, talkLineNum, useLineNum, 2, (SceneItem *) NULL);
+}
+
+/*--------------------------------------------------------------------------*/
+
+bool Scene1950::Keypad::startAction(CursorType action, Event &event) {
+ if ((action != CURSOR_USE) || (R2_GLOBALS.getFlag(37)))
+ return SceneHotspot::startAction(action, event);
+
+ Scene1950 *scene = (Scene1950 *)R2_GLOBALS._sceneManager._scene;
+
+ R2_GLOBALS._player.disableControl();
+ if (R2_GLOBALS.getFlag(36)) {
+ scene->_sceneMode = 1962;
+ scene->setAction(&scene->_sequenceManager, scene, 1962, &R2_GLOBALS._player, NULL);
+ } else {
+ scene->_sceneMode = 1963;
+ scene->setAction(&scene->_sequenceManager, scene, 1963, &R2_GLOBALS._player, NULL);
+ }
+ return true;
+}
+
+bool Scene1950::Door::startAction(CursorType action, Event &event) {
+ if (action != R2_SCRITH_KEY)
+ return SceneActor::startAction(action, event);
+
+ Scene1950 *scene = (Scene1950 *)R2_GLOBALS._sceneManager._scene;
+
+ R2_GLOBALS._player.disableControl();
+ R2_INVENTORY.setObjectScene(R2_SCRITH_KEY, 0);
+ scene->_sceneMode = 1958;
+ scene->setAction(&scene->_sequenceManager, scene, 1958, &R2_GLOBALS._player, &scene->_door, NULL);
+ return true;
+}
+
+bool Scene1950::Scrolls::startAction(CursorType action, Event &event) {
+ if ((action != CURSOR_USE) || (R2_INVENTORY.getObjectScene(R2_ANCIENT_SCROLLS) != 1950))
+ return SceneActor::startAction(action, event);
+
+ Scene1950 *scene = (Scene1950 *)R2_GLOBALS._sceneManager._scene;
+
+ R2_GLOBALS._player.disableControl();
+ scene->_sceneMode = 1968;
+ scene->setAction(&scene->_sequenceManager, scene, 1968, &R2_GLOBALS._player, NULL);
+
+ return true;
+}
+
+bool Scene1950::Gem::startAction(CursorType action, Event &event) {
+ if ((action != CURSOR_USE) || (!R2_GLOBALS.getFlag(37)))
+ return SceneActor::startAction(action, event);
+
+ Scene1950 *scene = (Scene1950 *)R2_GLOBALS._sceneManager._scene;
+
+ R2_GLOBALS._player.disableControl();
+ scene->_sceneMode = 1967;
+ scene->setAction(&scene->_sequenceManager, scene, 1967, &R2_GLOBALS._player, NULL);
+
+ return true;
+}
+
+/*--------------------------------------------------------------------------*/
+
+Scene1950::Vampire::Vampire() {
+ _deadPosition = Common::Point(0, 0);
+ _deltaX = 0;
+ _deltaY = 0;
+ _vampireMode = 0;
+}
+
+void Scene1950::Vampire::synchronize(Serializer &s) {
+ SceneActor::synchronize(s);
+
+ s.syncAsSint16LE(_deadPosition.x);
+ s.syncAsSint16LE(_deadPosition.y);
+ s.syncAsSint16LE(_deltaX);
+ s.syncAsSint16LE(_deltaY);
+ s.syncAsSint16LE(_vampireMode);
+}
+
+void Scene1950::Vampire::signal() {
+ Scene1950 *scene = (Scene1950 *)R2_GLOBALS._sceneManager._scene;
+
+ switch (_vampireMode) {
+ case 19: {
+ _vampireMode = 0;
+ setVisage(1960);
+ if (R2_GLOBALS._flubMazeEntryDirection == 3)
+ setStrip(2);
+ else
+ setStrip(1);
+
+ NpcMover *mover = new NpcMover();
+ addMover(mover, &scene->_vampireDestPos, scene);
+ }
+ break;
+ case 20: {
+ // Non fatal shot
+ _vampireMode = 19;
+ R2_GLOBALS._player.setVisage(22);
+ if (R2_GLOBALS._flubMazeEntryDirection == 3)
+ R2_GLOBALS._player.setStrip(1);
+ else
+ R2_GLOBALS._player.setStrip(2);
+ R2_GLOBALS._player.animate(ANIM_MODE_1, NULL);
+ R2_GLOBALS._vampireData[scene->_vampireIndex - 1]._shotsRequired--;
+
+ if (R2_GLOBALS._flubMazeEntryDirection == 3)
+ _deadPosition.x = _position.x + 10;
+ else
+ _deadPosition.x = _position.x - 10;
+ _deadPosition.y = _position.y - 4;
+
+ setVisage(1961);
+
+ if (R2_GLOBALS._flubMazeEntryDirection == 3)
+ setStrip(2);
+ else
+ setStrip(1);
+
+ animate(ANIM_MODE_2, NULL);
+ Common::Point pt = _deadPosition;
+ PlayerMover *mover = new PlayerMover();
+ addMover(mover, &pt, this);
+
+ R2_GLOBALS._player.enableControl();
+ }
+ break;
+ case 21: {
+ // Fatal shot
+ R2_GLOBALS._player.setVisage(22);
+ if (R2_GLOBALS._flubMazeEntryDirection == 3)
+ R2_GLOBALS._player.setStrip(1);
+ else
+ R2_GLOBALS._player.setStrip(2);
+ R2_GLOBALS._player.animate(ANIM_MODE_1, NULL);
+
+ setVisage(1961);
+ if (R2_GLOBALS._flubMazeEntryDirection == 3)
+ setStrip(4);
+ else
+ setStrip(3);
+ setDetails(1950, 15, -1, 17, 2, (SceneItem *) NULL);
+ addMover(NULL);
+ _numFrames = 8;
+ R2_GLOBALS._sound2.play(226);
+ animate(ANIM_MODE_5, NULL);
+ fixPriority(10);
+
+ R2_GLOBALS._vampireData[scene->_vampireIndex - 1]._isAlive = false;
+ R2_GLOBALS._vampireData[scene->_vampireIndex - 1]._shotsRequired--;
+ R2_GLOBALS._vampireData[scene->_vampireIndex - 1]._position = _position;
+ _deltaX = (_position.x - R2_GLOBALS._player._position.x) / 2;
+ _deltaY = (_position.y - R2_GLOBALS._player._position.y) / 2;
+
+ byte vampireCount = 0;
+ for (byte i = 0; i < 18; ++i) {
+ if (!R2_GLOBALS._vampireData[i]._isAlive)
+ ++vampireCount;
+ }
+
+ if (vampireCount == 18) {
+ R2_GLOBALS.setFlag(36);
+ _vampireMode = 23;
+ Common::Point pt(R2_GLOBALS._player._position.x + _deltaX, R2_GLOBALS._player._position.y + _deltaY);
+ NpcMover *mover = new NpcMover();
+ R2_GLOBALS._player.addMover(mover, &pt, this);
+ } else if (vampireCount == 1) {
+ _vampireMode = 22;
+ Common::Point pt(R2_GLOBALS._player._position.x + _deltaX, R2_GLOBALS._player._position.y + _deltaY);
+ NpcMover *mover = new NpcMover();
+ R2_GLOBALS._player.addMover(mover, &pt, this);
+ } else {
+ R2_GLOBALS._player.enableControl(CURSOR_WALK);
+ }
+
+ if (R2_GLOBALS._flubMazeEntryDirection == 3)
+ scene->_eastExit._enabled = true;
+ else
+ scene->_westExit._enabled = true;
+
+ scene->_vampireActive = false;
+ }
+ break;
+ case 22:
+ SceneItem::display(1950, 18, 0, 280, 1, 160, 9, 1, 2, 20, 7, 7, LIST_END);
+ R2_GLOBALS._player.enableControl(CURSOR_WALK);
+ break;
+ case 23:
+ SceneItem::display(1950, 25, 0, 280, 1, 160, 9, 1, 2, 20, 7, 7, LIST_END);
+ scene->_sceneMode = R2_GLOBALS._flubMazeEntryDirection;
+ scene->setAction(&scene->_sequenceManager, scene, 1960, &R2_GLOBALS._player, NULL);
+ break;
+ default:
+ break;
+ }
+}
+
+bool Scene1950::Vampire::startAction(CursorType action, Event &event) {
+ Scene1950 *scene = (Scene1950 *)R2_GLOBALS._sceneManager._scene;
+
+ if (!R2_GLOBALS._vampireData[scene->_vampireIndex - 1]._isAlive ||
+ (action != R2_PHOTON_STUNNER))
+ return SceneActor::startAction(action, event);
+
+ R2_GLOBALS._player.disableControl();
+
+ if (R2_GLOBALS._vampireData[scene->_vampireIndex - 1]._shotsRequired <= 1)
+ _vampireMode = 21;
+ else
+ _vampireMode = 20;
+
+ R2_GLOBALS._player.setVisage(25);
+ if (R2_GLOBALS._flubMazeEntryDirection == 3)
+ R2_GLOBALS._player.setStrip(2);
+ else
+ R2_GLOBALS._player.setStrip(1);
+ R2_GLOBALS._player.animate(ANIM_MODE_5, this);
+ R2_GLOBALS._sound3.play(99);
+
+ return true;
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Scene1950::NorthExit::changeScene() {
+ Scene1950 *scene = (Scene1950 *)R2_GLOBALS._sceneManager._scene;
+
+ _enabled = false;
+ R2_GLOBALS._player.disableControl(CURSOR_WALK);
+ R2_GLOBALS._flubMazeEntryDirection = 1;
+ scene->_sceneMode = 11;
+
+ Common::Point pt(160, 127);
+ PlayerMover *mover = new PlayerMover();
+ R2_GLOBALS._player.addMover(mover, &pt, scene);
+}
+
+void Scene1950::UpExit::changeScene() {
+ Scene1950 *scene = (Scene1950 *)R2_GLOBALS._sceneManager._scene;
+
+ _enabled = false;
+ R2_GLOBALS._player.disableControl(CURSOR_WALK);
+ R2_GLOBALS._flubMazeEntryDirection = 2;
+ scene->_sceneMode = 12;
+
+ if (!scene->_upExitStyle) {
+ if (R2_GLOBALS.getFlag(36))
+ scene->setAction(&scene->_sequenceManager, scene, 1953, &R2_GLOBALS._player, NULL);
+ else
+ scene->setAction(&scene->_sequenceManager, scene, 1970, &R2_GLOBALS._player, NULL);
+ } else {
+ if (R2_GLOBALS.getFlag(36))
+ scene->setAction(&scene->_sequenceManager, scene, 1952, &R2_GLOBALS._player, NULL);
+ else
+ scene->setAction(&scene->_sequenceManager, scene, 1969, &R2_GLOBALS._player, NULL);
+ }
+}
+
+void Scene1950::EastExit::changeScene() {
+ Scene1950 *scene = (Scene1950 *)R2_GLOBALS._sceneManager._scene;
+
+ _enabled = false;
+ R2_GLOBALS._player.disableControl(CURSOR_WALK);
+ R2_GLOBALS._flubMazeEntryDirection = 3;
+ scene->_sceneMode = 13;
+
+ if (scene->_vampireActive)
+ R2_GLOBALS._player.animate(ANIM_MODE_9);
+
+ Common::Point pt(340, 160);
+ NpcMover *mover = new NpcMover();
+ R2_GLOBALS._player.addMover(mover, &pt, scene);
+}
+
+void Scene1950::DownExit::changeScene() {
+ Scene1950 *scene = (Scene1950 *)R2_GLOBALS._sceneManager._scene;
+
+ _enabled = false;
+ R2_GLOBALS._player.disableControl(CURSOR_WALK);
+ R2_GLOBALS._flubMazeEntryDirection = 4;
+ scene->_sceneMode = 14;
+
+ if (R2_GLOBALS.getFlag(36))
+ scene->setAction(&scene->_sequenceManager, scene, 1956, &R2_GLOBALS._player, NULL);
+ else
+ scene->setAction(&scene->_sequenceManager, scene, 1973, &R2_GLOBALS._player, NULL);
+}
+
+void Scene1950::SouthExit::changeScene() {
+ Scene1950 *scene = (Scene1950 *)R2_GLOBALS._sceneManager._scene;
+
+ _enabled = false;
+ R2_GLOBALS._player.disableControl(CURSOR_WALK);
+ R2_GLOBALS._flubMazeEntryDirection = 5;
+ scene->_sceneMode = 15;
+
+ Common::Point pt(160, 213);
+ NpcMover *mover = new NpcMover();
+ R2_GLOBALS._player.addMover(mover, &pt, scene);
+}
+
+void Scene1950::WestExit::changeScene() {
+ Scene1950 *scene = (Scene1950 *)R2_GLOBALS._sceneManager._scene;
+
+ _enabled = false;
+ R2_GLOBALS._player.disableControl(CURSOR_WALK);
+ R2_GLOBALS._flubMazeEntryDirection = 6;
+
+ if (R2_GLOBALS._flubMazeArea == 2) {
+ // In the very first corridor area after the Scrith Door
+ if ((R2_GLOBALS.getFlag(36)) && (R2_INVENTORY.getObjectScene(R2_SAPPHIRE_BLUE) == 2) && (R2_INVENTORY.getObjectScene(R2_ANCIENT_SCROLLS) == 2)) {
+ scene->_sceneMode = 1961;
+ Common::Point pt(-20, 160);
+ NpcMover *mover = new NpcMover();
+ R2_GLOBALS._player.addMover(mover, &pt, scene);
+ } else {
+ if (!R2_GLOBALS.getFlag(36))
+ SceneItem::display(1950, 33, 0, 280, 1, 160, 9, 1, 2, 20, 7, 7, LIST_END);
+ if ((R2_INVENTORY.getObjectScene(R2_SAPPHIRE_BLUE) == 1950) || (R2_INVENTORY.getObjectScene(R2_ANCIENT_SCROLLS) == 1950))
+ SceneItem::display(1950, 34, 0, 280, 1, 160, 9, 1, 2, 20, 7, 7, LIST_END);
+ scene->_sceneMode = 0;
+ Common::Point pt(30, 160);
+ NpcMover *mover = new NpcMover();
+ R2_GLOBALS._player.addMover(mover, &pt, scene);
+ }
+ } else {
+ if (scene->_vampireActive)
+ R2_GLOBALS._player.animate(ANIM_MODE_9);
+
+ scene->_sceneMode = 16;
+ Common::Point pt(-20, 160);
+ NpcMover *mover = new NpcMover();
+ R2_GLOBALS._player.addMover(mover, &pt, scene);
+ }
+}
+
+void Scene1950::ShaftExit::changeScene() {
+ Scene1950 *scene = (Scene1950 *)R2_GLOBALS._sceneManager._scene;
+
+ _enabled = false;
+ R2_GLOBALS._player.disableControl(CURSOR_WALK);
+ R2_GLOBALS._flubMazeEntryDirection = 0;
+ scene->_sceneMode = 1951;
+ scene->setAction(&scene->_sequenceManager, scene, 1951, &R2_GLOBALS._player, NULL);
+}
+
+void Scene1950::DoorExit::changeScene() {
+ Scene1950 *scene = (Scene1950 *)R2_GLOBALS._sceneManager._scene;
+
+ _enabled = false;
+ R2_GLOBALS._player.disableControl(CURSOR_WALK);
+ R2_GLOBALS._flubMazeEntryDirection = 3;
+ if (R2_GLOBALS._player._visage == 22) {
+ scene->_sceneMode = 1975;
+ scene->setAction(&scene->_sequenceManager, scene, 1975, &R2_GLOBALS._player, NULL);
+ } else {
+ SceneItem::display(1950, 22, 0, 280, 1, 160, 9, 1, 2, 20, 7, 7, LIST_END);
+ R2_GLOBALS._flubMazeEntryDirection = 0;
+ scene->_sceneMode = 0;
+ Common::Point pt(250, 150);
+ NpcMover *mover = new NpcMover();
+ R2_GLOBALS._player.addMover(mover, &pt, scene);
+ _enabled = true;
+ }
+}
+
+/*--------------------------------------------------------------------------*/
+
+Scene1950::Scene1950() {
+ _upExitStyle = false;
+ _removeFlag = false;
+ _vampireActive = false;
+ _vampireDestPos = Common::Point(0, 0);
+ _vampireIndex = 0;
+}
+
+void Scene1950::synchronize(Serializer &s) {
+ SceneExt::synchronize(s);
+
+ s.syncAsSint16LE(_upExitStyle);
+ s.syncAsSint16LE(_removeFlag);
+ s.syncAsSint16LE(_vampireActive);
+ s.syncAsSint16LE(_vampireDestPos.x);
+ s.syncAsSint16LE(_vampireDestPos.y);
+ s.syncAsSint16LE(_vampireIndex);
+}
+
+void Scene1950::initArea() {
+ _northExit._enabled = false;
+ _upExit._enabled = false;
+ _eastExit._enabled = false;
+ _downExit._enabled = false;
+ _southExit._enabled = false;
+ _westExit._enabled = false;
+ _shaftExit._enabled = false;
+ _doorExit._enabled = false;
+ _northExit._insideArea = false;
+ _upExit._insideArea = false;
+ _eastExit._insideArea = false;
+ _downExit._insideArea = false;
+ _southExit._insideArea = false;
+ _westExit._insideArea = false;
+ _shaftExit._insideArea = false;
+ _doorExit._insideArea = false;
+ _northExit._moving = false;
+ _upExit._moving = false;
+ _eastExit._moving = false;
+ _downExit._moving = false;
+ _southExit._moving = false;
+ _westExit._moving = false;
+ _shaftExit._moving = false;
+ _doorExit._moving = false;
+ _upExitStyle = false;
+
+ switch (R2_GLOBALS._flubMazeArea - 1) {
+ case 0:
+ loadScene(1948);
+ break;
+ case 1:
+ // No break on purpose
+ case 8:
+ // No break on purpose
+ case 10:
+ // No break on purpose
+ case 12:
+ // No break on purpose
+ case 16:
+ // No break on purpose
+ case 19:
+ // No break on purpose
+ case 23:
+ // No break on purpose
+ case 30:
+ // No break on purpose
+ case 44:
+ // No break on purpose
+ case 72:
+ // No break on purpose
+ case 74:
+ // No break on purpose
+ case 86:
+ // No break on purpose
+ case 96:
+ // No break on purpose
+ case 103:
+ loadScene(1950);
+ break;
+ case 2:
+ // No break on purpose
+ case 29:
+ loadScene(1965);
+ break;
+ case 3:
+ // No break on purpose
+ case 9:
+ // No break on purpose
+ case 11:
+ // No break on purpose
+ case 15:
+ // No break on purpose
+ case 24:
+ // No break on purpose
+ case 39:
+ // No break on purpose
+ case 45:
+ // No break on purpose
+ case 71:
+ // No break on purpose
+ case 73:
+ // No break on purpose
+ case 75:
+ // No break on purpose
+ case 79:
+ // No break on purpose
+ case 85:
+ // No break on purpose
+ case 87:
+ // No break on purpose
+ case 95:
+ loadScene(1955);
+ break;
+ case 4:
+ // No break on purpose
+ case 6:
+ // No break on purpose
+ case 13:
+ // No break on purpose
+ case 27:
+ // No break on purpose
+ case 41:
+ // No break on purpose
+ case 48:
+ // No break on purpose
+ case 50:
+ // No break on purpose
+ case 54:
+ // No break on purpose
+ case 76:
+ // No break on purpose
+ case 80:
+ // No break on purpose
+ case 90:
+ // No break on purpose
+ case 104:
+ loadScene(1975);
+ break;
+ case 5:
+ // No break on purpose
+ case 7:
+ // No break on purpose
+ case 14:
+ // No break on purpose
+ case 28:
+ // No break on purpose
+ case 32:
+ // No break on purpose
+ case 47:
+ // No break on purpose
+ case 53:
+ loadScene(1997);
+ break;
+ case 17:
+ // No break on purpose
+ case 20:
+ // No break on purpose
+ case 25:
+ // No break on purpose
+ case 31:
+ // No break on purpose
+ case 33:
+ // No break on purpose
+ case 46:
+ loadScene(1995);
+ break;
+ case 18:
+ // No break on purpose
+ case 22:
+ // No break on purpose
+ case 26:
+ // No break on purpose
+ case 36:
+ // No break on purpose
+ case 38:
+ // No break on purpose
+ case 43:
+ // No break on purpose
+ case 51:
+ // No break on purpose
+ case 70:
+ // No break on purpose
+ case 78:
+ // No break on purpose
+ case 84:
+ // No break on purpose
+ case 89:
+ // No break on purpose
+ case 101:
+ loadScene(1970);
+ break;
+ case 21:
+ // No break on purpose
+ case 34:
+ // No break on purpose
+ case 57:
+ // No break on purpose
+ case 58:
+ // No break on purpose
+ case 59:
+ // No break on purpose
+ case 62:
+ // No break on purpose
+ case 65:
+ loadScene(1980);
+ break;
+ case 35:
+ // No break on purpose
+ case 61:
+ // No break on purpose
+ case 77:
+ // No break on purpose
+ case 83:
+ loadScene(1982);
+ break;
+ case 37:
+ // No break on purpose
+ case 52:
+ // No break on purpose
+ case 82:
+ // No break on purpose
+ case 88:
+ // No break on purpose
+ case 92:
+ // No break on purpose
+ case 97:
+ // No break on purpose
+ case 100:
+ loadScene(1962);
+ break;
+ case 40:
+ // No break on purpose
+ case 102:
+ loadScene(1960);
+ break;
+ case 42:
+ // No break on purpose
+ case 55:
+ // No break on purpose
+ case 60:
+ // No break on purpose
+ case 66:
+ // No break on purpose
+ case 68:
+ // No break on purpose
+ case 69:
+ // No break on purpose
+ case 93:
+ // No break on purpose
+ case 98:
+ loadScene(1990);
+ break;
+ case 49:
+ // No break on purpose
+ case 81:
+ // No break on purpose
+ case 91:
+ // No break on purpose
+ case 94:
+ // No break on purpose
+ case 99:
+ loadScene(1967);
+ break;
+ case 56:
+ // No break on purpose
+ case 63:
+ // No break on purpose
+ case 64:
+ // No break on purpose
+ case 67:
+ loadScene(1985);
+ _upExitStyle = true;
+ break;
+ default:
+ break;
+ }
+
+ if (R2_GLOBALS._flubMazeArea != 1)
+ R2_GLOBALS._walkRegions.load(1950);
+
+ switch (R2_GLOBALS._flubMazeArea - 1) {
+ case 0:
+ _shaftExit._enabled = true;
+ if ((R2_INVENTORY.getObjectScene(R2_SCRITH_KEY) == 0) && (R2_INVENTORY.getObjectScene(R2_SAPPHIRE_BLUE) == 1950))
+ _doorExit._enabled = true;
+ R2_GLOBALS._walkRegions.disableRegion(2);
+ R2_GLOBALS._walkRegions.disableRegion(3);
+ R2_GLOBALS._walkRegions.disableRegion(4);
+ R2_GLOBALS._walkRegions.disableRegion(5);
+ R2_GLOBALS._walkRegions.disableRegion(6);
+ break;
+ case 1:
+ // No break on purpose
+ case 2:
+ // No break on purpose
+ case 3:
+ // No break on purpose
+ case 8:
+ // No break on purpose
+ case 9:
+ // No break on purpose
+ case 10:
+ // No break on purpose
+ case 11:
+ // No break on purpose
+ case 12:
+ // No break on purpose
+ case 15:
+ // No break on purpose
+ case 16:
+ // No break on purpose
+ case 19:
+ // No break on purpose
+ case 23:
+ // No break on purpose
+ case 24:
+ // No break on purpose
+ case 29:
+ // No break on purpose
+ case 30:
+ // No break on purpose
+ case 39:
+ // No break on purpose
+ case 40:
+ // No break on purpose
+ case 44:
+ // No break on purpose
+ case 45:
+ // No break on purpose
+ case 71:
+ // No break on purpose
+ case 72:
+ // No break on purpose
+ case 73:
+ // No break on purpose
+ case 74:
+ // No break on purpose
+ case 75:
+ // No break on purpose
+ case 79:
+ // No break on purpose
+ case 85:
+ // No break on purpose
+ case 86:
+ // No break on purpose
+ case 87:
+ // No break on purpose
+ case 95:
+ // No break on purpose
+ case 96:
+ // No break on purpose
+ case 102:
+ // No break on purpose
+ case 103:
+ _eastExit._enabled = true;
+ _westExit._enabled = true;
+ break;
+ case 4:
+ // No break on purpose
+ case 6:
+ // No break on purpose
+ case 13:
+ // No break on purpose
+ case 17:
+ // No break on purpose
+ case 20:
+ // No break on purpose
+ case 25:
+ // No break on purpose
+ case 27:
+ // No break on purpose
+ case 31:
+ // No break on purpose
+ case 33:
+ // No break on purpose
+ case 37:
+ // No break on purpose
+ case 41:
+ // No break on purpose
+ case 46:
+ // No break on purpose
+ case 48:
+ // No break on purpose
+ case 50:
+ // No break on purpose
+ case 52:
+ // No break on purpose
+ case 54:
+ // No break on purpose
+ case 76:
+ // No break on purpose
+ case 80:
+ // No break on purpose
+ case 82:
+ // No break on purpose
+ case 88:
+ // No break on purpose
+ case 90:
+ // No break on purpose
+ case 92:
+ // No break on purpose
+ case 97:
+ // No break on purpose
+ case 100:
+ // No break on purpose
+ case 104:
+ _westExit._enabled = true;
+ R2_GLOBALS._walkRegions.disableRegion(6);
+ R2_GLOBALS._walkRegions.disableRegion(9);
+ break;
+ case 5:
+ // No break on purpose
+ case 7:
+ // No break on purpose
+ case 14:
+ // No break on purpose
+ case 18:
+ // No break on purpose
+ case 22:
+ // No break on purpose
+ case 26:
+ // No break on purpose
+ case 28:
+ // No break on purpose
+ case 32:
+ // No break on purpose
+ case 36:
+ // No break on purpose
+ case 38:
+ // No break on purpose
+ case 43:
+ // No break on purpose
+ case 47:
+ // No break on purpose
+ case 49:
+ // No break on purpose
+ case 51:
+ // No break on purpose
+ case 53:
+ // No break on purpose
+ case 70:
+ // No break on purpose
+ case 78:
+ // No break on purpose
+ case 81:
+ // No break on purpose
+ case 84:
+ // No break on purpose
+ case 89:
+ // No break on purpose
+ case 91:
+ // No break on purpose
+ case 94:
+ // No break on purpose
+ case 99:
+ // No break on purpose
+ case 101:
+ _eastExit._enabled = true;
+ R2_GLOBALS._walkRegions.disableRegion(1);
+ R2_GLOBALS._walkRegions.disableRegion(7);
+ R2_GLOBALS._walkRegions.disableRegion(13);
+ break;
+ default:
+ R2_GLOBALS._walkRegions.disableRegion(1);
+ R2_GLOBALS._walkRegions.disableRegion(6);
+ R2_GLOBALS._walkRegions.disableRegion(7);
+ R2_GLOBALS._walkRegions.disableRegion(9);
+ R2_GLOBALS._walkRegions.disableRegion(13);
+ break;
+ }
+
+ _northDoorway.remove();
+ _northDoorway.removeObject();
+ _southDoorway.remove();
+
+ switch (R2_GLOBALS._flubMazeArea - 4) {
+ case 0:
+ // No break on purpose
+ case 3:
+ // No break on purpose
+ case 16:
+ // No break on purpose
+ case 22:
+ // No break on purpose
+ case 24:
+ // No break on purpose
+ case 32:
+ // No break on purpose
+ case 33:
+ // No break on purpose
+ case 45:
+ // No break on purpose
+ case 46:
+ // No break on purpose
+ case 48:
+ // No break on purpose
+ case 51:
+ // No break on purpose
+ case 56:
+ // No break on purpose
+ case 59:
+ // No break on purpose
+ case 67:
+ // No break on purpose
+ case 68:
+ // No break on purpose
+ case 70:
+ // No break on purpose
+ case 73:
+ // No break on purpose
+ case 82:
+ // No break on purpose
+ case 90:
+ _northExit._enabled = true;
+ _northDoorway.setup(1950, (R2_GLOBALS._flubMazeArea % 2) + 1, 1, 160, 137, 25);
+ //visage,strip,frame,px,py,priority,effect
+ _southDoorway.postInit();
+ _southDoorway.setVisage(1950);
+ _southDoorway.setStrip((((R2_GLOBALS._flubMazeArea - 1) / 35) % 2) + 1);
+ _southDoorway.setFrame(2);
+ _southDoorway.setPosition(Common::Point(160, 167));
+ _southDoorway.fixPriority(220);
+ R2_GLOBALS._walkRegions.disableRegion(3);
+ R2_GLOBALS._walkRegions.disableRegion(4);
+ break;
+ case 7:
+ // No break on purpose
+ case 10:
+ // No break on purpose
+ case 23:
+ // No break on purpose
+ case 29:
+ // No break on purpose
+ case 31:
+ // No break on purpose
+ case 39:
+ // No break on purpose
+ case 40:
+ // No break on purpose
+ case 52:
+ // No break on purpose
+ case 53:
+ // No break on purpose
+ case 55:
+ // No break on purpose
+ case 63:
+ // No break on purpose
+ case 65:
+ // No break on purpose
+ case 66:
+ // No break on purpose
+ case 75:
+ // No break on purpose
+ case 77:
+ // No break on purpose
+ case 81:
+ // No break on purpose
+ case 87:
+ // No break on purpose
+ case 89:
+ // No break on purpose
+ case 97:
+ _southExit._enabled = true;
+
+ _southDoorway.postInit();
+ _southDoorway.setVisage(1950);
+ _southDoorway.setStrip((((R2_GLOBALS._flubMazeArea - 1) / 35) % 2) + 1);
+ _southDoorway.setFrame(3);
+ _southDoorway.setPosition(Common::Point(160, 167));
+ _southDoorway.fixPriority(220);
+ break;
+ case 58:
+ // No break on purpose
+ case 74:
+ // No break on purpose
+ case 80:
+ _northExit._enabled = true;
+ _southExit._enabled = true;
+
+ _northDoorway.setup(1950, (R2_GLOBALS._flubMazeArea % 2) + 1, 1, 160, 137, 25);
+
+ _southDoorway.postInit();
+ _southDoorway.setVisage(1950);
+ _southDoorway.setStrip((((R2_GLOBALS._flubMazeArea - 1) / 35) % 2) + 1);
+ _southDoorway.setFrame(3);
+ _southDoorway.setPosition(Common::Point(160, 167));
+ _southDoorway.fixPriority(220);
+ R2_GLOBALS._walkRegions.disableRegion(3);
+ R2_GLOBALS._walkRegions.disableRegion(4);
+ break;
+ default:
+ _southDoorway.postInit();
+ _southDoorway.setVisage(1950);
+ _southDoorway.setStrip(((R2_GLOBALS._flubMazeArea - 1) / 35) % 2 + 1);
+ _southDoorway.setFrame(2);
+ _southDoorway.setPosition(Common::Point(160, 167));
+ _southDoorway.fixPriority(220);
+ break;
+ }
+
+ switch (R2_GLOBALS._flubMazeArea - 3) {
+ case 0:
+ // No break on purpose
+ case 3:
+ // No break on purpose
+ case 5:
+ // No break on purpose
+ case 12:
+ // No break on purpose
+ case 15:
+ // No break on purpose
+ case 18:
+ // No break on purpose
+ case 19:
+ // No break on purpose
+ case 23:
+ // No break on purpose
+ case 26:
+ // No break on purpose
+ case 27:
+ // No break on purpose
+ case 29:
+ // No break on purpose
+ case 30:
+ // No break on purpose
+ case 31:
+ // No break on purpose
+ case 32:
+ // No break on purpose
+ case 44:
+ // No break on purpose
+ case 45:
+ // No break on purpose
+ case 51:
+ // No break on purpose
+ case 55:
+ // No break on purpose
+ case 56:
+ // No break on purpose
+ case 57:
+ // No break on purpose
+ case 60:
+ // No break on purpose
+ case 63:
+ _upExit._enabled = true;
+ break;
+ case 54:
+ // No break on purpose
+ case 61:
+ // No break on purpose
+ case 62:
+ // No break on purpose
+ case 65:
+ _upExit._enabled = true;
+ // No break on purpose
+ case 35:
+ // No break on purpose
+ case 38:
+ // No break on purpose
+ case 40:
+ // No break on purpose
+ case 47:
+ // No break on purpose
+ case 50:
+ // No break on purpose
+ case 53:
+ // No break on purpose
+ case 58:
+ // No break on purpose
+ case 64:
+ // No break on purpose
+ case 66:
+ // No break on purpose
+ case 67:
+ // No break on purpose
+ case 79:
+ // No break on purpose
+ case 80:
+ // No break on purpose
+ case 86:
+ // No break on purpose
+ case 89:
+ // No break on purpose
+ case 90:
+ // No break on purpose
+ case 91:
+ // No break on purpose
+ case 92:
+ // No break on purpose
+ case 95:
+ // No break on purpose
+ case 96:
+ // No break on purpose
+ case 97:
+ // No break on purpose
+ case 98:
+ // No break on purpose
+ case 100:
+ _downExit._enabled = true;
+ R2_GLOBALS._walkRegions.disableRegion(4);
+ R2_GLOBALS._walkRegions.disableRegion(5);
+ R2_GLOBALS._walkRegions.disableRegion(6);
+ R2_GLOBALS._walkRegions.disableRegion(10);
+ R2_GLOBALS._walkRegions.disableRegion(11);
+ default:
+ break;
+ }
+ R2_GLOBALS._uiElements.draw();
+}
+
+void Scene1950::enterArea() {
+ R2_GLOBALS._player.disableControl();
+ R2_GLOBALS._player.animate(ANIM_MODE_1, NULL);
+
+ _vampire.remove();
+ _door.remove();
+ _scrolls.remove();
+
+ _vampireActive = false;
+ _vampireIndex = 0;
+
+ // Certain areas have a vampire in them
+ switch (R2_GLOBALS._flubMazeArea) {
+ case 10:
+ _vampireIndex = 1;
+ break;
+ case 13:
+ _vampireIndex = 2;
+ break;
+ case 16:
+ _vampireIndex = 3;
+ break;
+ case 17:
+ _vampireIndex = 4;
+ break;
+ case 24:
+ _vampireIndex = 5;
+ break;
+ case 25:
+ _vampireIndex = 6;
+ break;
+ case 31:
+ _vampireIndex = 7;
+ break;
+ case 40:
+ _vampireIndex = 8;
+ break;
+ case 45:
+ _vampireIndex = 9;
+ break;
+ case 46:
+ _vampireIndex = 10;
+ break;
+ case 73:
+ _vampireIndex = 11;
+ break;
+ case 75:
+ _vampireIndex = 12;
+ break;
+ case 80:
+ _vampireIndex = 13;
+ break;
+ case 87:
+ _vampireIndex = 14;
+ break;
+ case 88:
+ _vampireIndex = 15;
+ break;
+ case 96:
+ _vampireIndex = 16;
+ break;
+ case 97:
+ _vampireIndex = 17;
+ break;
+ case 104:
+ _vampireIndex = 18;
+ break;
+ default:
+ break;
+ }
+
+ if (_vampireIndex != 0) {
+ _vampire.postInit();
+ _vampire._numFrames = 6;
+ _vampire._moveRate = 6;
+ _vampire._moveDiff = Common::Point(3, 2);
+ _vampire._effect = EFFECT_SHADED;
+
+ if (!R2_GLOBALS._vampireData[_vampireIndex - 1]._isAlive) {
+ // Show vampire ashes
+ _vampire.setPosition(Common::Point(R2_GLOBALS._vampireData[_vampireIndex - 1]._position));
+ _vampire.animate(ANIM_MODE_NONE, NULL);
+ _vampire.addMover(NULL);
+ _vampire.setVisage(1961);
+ _vampire.setStrip(4);
+ _vampire.setFrame(10);
+ _vampire.fixPriority(10);
+ _vampire.setDetails(1950, 15, -1, 17, 2, (SceneItem *) NULL);
+ } else {
+ // Start the vampire
+ _vampire.setVisage(1960);
+ _vampire.setPosition(Common::Point(160, 130));
+ _vampire.animate(ANIM_MODE_2, NULL);
+ _vampire.setDetails(1950, 12, -1, 14, 2, (SceneItem *) NULL);
+ _vampireActive = true;
+ }
+ }
+ if ((R2_GLOBALS._flubMazeArea == 1) && (R2_INVENTORY.getObjectScene(R2_SCRITH_KEY) != 0)) {
+ // Show doorway at the right hand side of the very first flub corridor
+ _door.postInit();
+ _door.setVisage(1948);
+ _door.setStrip(3);
+ _door.setPosition(Common::Point(278, 155));
+ _door.fixPriority(100);
+ _door.setDetails(1950, 19, 20, 23, 2, (SceneItem *) NULL);
+ }
+
+ if (R2_GLOBALS._flubMazeArea == 102) {
+ R2_GLOBALS._walkRegions.load(1951);
+ R2_GLOBALS._walkRegions.disableRegion(1);
+ R2_GLOBALS._walkRegions.disableRegion(5);
+ R2_GLOBALS._walkRegions.disableRegion(6);
+ R2_GLOBALS._walkRegions.disableRegion(7);
+
+ _cube.postInit();
+ _cube.setVisage(1970);
+ _cube.setStrip(1);
+ if (R2_GLOBALS.getFlag(37))
+ _cube.setFrame(3);
+ else
+ _cube.setFrame(1);
+ _cube.setPosition(Common::Point(193, 158));
+ _cube.setDetails(1950, 3, 4, 5, 2, (SceneItem *) NULL);
+
+ _pulsingLights.postInit();
+ _pulsingLights.setVisage(1970);
+ _pulsingLights.setStrip(3);
+ _pulsingLights.animate(ANIM_MODE_2, NULL);
+ _pulsingLights._numFrames = 6;
+ _pulsingLights.setPosition(Common::Point(194, 158));
+ _pulsingLights.fixPriority(159);
+
+ _keypad.setDetails(Rect(188, 124, 199, 133), 1950, 27, 28, -1, 2, NULL);
+
+ if (R2_INVENTORY.getObjectScene(R2_SAPPHIRE_BLUE) == 1950) {
+ _gem.postInit();
+ _gem.setVisage(1970);
+ _gem.setStrip(1);
+ _gem.setFrame(2);
+ _gem.fixPriority(160);
+ }
+
+ if (R2_GLOBALS.getFlag(37)) {
+ _gem.setPosition(Common::Point(192, 118));
+ _gem.setDetails(1950, 9, 4, -1, 2, (SceneItem *) NULL);
+ } else {
+ _containmentField.postInit();
+ _containmentField.setVisage(1970);
+ _containmentField.setStrip(4);
+ _containmentField._numFrames = 4;
+ _containmentField.animate(ANIM_MODE_8, 0, NULL);
+ _containmentField.setPosition(Common::Point(192, 121));
+ _containmentField.fixPriority(159);
+ _containmentField.setDetails(1950, 6, 7, 8, 2, (SceneItem *) NULL);
+
+ _gem.setPosition(Common::Point(192, 109));
+ _gem.setDetails(1950, 9, 7, 8, 2, (SceneItem *) NULL);
+ }
+
+ _scrolls.postInit();
+ _scrolls.setVisage(1972);
+ _scrolls.setStrip(1);
+ _scrolls.setPosition(Common::Point(76, 94));
+ _scrolls.fixPriority(25);
+ _scrolls.setDetails(1950, 30, -1, -1, 2, (SceneItem *) NULL);
+ if (R2_INVENTORY.getObjectScene(R2_ANCIENT_SCROLLS) == 2)
+ _scrolls.setFrame(2);
+ else
+ _scrolls.setFrame(1);
+
+ _removeFlag = true;
+ } else if (_removeFlag) {
+ _cube.remove();
+ _containmentField.remove();
+ _gem.remove();
+ _pulsingLights.remove();
+ _scrolls.remove();
+
+ R2_GLOBALS._sceneItems.remove(&_background);
+ _background.setDetails(Rect(0, 0, 320, 200), 1950, 0, 1, 2, 2, NULL);
+
+ _removeFlag = false;
+ }
+
+ switch (R2_GLOBALS._flubMazeEntryDirection) {
+ case 0:
+ _sceneMode = 1950;
+ if (R2_INVENTORY.getObjectScene(R2_SCRITH_KEY) == 0)
+ // The original uses CURSOR_ARROW. CURSOR_WALK is much more coherent
+ R2_GLOBALS._player.enableControl(CURSOR_WALK);
+ else
+ setAction(&_sequenceManager, this, 1950, &R2_GLOBALS._player, NULL);
+
+ break;
+ case 1: {
+ _sceneMode = R2_GLOBALS._flubMazeEntryDirection;
+ R2_GLOBALS._player.setPosition(Common::Point(160, 213));
+ Common::Point pt(160, 160);
+ NpcMover *mover = new NpcMover();
+ R2_GLOBALS._player.addMover(mover, &pt, this);
+ }
+ break;
+ case 2:
+ _sceneMode = R2_GLOBALS._flubMazeEntryDirection;
+ if (R2_GLOBALS.getFlag(36))
+ setAction(&_sequenceManager, this, 1957, &R2_GLOBALS._player, NULL);
+ else
+ setAction(&_sequenceManager, this, 1974, &R2_GLOBALS._player, NULL);
+ break;
+ case 3:
+ // Entering from the left
+ if (!_vampireActive) {
+ _sceneMode = R2_GLOBALS._flubMazeEntryDirection;
+ R2_GLOBALS._player.setPosition(Common::Point(-20, 160));
+ Common::Point pt(30, 160);
+ NpcMover *mover = new NpcMover();
+ R2_GLOBALS._player.addMover(mover, &pt, this);
+ } else {
+ _sceneMode = 18;
+ _eastExit._enabled = false;
+ _vampireDestPos = Common::Point(60, 152);
+ R2_GLOBALS._player.enableControl(CURSOR_USE);
+ R2_GLOBALS._player._canWalk = false;
+
+ _vampire.setStrip(2);
+ NpcMover *mover = new NpcMover();
+ _vampire.addMover(mover, &_vampireDestPos, this);
+
+ R2_GLOBALS._player.setPosition(Common::Point(-20, 160));
+ Common::Point pt2(30, 160);
+ NpcMover *mover2 = new NpcMover();
+ R2_GLOBALS._player.addMover(mover2, &pt2, NULL);
+ }
+ break;
+ case 4:
+ _sceneMode = R2_GLOBALS._flubMazeEntryDirection;
+ if (!_upExitStyle) {
+ if (R2_GLOBALS.getFlag(36))
+ setAction(&_sequenceManager, this, 1955, &R2_GLOBALS._player, NULL);
+ else
+ setAction(&_sequenceManager, this, 1972, &R2_GLOBALS._player, NULL);
+ } else {
+ if (R2_GLOBALS.getFlag(36))
+ setAction(&_sequenceManager, this, 1954, &R2_GLOBALS._player, NULL);
+ else
+ setAction(&_sequenceManager, this, 1971, &R2_GLOBALS._player, NULL);
+ }
+ break;
+ case 5: {
+ _sceneMode = R2_GLOBALS._flubMazeEntryDirection;
+ R2_GLOBALS._player.setPosition(Common::Point(160, 127));
+ Common::Point pt(160, 160);
+ NpcMover *mover = new NpcMover();
+ R2_GLOBALS._player.addMover(mover, &pt, this);
+ }
+ break;
+ case 6:
+ // Entering from the right
+ if (!_vampireActive) {
+ _sceneMode = R2_GLOBALS._flubMazeEntryDirection;
+ if (R2_GLOBALS._flubMazeArea == 1) {
+ setAction(&_sequenceManager, this, 1961, &R2_GLOBALS._player, NULL);
+ } else {
+ R2_GLOBALS._player.setPosition(Common::Point(340, 160));
+ Common::Point pt(289, 160);
+ NpcMover *mover = new NpcMover();
+ R2_GLOBALS._player.addMover(mover, &pt, this);
+ }
+ } else {
+ _sceneMode = 17;
+ _westExit._enabled = false;
+ _vampireDestPos = Common::Point(259, 152);
+
+ R2_GLOBALS._player.enableControl(CURSOR_USE);
+ R2_GLOBALS._player._canWalk = false;
+
+ _vampire.setStrip(1);
+ NpcMover *mover = new NpcMover();
+ _vampire.addMover(mover, &_vampireDestPos, this);
+
+ R2_GLOBALS._player.setPosition(Common::Point(340, 160));
+ Common::Point pt2(289, 160);
+ NpcMover *mover2 = new NpcMover();
+ R2_GLOBALS._player.addMover(mover2, &pt2, NULL);
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+void Scene1950::doButtonPress(int indx) {
+ Scene1950 *scene = (Scene1950 *)R2_GLOBALS._sceneManager._scene;
+ R2_GLOBALS._player.disableControl();
+
+ int prevIndex = indx - 1;
+ if ((indx / 4) == (prevIndex / 4)) {
+ if (prevIndex < 0)
+ prevIndex = 3;
+ } else {
+ prevIndex += 4;
+ }
+
+ assert(prevIndex >= 0 && prevIndex < 16);
+ if (!_KeypadWindow._buttons[prevIndex]._toggled) {
+ _KeypadWindow._buttons[prevIndex].setFrame(2);
+ _KeypadWindow._buttons[prevIndex]._toggled = true;
+ } else {
+ _KeypadWindow._buttons[prevIndex].setFrame(1);
+ _KeypadWindow._buttons[prevIndex]._toggled = false;
+ }
+
+ prevIndex = indx + 1;
+ if ((indx / 4) == (prevIndex / 4)) {
+ if (prevIndex > 15)
+ prevIndex = 12;
+ } else {
+ prevIndex -= 4;
+ }
+
+ assert(prevIndex >= 0 && prevIndex < 16);
+ if (!_KeypadWindow._buttons[prevIndex]._toggled) {
+ _KeypadWindow._buttons[prevIndex].setFrame(2);
+ _KeypadWindow._buttons[prevIndex]._toggled = true;
+ } else {
+ _KeypadWindow._buttons[prevIndex].setFrame(1);
+ _KeypadWindow._buttons[prevIndex]._toggled = false;
+ }
+
+ prevIndex = indx - 4;
+ if (prevIndex < 0)
+ prevIndex += 16;
+
+ assert(prevIndex >= 0 && prevIndex < 16);
+ if (!_KeypadWindow._buttons[prevIndex]._toggled) {
+ _KeypadWindow._buttons[prevIndex].setFrame(2);
+ _KeypadWindow._buttons[prevIndex]._toggled = true;
+ } else {
+ _KeypadWindow._buttons[prevIndex].setFrame(1);
+ _KeypadWindow._buttons[prevIndex]._toggled = false;
+ }
+
+ prevIndex = indx + 4;
+ if (prevIndex > 15)
+ prevIndex -= 16;
+
+ assert(prevIndex >= 0 && prevIndex < 16);
+ if (!_KeypadWindow._buttons[prevIndex]._toggled) {
+ _KeypadWindow._buttons[prevIndex].setFrame(2);
+ _KeypadWindow._buttons[prevIndex]._toggled = true;
+ } else {
+ _KeypadWindow._buttons[prevIndex].setFrame(1);
+ _KeypadWindow._buttons[prevIndex]._toggled = false;
+ }
+
+ // Check whether all the buttons are highlighted
+ int cpt = 0;
+ for (prevIndex = 0; prevIndex < 16; prevIndex++) {
+ if (_KeypadWindow._buttons[prevIndex]._toggled)
+ ++cpt;
+ }
+
+ if (cpt != 16) {
+ R2_GLOBALS._player.enableControl();
+ R2_GLOBALS._player._canWalk = false;
+ } else {
+ R2_GLOBALS.setFlag(37);
+ _sceneMode = 24;
+ setAction(&_sequenceManager, scene, 1976, NULL);
+ }
+}
+
+void Scene1950::postInit(SceneObjectList *OwnerList) {
+ _upExitStyle = false;
+ _removeFlag = false;
+ _vampireActive = false;
+ _vampireIndex = 0;
+ if (R2_GLOBALS._sceneManager._previousScene == 300)
+ R2_GLOBALS._flubMazeArea = 103;
+
+ initArea();
+ SceneExt::postInit();
+ R2_GLOBALS._sound1.play(105);
+
+ _northExit.setDetails(Rect(130, 46, 189, 135), SHADECURSOR_UP, 1950);
+ _northExit.setDest(Common::Point(160, 145));
+
+ _upExit.setDetails(Rect(208, 0, 255, 73), EXITCURSOR_N, 1950);
+ _upExit.setDest(Common::Point(200, 151));
+
+ _eastExit.setDetails(Rect(305, 95, 320, 147), EXITCURSOR_E, 1950);
+ _eastExit.setDest(Common::Point(312, 160));
+
+ _downExit.setDetails(Rect(208, 99, 255, 143), EXITCURSOR_S, 1950);
+ _downExit.setDest(Common::Point(200, 151));
+
+ _southExit.setDetails(Rect(113, 154, 206, 168), SHADECURSOR_DOWN, 1950);
+ _southExit.setDest(Common::Point(160, 165));
+
+ _westExit.setDetails(Rect(0, 95, 14, 147), EXITCURSOR_W, 1950);
+ _westExit.setDest(Common::Point(7, 160));
+
+ _shaftExit.setDetails(Rect(72, 54, 120, 128), EXITCURSOR_NW, 1950);
+ _shaftExit.setDest(Common::Point(120, 140));
+
+ _doorExit.setDetails(Rect(258, 60, 300, 145), EXITCURSOR_NE, 1950);
+ _doorExit.setDest(Common::Point(268, 149));
+
+ R2_GLOBALS._player.postInit();
+ if ( (R2_INVENTORY.getObjectScene(R2_TANNER_MASK) == 0) && (R2_INVENTORY.getObjectScene(R2_PURE_GRAIN_ALCOHOL) == 0)
+ && (R2_INVENTORY.getObjectScene(R2_SOAKED_FACEMASK) == 0) && (!R2_GLOBALS.getFlag(36)) )
+ R2_GLOBALS._player.setVisage(22);
+ else
+ R2_GLOBALS._player.setVisage(20);
+
+ R2_GLOBALS._player._moveDiff = Common::Point(5, 3);
+ _background.setDetails(Rect(0, 0, 320, 200), 1950, 0, 1, 2, 1, NULL);
+
+ enterArea();
+}
+
+void Scene1950::remove() {
+ R2_GLOBALS._sound1.stop();
+ R2_GLOBALS._sound2.fadeOut2(NULL);
+ SceneExt::remove();
+}
+
+void Scene1950::signal() {
+ switch (_sceneMode) {
+ case 11:
+ R2_GLOBALS._flubMazeArea += 7;
+ initArea();
+ enterArea();
+ break;
+ case 12:
+ // Moving up a ladder within the Flub maze
+ R2_GLOBALS._flubMazeArea += 35;
+ initArea();
+ enterArea();
+ break;
+ case 1975:
+ SceneItem::display(1950, 21, SET_WIDTH, 280, SET_X, 160, SET_POS_MODE, 1,
+ SET_Y, 20, SET_EXT_BGCOLOR, 7, LIST_END);
+ // No break on purpose
+ case 13:
+ // Moving east within the Flub maze
+ ++R2_GLOBALS._flubMazeArea;
+ initArea();
+ enterArea();
+ break;
+ case 14:
+ // Moving down a ladder within the Flub maze
+ R2_GLOBALS._flubMazeArea -= 35;
+ initArea();
+ enterArea();
+ break;
+ case 15:
+ R2_GLOBALS._flubMazeArea -= 7;
+ initArea();
+ enterArea();
+ break;
+ case 16:
+ // Moving west within the Flub maze
+ // No break on purpose
+ case 1961:
+ --R2_GLOBALS._flubMazeArea;
+ initArea();
+ enterArea();
+ break;
+ case 17: {
+ _sceneMode = 13;
+ R2_GLOBALS._flubMazeEntryDirection = 3;
+ _vampireActive = false;
+ R2_GLOBALS._player.disableControl(CURSOR_WALK);
+ R2_GLOBALS._player._canWalk = true;
+ R2_GLOBALS._player.setVisage(22);
+ R2_GLOBALS._player.animate(ANIM_MODE_9);
+ Common::Point pt(340, 160);
+ NpcMover *mover = new NpcMover();
+ R2_GLOBALS._player.addMover(mover, &pt, this);
+ Common::Point pt2(289, 160);
+ NpcMover *mover2 = new NpcMover();
+ _vampire.addMover(mover2, &pt2, NULL);
+ }
+ break;
+ case 18: {
+ _sceneMode = 16;
+ R2_GLOBALS._flubMazeEntryDirection = 6;
+ _vampireActive = false;
+ R2_GLOBALS._player.disableControl(CURSOR_WALK);
+ R2_GLOBALS._player._canWalk = true;
+ R2_GLOBALS._player.setVisage(22);
+ R2_GLOBALS._player.animate(ANIM_MODE_9);
+ Common::Point pt(-20, 160);
+ NpcMover *mover = new NpcMover();
+ R2_GLOBALS._player.addMover(mover, &pt, this);
+ Common::Point pt2(30, 160);
+ NpcMover *mover2 = new NpcMover();
+ _vampire.addMover(mover2, &pt2, NULL);
+ }
+ break;
+ case 24:
+ _KeypadWindow.remove();
+ _sceneMode = 1966;
+ _cube.setFrame(3);
+ setAction(&_sequenceManager, this, 1966, &_containmentField, &_gem, NULL);
+ break;
+ case 1951:
+ R2_GLOBALS._sound1.fadeOut2(NULL);
+ R2_GLOBALS._sceneManager.changeScene(1945);
+ break;
+ case 1958:
+ SceneItem::display(1950, 24, 0, 280, 1, 160, 9, 1, 2, 20, 7, 7, LIST_END);
+ R2_GLOBALS._player.enableControl(CURSOR_WALK);
+ _doorExit._enabled = true;
+ break;
+ case 1959:
+ R2_INVENTORY.setObjectScene(R2_SOAKED_FACEMASK, 0);
+ R2_GLOBALS._player.enableControl(CURSOR_WALK);
+ _doorExit._enabled = true;
+ break;
+ case 1962:
+ // No break on purpose
+ case 1963:
+ R2_GLOBALS._player.enableControl();
+ _KeypadWindow.setup2(1971, 1, 1, 160, 135);
+ break;
+ case 1964:
+ // No break on purpose
+ case 1965:
+ if (!R2_GLOBALS.getFlag(37))
+ SceneItem::display(1950, 26, 0, 280, 1, 160, 9, 1, 2, 20, 7, 7, LIST_END);
+
+ R2_GLOBALS._player.enableControl();
+ break;
+ case 1966:
+ _containmentField.remove();
+ if (R2_GLOBALS.getFlag(36)) {
+ _sceneMode = 1964;
+ setAction(&_sequenceManager, this, 1964, &R2_GLOBALS._player, NULL);
+ } else {
+ _sceneMode = 1965;
+ setAction(&_sequenceManager, this, 1965, &R2_GLOBALS._player, NULL);
+ }
+ _gem.setDetails(1950, 9, -1, -1, 2, (SceneItem *) NULL);
+ break;
+ case 1967: {
+ _sceneMode = 0;
+ R2_INVENTORY.setObjectScene(R2_SAPPHIRE_BLUE, 2);
+ _gem.remove();
+ if (R2_GLOBALS.getFlag(36))
+ R2_GLOBALS._player.setVisage(20);
+ else
+ R2_GLOBALS._player.setVisage(22);
+
+ R2_GLOBALS._player.animate(ANIM_MODE_1, NULL);
+ // This is a hack to work around a pathfinding issue. original destination is (218, 165)
+ Common::Point pt(128, 165);
+ NpcMover *mover = new NpcMover();
+ R2_GLOBALS._player.addMover(mover, &pt, this);
+ }
+ break;
+ case 1968:
+ R2_GLOBALS._player.enableControl();
+ R2_INVENTORY.setObjectScene(R2_ANCIENT_SCROLLS, 2);
+ _scrolls.setFrame(2);
+ if (R2_GLOBALS.getFlag(36))
+ R2_GLOBALS._player.setVisage(20);
+ else
+ R2_GLOBALS._player.setVisage(22);
+ R2_GLOBALS._player.animate(ANIM_MODE_1, NULL);
+ break;
+ default:
+ R2_GLOBALS._player.enableControl(CURSOR_WALK);
+ break;
+ }
+}
+
+void Scene1950::process(Event &event) {
+ if ( (event.eventType == EVENT_BUTTON_DOWN)
+ && (R2_GLOBALS._player._uiEnabled)
+ && (R2_GLOBALS._events.getCursor() == R2_SOAKED_FACEMASK)
+ && (R2_GLOBALS._player._bounds.contains(event.mousePos))
+ && (R2_INVENTORY.getObjectScene(R2_SCRITH_KEY) == 0)) {
+ event.handled = true;
+ R2_GLOBALS._player.disableControl();
+ _shaftExit._enabled = false;
+ _doorExit._enabled = false;
+ _sceneMode = 1959;
+ setAction(&_sequenceManager, this, 1959, &R2_GLOBALS._player, NULL);
+ }
+
+ Scene::process(event);
+}
+
+} // End of namespace Ringworld2
+} // End of namespace TsAGE
diff --git a/engines/tsage/ringworld2/ringworld2_vampire.h b/engines/tsage/ringworld2/ringworld2_vampire.h
new file mode 100644
index 0000000000..ca7aa34544
--- /dev/null
+++ b/engines/tsage/ringworld2/ringworld2_vampire.h
@@ -0,0 +1,179 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef TSAGE_RINGWORLD2_VAMPIRE_H
+#define TSAGE_RINGWORLD2_VAMPIRE_H
+
+#include "tsage/events.h"
+#include "tsage/core.h"
+#include "tsage/scenes.h"
+#include "tsage/globals.h"
+#include "tsage/sound.h"
+#include "tsage/ringworld2/ringworld2_logic.h"
+
+namespace TsAGE {
+
+namespace Ringworld2 {
+
+using namespace TsAGE;
+
+class Scene1950 : public SceneExt {
+ /* Windows */
+ class KeypadWindow: public ModalWindow {
+ public:
+ class KeypadButton : public SceneActor {
+ public:
+ int _buttonIndex;
+ bool _pressed;
+ bool _toggled;
+
+ KeypadButton();
+ void synchronize(Serializer &s);
+
+ void init(int indx);
+ virtual void process(Event &event);
+ virtual bool startAction(CursorType action, Event &event);
+ };
+
+ SceneActor _areaActor;
+ KeypadButton _buttons[16];
+
+ int _buttonIndex;
+
+ KeypadWindow();
+ virtual void synchronize(Serializer &s);
+ virtual void remove();
+ virtual void setup2(int visage, int stripFrameNum, int frameNum, int posX, int posY);
+ virtual void setup3(int resNum, int lookLineNum, int talkLineNum, int useLineNum);
+ };
+
+ class Keypad : public NamedHotspot {
+ public:
+ virtual bool startAction(CursorType action, Event &event);
+ };
+
+ /* Actors */
+ class Door : public SceneActor {
+ public:
+ virtual bool startAction(CursorType action, Event &event);
+ };
+ class Scrolls : public SceneActor {
+ public:
+ virtual bool startAction(CursorType action, Event &event);
+ };
+ class Gem : public SceneActor {
+ public:
+ virtual bool startAction(CursorType action, Event &event);
+ };
+ class Vampire : public SceneActor {
+ public:
+ Common::Point _deadPosition;
+ int _deltaX;
+ int _deltaY;
+ int _vampireMode;
+
+ Vampire();
+ void synchronize(Serializer &s);
+
+ virtual void signal();
+ virtual bool startAction(CursorType action, Event &event);
+ };
+
+ /* Exits */
+ class NorthExit : public SceneExit {
+ public:
+ virtual void changeScene();
+ };
+ class UpExit : public SceneExit {
+ public:
+ virtual void changeScene();
+ };
+ class EastExit : public SceneExit {
+ public:
+ virtual void changeScene();
+ };
+ class DownExit : public SceneExit {
+ public:
+ virtual void changeScene();
+ };
+ class SouthExit : public SceneExit {
+ public:
+ virtual void changeScene();
+ };
+ class WestExit : public SceneExit {
+ public:
+ virtual void changeScene();
+ };
+ class ShaftExit : public SceneExit {
+ public:
+ virtual void changeScene();
+ };
+ class DoorExit : public SceneExit {
+ public:
+ virtual void changeScene();
+ };
+private:
+ void initArea();
+ void enterArea();
+ void doButtonPress(int indx);
+public:
+ NamedHotspot _background;
+ Keypad _keypad;
+ SceneActor _southDoorway;
+ SceneObject _northDoorway;
+ Door _door;
+ Scrolls _scrolls;
+ SceneActor _containmentField;
+ Gem _gem;
+ SceneActor _cube;
+ SceneActor _pulsingLights;
+ Vampire _vampire;
+ KeypadWindow _KeypadWindow;
+ NorthExit _northExit;
+ UpExit _upExit;
+ EastExit _eastExit;
+ DownExit _downExit;
+ SouthExit _southExit;
+ WestExit _westExit;
+ ShaftExit _shaftExit;
+ DoorExit _doorExit;
+ SequenceManager _sequenceManager;
+
+ bool _upExitStyle;
+ bool _removeFlag;
+ bool _vampireActive;
+ Common::Point _vampireDestPos;
+ int _vampireIndex;
+
+ Scene1950();
+ void synchronize(Serializer &s);
+
+ virtual void postInit(SceneObjectList *OwnerList = NULL);
+ virtual void remove();
+ virtual void signal();
+ virtual void process(Event &event);
+};
+
+} // End of namespace Ringworld2
+} // End of namespace TsAGE
+
+#endif
diff --git a/engines/tsage/sound.cpp b/engines/tsage/sound.cpp
index fee1bd752b..b95b614f09 100644
--- a/engines/tsage/sound.cpp
+++ b/engines/tsage/sound.cpp
@@ -164,7 +164,7 @@ Common::List<SoundDriverEntry> &SoundManager::buildDriverList(bool detectFlag) {
sd._status = detectFlag ? SNDSTATUS_DETECTED : SNDSTATUS_SKIPPED;
sd._field2 = 0;
sd._field6 = 15000;
- sd._shortDescription = "Adlib or SoundBlaster";
+ sd._shortDescription = "AdLib or SoundBlaster";
sd._longDescription = "3812fm";
_availableDrivers.push_back(sd);
diff --git a/engines/wintermute/POTFILES b/engines/wintermute/POTFILES
new file mode 100644
index 0000000000..e9422415b2
--- /dev/null
+++ b/engines/wintermute/POTFILES
@@ -0,0 +1 @@
+engines/wintermute/detection.cpp
diff --git a/engines/wintermute/base/base_engine.cpp b/engines/wintermute/base/base_engine.cpp
index 7c2e9c8468..2166a3e070 100644
--- a/engines/wintermute/base/base_engine.cpp
+++ b/engines/wintermute/base/base_engine.cpp
@@ -61,10 +61,11 @@ BaseEngine::~BaseEngine() {
delete _classReg;
}
-void BaseEngine::createInstance(const Common::String &targetName, const Common::String &gameId, Common::Language lang) {
+void BaseEngine::createInstance(const Common::String &targetName, const Common::String &gameId, Common::Language lang, WMETargetExecutable targetExecutable) {
instance()._targetName = targetName;
instance()._gameId = gameId;
instance()._language = lang;
+ instance()._targetExecutable = targetExecutable;
instance().init();
}
diff --git a/engines/wintermute/base/base_engine.h b/engines/wintermute/base/base_engine.h
index dd82cf9c29..0f4a6b0775 100644
--- a/engines/wintermute/base/base_engine.h
+++ b/engines/wintermute/base/base_engine.h
@@ -34,6 +34,8 @@
#include "common/random.h"
#include "common/language.h"
+#include "engines/wintermute/game_description.h"
+
namespace Wintermute {
class BaseFileManager;
@@ -53,10 +55,12 @@ class BaseEngine : public Common::Singleton<Wintermute::BaseEngine> {
Common::RandomSource *_rnd;
SystemClassRegistry *_classReg;
Common::Language _language;
+ WMETargetExecutable _targetExecutable;
public:
BaseEngine();
~BaseEngine();
- static void createInstance(const Common::String &targetName, const Common::String &gameId, Common::Language lang);
+ static void createInstance(const Common::String &targetName, const Common::String &gameId, Common::Language lang, WMETargetExecutable targetExecutable = LATEST_VERSION);
+
void setGameRef(BaseGame *gameRef) { _gameRef = gameRef; }
Common::RandomSource *getRandomSource() { return _rnd; }
@@ -73,6 +77,9 @@ public:
const char *getGameTargetName() const { return _targetName.c_str(); }
Common::String getGameId() const { return _gameId; }
Common::Language getLanguage() const { return _language; }
+ WMETargetExecutable getTargetExecutable() const {
+ return _targetExecutable;
+ }
};
} // End of namespace Wintermute
diff --git a/engines/wintermute/base/base_game.cpp b/engines/wintermute/base/base_game.cpp
index d37a22e2a6..668053bb3a 100644
--- a/engines/wintermute/base/base_game.cpp
+++ b/engines/wintermute/base/base_game.cpp
@@ -3110,6 +3110,10 @@ bool BaseGame::persist(BasePersistenceManager *persistMgr) {
persistMgr->transferUint32(TMEMBER(_autoSaveSlot));
persistMgr->transferBool(TMEMBER(_cursorHidden));
+ if (persistMgr->checkVersion(1, 3, 1)) {
+ _settings->persist(persistMgr);
+ }
+
if (!persistMgr->getIsSaving()) {
_quitting = false;
}
@@ -3892,6 +3896,11 @@ void BaseGame::expandStringByStringTable(char **str) const {
_settings->expandStringByStringTable(str);
}
+//////////////////////////////////////////////////////////////////////////
+void BaseGame::expandStringByStringTable(Common::String &str) const {
+ _settings->expandStringByStringTable(str);
+}
+
char *BaseGame::getKeyFromStringTable(const char *str) const {
return _settings->getKeyFromStringTable(str);
}
diff --git a/engines/wintermute/base/base_game.h b/engines/wintermute/base/base_game.h
index cdbbff6c93..e535cc9618 100644
--- a/engines/wintermute/base/base_game.h
+++ b/engines/wintermute/base/base_game.h
@@ -123,6 +123,7 @@ public:
inline BaseObject *getMainObject() { return _mainObject; }
inline BaseFont *getSystemFont() { return _systemFont; }
+ inline BaseFont *getVideoFont() { return _videoFont; }
bool initInput();
bool initLoop();
@@ -140,6 +141,7 @@ public:
// String Table
void expandStringByStringTable(char **str) const;
+ void expandStringByStringTable(Common::String &str) const;
char *getKeyFromStringTable(const char *str) const;
void LOG(bool res, const char *fmt, ...);
diff --git a/engines/wintermute/base/base_game_settings.cpp b/engines/wintermute/base/base_game_settings.cpp
index 3b54384cc7..996bada997 100644
--- a/engines/wintermute/base/base_game_settings.cpp
+++ b/engines/wintermute/base/base_game_settings.cpp
@@ -215,8 +215,17 @@ void BaseGameSettings::expandStringByStringTable(char **str) const {
_stringTable->expand(str);
}
+//////////////////////////////////////////////////////////////////////////
+void BaseGameSettings::expandStringByStringTable(Common::String &str) const {
+ _stringTable->expand(str);
+}
+
char *BaseGameSettings::getKeyFromStringTable(const char *str) const {
return _stringTable->getKey(str);
}
+bool BaseGameSettings::persist(BasePersistenceManager *persistMgr) {
+ return _stringTable->persist(persistMgr);
+}
+
} // End of namespace Wintermute
diff --git a/engines/wintermute/base/base_game_settings.h b/engines/wintermute/base/base_game_settings.h
index fe0e9907e6..15afb06450 100644
--- a/engines/wintermute/base/base_game_settings.h
+++ b/engines/wintermute/base/base_game_settings.h
@@ -34,6 +34,7 @@
namespace Wintermute {
class BaseStringTable;
class BaseGame;
+class BasePersistenceManager;
class BaseGameSettings {
public:
const char *getGameFile() const { return (_gameFile ? _gameFile : "default.game"); }
@@ -45,7 +46,10 @@ public:
bool loadSettings(const char *filename);
bool loadStringTable(const char *filename, bool clearOld);
void expandStringByStringTable(char **str) const;
+ void expandStringByStringTable(Common::String &str) const;
char *getKeyFromStringTable(const char *str) const;
+
+ bool persist(BasePersistenceManager *persistMgr);
private:
char *_gameFile;
int _resWidth;
diff --git a/engines/wintermute/base/base_keyboard_state.cpp b/engines/wintermute/base/base_keyboard_state.cpp
index 61087c5836..0babc07586 100644
--- a/engines/wintermute/base/base_keyboard_state.cpp
+++ b/engines/wintermute/base/base_keyboard_state.cpp
@@ -278,10 +278,24 @@ uint32 BaseKeyboardState::keyCodeToVKey(Common::Event *event) {
enum VKeyCodes {
kVkEscape = 27,
kVkSpace = 32,
+ kVkHome = 36,
kVkLeft = 37,
kVkUp = 38,
kVkRight = 39,
- kVkDown = 40
+ kVkDown = 40,
+
+ kVkF1 = 112,
+ kVkF2 = 113,
+ kVkF3 = 114,
+ kVkF4 = 115,
+ kVkF5 = 116,
+ kVkF6 = 117,
+ kVkF7 = 118,
+ kVkF8 = 119,
+ kVkF9 = 120,
+ kVkF10 = 121,
+ kVkF11 = 122,
+ kVkF12 = 123
};
//////////////////////////////////////////////////////////////////////////
@@ -290,22 +304,42 @@ Common::KeyCode BaseKeyboardState::vKeyToKeyCode(uint32 vkey) {
switch (vkey) {
case kVkEscape:
return Common::KEYCODE_ESCAPE;
- break;
case kVkSpace:
return Common::KEYCODE_SPACE;
- break;
+ case kVkHome:
+ return Common::KEYCODE_HOME;
case kVkLeft:
return Common::KEYCODE_LEFT;
- break;
case kVkRight:
return Common::KEYCODE_RIGHT;
- break;
case kVkUp:
return Common::KEYCODE_UP;
- break;
case kVkDown:
return Common::KEYCODE_DOWN;
- break;
+ case kVkF1:
+ return Common::KEYCODE_F1;
+ case kVkF2:
+ return Common::KEYCODE_F2;
+ case kVkF3:
+ return Common::KEYCODE_F3;
+ case kVkF4:
+ return Common::KEYCODE_F4;
+ case kVkF5:
+ return Common::KEYCODE_F5;
+ case kVkF6:
+ return Common::KEYCODE_F6;
+ case kVkF7:
+ return Common::KEYCODE_F7;
+ case kVkF8:
+ return Common::KEYCODE_F8;
+ case kVkF9:
+ return Common::KEYCODE_F9;
+ case kVkF10:
+ return Common::KEYCODE_F10;
+ case kVkF11:
+ return Common::KEYCODE_F11;
+ case kVkF12:
+ return Common::KEYCODE_F12;
default:
warning("Unknown VKEY: %d", vkey);
return (Common::KeyCode)vkey;
diff --git a/engines/wintermute/base/base_sprite.cpp b/engines/wintermute/base/base_sprite.cpp
index 04060bff32..09e138a1fd 100644
--- a/engines/wintermute/base/base_sprite.cpp
+++ b/engines/wintermute/base/base_sprite.cpp
@@ -41,6 +41,7 @@
#include "engines/wintermute/base/scriptables/script_value.h"
#include "engines/wintermute/base/scriptables/script.h"
#include "engines/wintermute/base/scriptables/script_stack.h"
+#include "engines/wintermute/game_description.h"
namespace Wintermute {
@@ -347,9 +348,17 @@ void BaseSprite::reset() {
} else {
_currentFrame = -1;
}
-
- killAllSounds();
-
+ if (BaseEngine::instance().getTargetExecutable() >= WME_1_8_6) {
+ /*
+ * This was added in WME 1.8.6
+ *
+ * 5MA and possibly other games ship with pre-1.8.6 WME, and
+ * depends (e.g.: menu sounds, etc) on this not being triggered.
+ *
+ * See bug #6647
+ */
+ killAllSounds();
+ }
_lastFrameTime = 0;
_finished = false;
_moveX = _moveY = 0;
diff --git a/engines/wintermute/base/base_string_table.cpp b/engines/wintermute/base/base_string_table.cpp
index 9adbbdf7be..4c750ebc93 100644
--- a/engines/wintermute/base/base_string_table.cpp
+++ b/engines/wintermute/base/base_string_table.cpp
@@ -147,6 +147,15 @@ void BaseStringTable::expand(char **str) const {
}
}
+//////////////////////////////////////////////////////////////////////////
+void BaseStringTable::expand(Common::String &str) const {
+ char *tmp = new char[str.size()+1];
+ strcpy(tmp, str.c_str());
+ expand(&tmp);
+ str = tmp;
+ delete[] tmp;
+}
+
//////////////////////////////////////////////////////////////////////////
const char *BaseStringTable::expandStatic(const char *string) const {
@@ -189,8 +198,10 @@ bool BaseStringTable::loadFile(const char *filename, bool clearOld) {
BaseEngine::LOG(0, "Loading string table...");
if (clearOld) {
+ _filenames.clear();
_strings.clear();
}
+ _filenames.push_back(Common::String(filename));
uint32 size;
byte *buffer = BaseFileManager::getEngineInstance()->readWholeFile(filename, &size);
@@ -253,4 +264,27 @@ bool BaseStringTable::loadFile(const char *filename, bool clearOld) {
return STATUS_OK;
}
+bool BaseStringTable::persist(BasePersistenceManager *persistMgr) {
+ // Do nothing if the save game is too old.
+ if (!persistMgr->checkVersion(1, 3, 1)) {
+ return true;
+ }
+ uint32 numFiles = _filenames.size();
+ persistMgr->transferUint32("NumFiles", &numFiles);
+ if (persistMgr->getIsSaving()) {
+ for (uint i = 0; i < numFiles; i++) {
+ persistMgr->transferString("Filename", &_filenames[i]);
+ }
+ } else {
+ _strings.clear();
+ _filenames.clear();
+ for (uint i = 0; i < numFiles; i++) {
+ Common::String filename = "";
+ persistMgr->transferString("Filename", &filename);
+ loadFile(filename.c_str(), false);
+ }
+ }
+ return true;
+}
+
} // End of namespace Wintermute
diff --git a/engines/wintermute/base/base_string_table.h b/engines/wintermute/base/base_string_table.h
index 9e915a1ad9..cfa3eeb226 100644
--- a/engines/wintermute/base/base_string_table.h
+++ b/engines/wintermute/base/base_string_table.h
@@ -35,17 +35,22 @@
namespace Wintermute {
+class BasePersistenceManager;
+
class BaseStringTable : public BaseClass {
public:
bool loadFile(const char *filename, bool deleteAll = true);
void expand(char **str) const;
+ void expand(Common::String &str) const;
const char *expandStatic(const char *string) const;
bool addString(const char *key, const char *val, bool reportDuplicities = true);
BaseStringTable(BaseGame *inGame);
virtual ~BaseStringTable();
char *getKey(const char *str) const;
+ bool persist(BasePersistenceManager *persistMgr);
private:
Common::HashMap<Common::String, Common::String> _strings;
+ Common::Array<Common::String> _filenames;
typedef Common::HashMap<Common::String, Common::String>::const_iterator StringsIter;
};
diff --git a/engines/wintermute/base/gfx/base_renderer.h b/engines/wintermute/base/gfx/base_renderer.h
index 42ff2cb9e1..6b1a4f97f4 100644
--- a/engines/wintermute/base/gfx/base_renderer.h
+++ b/engines/wintermute/base/gfx/base_renderer.h
@@ -72,7 +72,6 @@ public:
* Fade the screen to black
*
* @param alpha amount to fade by (alpha value of black)
- * @return
*/
virtual void fade(uint16 alpha) = 0;
/**
diff --git a/engines/wintermute/base/sound/base_sound.cpp b/engines/wintermute/base/sound/base_sound.cpp
index fa452cc0d6..b5b12d55f9 100644
--- a/engines/wintermute/base/sound/base_sound.cpp
+++ b/engines/wintermute/base/sound/base_sound.cpp
@@ -89,7 +89,7 @@ bool BaseSound::setSoundSimple() {
_sound->setLooping(_soundLooping);
_sound->setPrivateVolume(_soundPrivateVolume);
_sound->setLoopStart(_soundLoopStart);
- _sound->_freezePaused = _soundFreezePaused;
+ _sound->setFreezePaused(_soundFreezePaused);
if (_soundPlaying) {
return _sound->resume();
} else {
@@ -130,7 +130,7 @@ bool BaseSound::pause(bool freezePaused) {
if (_sound) {
_soundPaused = true;
if (freezePaused) {
- _sound->_freezePaused = true;
+ _sound->setFreezePaused(true);
}
return _sound->pause();
} else {
@@ -150,13 +150,13 @@ bool BaseSound::resume() {
bool BaseSound::persist(BasePersistenceManager *persistMgr) {
if (persistMgr->getIsSaving() && _sound) {
_soundPlaying = _sound->isPlaying();
- _soundLooping = _sound->_looping;
- _soundPrivateVolume = _sound->_privateVolume;
+ _soundLooping = _sound->isLooping();
+ _soundPrivateVolume = _sound->getPrivateVolume();
if (_soundPlaying) {
_soundPosition = _sound->getPosition();
}
- _soundLoopStart = _sound->_loopStart;
- _soundFreezePaused = _sound->_freezePaused;
+ _soundLoopStart = _sound->getLoopStart();
+ _soundFreezePaused = _sound->isFreezePaused();
}
if (persistMgr->getIsSaving()) {
@@ -232,7 +232,7 @@ bool BaseSound::setPrivateVolume(int volume) {
if (!_sound) {
return STATUS_FAILED;
} else {
- _sound->_privateVolume = volume;
+ _sound->setPrivateVolume(volume);
return STATUS_OK;
}
}
@@ -241,7 +241,7 @@ int BaseSound::getVolumePercent() {
if (!_sound) {
return 0;
} else {
- return _sound->_privateVolume * 100 / 255;
+ return _sound->getPrivateVolume() * 100 / 255;
}
}
@@ -249,7 +249,7 @@ int BaseSound::getVolume() {
if (!_sound) {
return 0;
} else {
- return _sound->_privateVolume;
+ return _sound->getPrivateVolume();
}
}
diff --git a/engines/wintermute/base/sound/base_sound_buffer.cpp b/engines/wintermute/base/sound/base_sound_buffer.cpp
index 7ec68ea752..5fdac12cef 100644
--- a/engines/wintermute/base/sound/base_sound_buffer.cpp
+++ b/engines/wintermute/base/sound/base_sound_buffer.cpp
@@ -143,8 +143,13 @@ bool BaseSoundBuffer::play(bool looping, uint32 startSample) {
_stream->seek(startSample);
_handle = new Audio::SoundHandle;
if (_looping) {
- Audio::AudioStream *loopStream = new Audio::LoopingAudioStream(_stream, 0, DisposeAfterUse::NO);
- g_system->getMixer()->playStream(_type, _handle, loopStream, -1, _volume, _pan, DisposeAfterUse::YES);
+ if (_loopStart != 0) {
+ Audio::AudioStream *loopStream = new Audio::SubLoopingAudioStream(_stream, 0, Audio::Timestamp(_loopStart, _stream->getRate()), _stream->getLength(), DisposeAfterUse::NO);
+ g_system->getMixer()->playStream(_type, _handle, loopStream, -1, _volume, _pan, DisposeAfterUse::YES);
+ } else {
+ Audio::AudioStream *loopStream = new Audio::LoopingAudioStream(_stream, 0, DisposeAfterUse::NO);
+ g_system->getMixer()->playStream(_type, _handle, loopStream, -1, _volume, _pan, DisposeAfterUse::YES);
+ }
} else {
g_system->getMixer()->playStream(_type, _handle, _stream, -1, _volume, _pan, DisposeAfterUse::NO);
}
@@ -296,4 +301,24 @@ bool BaseSoundBuffer::applyFX(TSFXType type, float param1, float param2, float p
return STATUS_OK;
}
+int32 BaseSoundBuffer::getPrivateVolume() const {
+ return _privateVolume;
+}
+
+bool BaseSoundBuffer::isLooping() const {
+ return _looping;
+}
+
+bool BaseSoundBuffer::isFreezePaused() const {
+ return _freezePaused;
+}
+
+void BaseSoundBuffer::setFreezePaused(bool freezePaused) {
+ _freezePaused = freezePaused;
+}
+
+Audio::Mixer::SoundType BaseSoundBuffer::getType() const {
+ return _type;
+}
+
} // End of namespace Wintermute
diff --git a/engines/wintermute/base/sound/base_sound_buffer.h b/engines/wintermute/base/sound/base_sound_buffer.h
index 94bc8dc6ad..b3f3046674 100644
--- a/engines/wintermute/base/sound/base_sound_buffer.h
+++ b/engines/wintermute/base/sound/base_sound_buffer.h
@@ -71,23 +71,26 @@ public:
void updateVolume();
void setType(Audio::Mixer::SoundType Type);
+ Audio::Mixer::SoundType getType() const;
bool loadFromFile(const Common::String &filename, bool forceReload = false);
void setStreaming(bool streamed, uint32 numBlocks = 0, uint32 blockSize = 0);
bool applyFX(TSFXType type, float param1, float param2, float param3, float param4);
-
+ int32 getPrivateVolume() const;
+ void setFreezePaused(bool freezePaused);
+ bool isFreezePaused() const;
+ bool isLooping() const;
//HSTREAM _stream;
//HSYNC _sync;
+
+private:
+ Audio::Mixer::SoundType _type;
Audio::SeekableAudioStream *_stream;
Audio::SoundHandle *_handle;
-
bool _freezePaused;
- uint32 _loopStart;
- Audio::Mixer::SoundType _type;
bool _looping;
-
int32 _privateVolume;
-private:
+ uint32 _loopStart;
uint32 _startPos;
Common::String _filename;
bool _streamed;
diff --git a/engines/wintermute/base/sound/base_sound_manager.cpp b/engines/wintermute/base/sound/base_sound_manager.cpp
index 41cfe5ea62..f1e0c3b1f9 100644
--- a/engines/wintermute/base/sound/base_sound_manager.cpp
+++ b/engines/wintermute/base/sound/base_sound_manager.cpp
@@ -254,9 +254,9 @@ byte BaseSoundMgr::getMasterVolume() {
bool BaseSoundMgr::pauseAll(bool includingMusic) {
for (uint32 i = 0; i < _sounds.size(); i++) {
- if (_sounds[i]->isPlaying() && (_sounds[i]->_type != Audio::Mixer::kMusicSoundType || includingMusic)) {
+ if (_sounds[i]->isPlaying() && (_sounds[i]->getType() != Audio::Mixer::kMusicSoundType || includingMusic)) {
_sounds[i]->pause();
- _sounds[i]->_freezePaused = true;
+ _sounds[i]->setFreezePaused(true);
}
}
@@ -268,9 +268,9 @@ bool BaseSoundMgr::pauseAll(bool includingMusic) {
bool BaseSoundMgr::resumeAll() {
for (uint32 i = 0; i < _sounds.size(); i++) {
- if (_sounds[i]->_freezePaused) {
+ if (_sounds[i]->isFreezePaused()) {
_sounds[i]->resume();
- _sounds[i]->_freezePaused = false;
+ _sounds[i]->setFreezePaused(false);
}
}
diff --git a/engines/wintermute/dcgf.h b/engines/wintermute/dcgf.h
index 78503b8c3b..c919180e45 100644
--- a/engines/wintermute/dcgf.h
+++ b/engines/wintermute/dcgf.h
@@ -32,8 +32,8 @@
//////////////////////////////////////////////////////////////////////////
#define DCGF_VER_MAJOR 1
-#define DCGF_VER_MINOR 2
-#define DCGF_VER_BUILD 2
+#define DCGF_VER_MINOR 3
+#define DCGF_VER_BUILD 1
#define DCGF_VER_SUFFIX "ScummVM"
#define DCGF_VER_BETA true
diff --git a/engines/wintermute/detection.cpp b/engines/wintermute/detection.cpp
index a659c434d0..aca682ae99 100644
--- a/engines/wintermute/detection.cpp
+++ b/engines/wintermute/detection.cpp
@@ -74,7 +74,7 @@ static const char *directoryGlobs[] = {
class WintermuteMetaEngine : public AdvancedMetaEngine {
public:
- WintermuteMetaEngine() : AdvancedMetaEngine(Wintermute::gameDescriptions, sizeof(ADGameDescription), Wintermute::wintermuteGames, gameGuiOptions) {
+ WintermuteMetaEngine() : AdvancedMetaEngine(Wintermute::gameDescriptions, sizeof(WMEGameDescription), Wintermute::wintermuteGames, gameGuiOptions) {
_singleid = "wintermute";
_guioptions = GUIO2(GUIO_NOMIDI, GAMEOPTION_SHOW_FPS);
_maxScanDepth = 2;
@@ -127,8 +127,8 @@ public:
virtual bool createInstance(OSystem *syst, Engine **engine, const ADGameDescription *desc) const {
assert(syst);
assert(engine);
-
- *engine = new Wintermute::WintermuteEngine(syst, desc);
+ const WMEGameDescription *gd = (const WMEGameDescription *)desc;
+ *engine = new Wintermute::WintermuteEngine(syst, gd);
return true;
}
diff --git a/engines/wintermute/detection_tables.h b/engines/wintermute/detection_tables.h
index 8206ca9643..4e3320159a 100644
--- a/engines/wintermute/detection_tables.h
+++ b/engines/wintermute/detection_tables.h
@@ -90,1342 +90,458 @@ static const PlainGameDescriptor wintermuteGames[] = {
{0, 0}
};
-static const ADGameDescription gameDescriptions[] = {
+// Duplicates WME_ENTRY1s, for consistency
+#define WME_ENTRY1s(f1, h1, s1) { {f1, 0, h1, s1}, AD_LISTEND }
+#define WME_ENTRY2s(f1, h1, s1, f2, h2, s2) { {f1, 0, h1, s1}, {f2, 0, h2, s2}, AD_LISTEND }
+#define WME_ENTRY3s(f1, h1, s1, f2, h2, s2, f3, h3, s3) { {f1, 0, h1, s1}, {f2, 0, h2, s2}, {f3, 0, h3, s3}, AD_LISTEND }
+
+#define WME_PLATENTRY(shortName, extraName, hashEntry, lang, plat, status, version) \
+ { \
+ { \
+ shortName, \
+ extraName, \
+ hashEntry, \
+ lang, \
+ plat, \
+ status, \
+ GUIO0(), \
+ }, \
+ version \
+ }
+
+// Convenience variant, as most of the games are Windows-games
+#define WME_WINENTRY(shortName, extraName, hashEntry, lang, status, version) \
+ { \
+ { \
+ shortName, \
+ extraName, \
+ hashEntry, \
+ lang, \
+ Common::kPlatformWindows, \
+ status, \
+ GUIO0(), \
+ }, \
+ version \
+ }
+
+/* To add new entries:
+ * Make sure you have a target name defined at the top of the file
+ *
+ * If the game has only one language, and can be detected using only one file,
+ * then use WME_WINENTRY, with WME_ENTRY1s as exemplified below.
+ *
+ * If the game has more than one language, and the main data file is common across
+ * the versions, then you should use WME_WINENTRY with WME_ENTRY2s/WME_ENTRY3s, with
+ * the language file as the first hit, and the data file as the second. (Make sure to
+ * NOT create a WME_ENTRY1s matching the same data file as the 2/3 file match)
+ */
+
+static const WMEGameDescription gameDescriptions[] = {
// Five Lethal Demons
- {
- "5ld",
- "",
- AD_ENTRY1s("data.dcp", "1037a77cbd001e0644898addc022322c", 15407750),
- Common::EN_ANY,
- Common::kPlatformWindows,
- ADGF_UNSTABLE,
- GUIO0()
- },
+ WME_WINENTRY("5ld", "",
+ WME_ENTRY1s("data.dcp", "1037a77cbd001e0644898addc022322c", 15407750), Common::EN_ANY, ADGF_UNSTABLE, LATEST_VERSION),
// Five Magical Amulets
- {
- "5ma",
- "",
- AD_ENTRY1s("data.dcp", "0134e92bcd5fd2837df3971087e96067", 163316498),
- Common::EN_ANY,
- Common::kPlatformWindows,
- ADGF_UNSTABLE,
- GUIO0()
- },
+ WME_WINENTRY("5ma", "",
+ WME_ENTRY1s("data.dcp", "0134e92bcd5fd2837df3971087e96067", 163316498), Common::EN_ANY, ADGF_UNSTABLE, WME_1_7_0),
// Actual Destination
- {
- "actualdest",
- "",
- AD_ENTRY1s("data.dcp", "6926f44b26f21ceb1d840eaab9aeb510", 9081740),
- Common::EN_ANY,
- Common::kPlatformWindows,
- ADGF_UNSTABLE,
- GUIO0()
- },
+ WME_WINENTRY("actualdest", "",
+ WME_ENTRY1s("data.dcp", "6926f44b26f21ceb1d840eaab9aeb510", 9081740), Common::EN_ANY, ADGF_UNSTABLE, LATEST_VERSION),
// Boredom of Agustin Cordes
- {
- "agustin",
- "",
- AD_ENTRY1s("data.dcp", "abb79c16c9b92e9b06525a4c7c3f5861", 2461949),
- Common::EN_ANY,
- Common::kPlatformWindows,
- ADGF_UNSTABLE,
- GUIO0()
- },
+ WME_WINENTRY("agustin", "",
+ WME_ENTRY1s("data.dcp", "abb79c16c9b92e9b06525a4c7c3f5861", 2461949), Common::EN_ANY, ADGF_UNSTABLE, LATEST_VERSION),
// Beyond the Threshold
- {
- "bthreshold",
- "",
- AD_ENTRY1s("data.dcp", "d49bf9ccb2e74507447c82d6ad3e2bc4", 12773712),
- Common::EN_ANY,
- Common::kPlatformWindows,
- ADGF_UNSTABLE,
- GUIO0()
- },
+ WME_WINENTRY("bthreshold", "",
+ WME_ENTRY1s("data.dcp", "d49bf9ccb2e74507447c82d6ad3e2bc4", 12773712), Common::EN_ANY, ADGF_UNSTABLE, LATEST_VERSION),
// Bickadoodle
- {
- "bickadoodle",
- "",
- AD_ENTRY1s("data.dcp", "84db4d1594cac95e25614985775d10a8", 35303844),
- Common::EN_ANY,
- Common::kPlatformWindows,
- ADGF_UNSTABLE,
- GUIO0()
- },
+ WME_WINENTRY("bickadoodle", "",
+ WME_ENTRY1s("data.dcp", "84db4d1594cac95e25614985775d10a8", 35303844), Common::EN_ANY, ADGF_UNSTABLE, LATEST_VERSION),
// Bickadoodle (Ver 1.1)
- {
- "bickadoodle",
- "Version 1.1",
- AD_ENTRY1s("data.dcp", "8bb52ac9a9ee129c5059e8e808b669d7", 35337760),
- Common::EN_ANY,
- Common::kPlatformWindows,
- ADGF_UNSTABLE,
- GUIO0()
- },
+ WME_WINENTRY("bickadoodle", "Version 1.1",
+ WME_ENTRY1s("data.dcp", "8bb52ac9a9ee129c5059e8e808b669d7", 35337760), Common::EN_ANY, ADGF_UNSTABLE, LATEST_VERSION),
+ // Bickadoodle (Ver 1.2)
+ WME_WINENTRY("bickadoodle", "Version 1.2",
+ WME_ENTRY1s("data.dcp", "1796a48f3ed72dd785ce93334ab883cc", 35337760), Common::EN_ANY, ADGF_UNSTABLE, LATEST_VERSION),
// Bickadoodle (download from http://aethericgames.com/games/bickadoodle/download-bickadoodle/)
- {
- "bickadoodle",
- "",
- AD_ENTRY1s("data.dcp", "1584d83577c32add0fce27fae91141a2", 35337728),
- Common::EN_ANY,
- Common::kPlatformWindows,
- ADGF_UNSTABLE,
- GUIO0()
- },
+ WME_WINENTRY("bickadoodle", "",
+ WME_ENTRY1s("data.dcp", "1584d83577c32add0fce27fae91141a2", 35337728), Common::EN_ANY, ADGF_UNSTABLE, LATEST_VERSION),
// Book of Gron Part One
- {
- "bookofgron",
- "",
- AD_ENTRY1s("data.dcp", "e61b2ebee044a82fa0f8ca0fce2c8946", 83129531),
- Common::RU_RUS,
- Common::kPlatformWindows,
- ADGF_UNSTABLE,
- GUIO0()
- },
+ WME_WINENTRY("bookofgron", "",
+ WME_ENTRY1s("data.dcp", "e61b2ebee044a82fa0f8ca0fce2c8946", 83129531), Common::RU_RUS, ADGF_UNSTABLE, LATEST_VERSION),
// Carol Reed 4 - East Side Story (Demo)
- {
- "carolreed4",
- "Demo",
- AD_ENTRY1s("data.dcp", "b3f8b09bb4b05ee3e9d14697525257f9", 59296246),
- Common::EN_ANY,
- Common::kPlatformWindows,
- ADGF_UNSTABLE |
- ADGF_DEMO,
- GUIO0()
- },
+ WME_WINENTRY("carolreed4", "Demo",
+ WME_ENTRY1s("data.dcp", "b3f8b09bb4b05ee3e9d14697525257f9", 59296246), Common::EN_ANY, ADGF_UNSTABLE | ADGF_DEMO, LATEST_VERSION),
// Carol Reed 4 - East Side Story
- {
- "carolreed4",
- "",
- AD_ENTRY1s("data.dcp", "b26377797f060afc2d440d820100c1ce", 529320536),
- Common::EN_ANY,
- Common::kPlatformWindows,
- ADGF_UNSTABLE |
- ADGF_DEMO,
- GUIO0()
- },
+ WME_WINENTRY("carolreed4", "",
+ WME_ENTRY1s("data.dcp", "b26377797f060afc2d440d820100c1ce", 529320536), Common::EN_ANY, ADGF_UNSTABLE | ADGF_DEMO, LATEST_VERSION),
// Carol Reed 5 - The Colour of Murder
- {
- "carolreed5",
- "",
- AD_ENTRY1s("data.dcp", "3fcfca44209545d0e26774156427b494", 603660415),
- Common::EN_ANY,
- Common::kPlatformWindows,
- ADGF_UNSTABLE,
- GUIO0()
- },
+ WME_WINENTRY("carolreed5", "",
+ WME_ENTRY1s("data.dcp", "3fcfca44209545d0e26774156427b494", 603660415), Common::EN_ANY, ADGF_UNSTABLE, LATEST_VERSION),
// Carol Reed 6 - Black Circle
- {
- "carolreed6",
- "",
- AD_ENTRY1s("data.dcp", "0e4c532beecf23d85012168753f41189", 456258147),
- Common::EN_ANY,
- Common::kPlatformWindows,
- ADGF_UNSTABLE,
- GUIO0()
- },
+ WME_WINENTRY("carolreed6", "",
+ WME_ENTRY1s("data.dcp", "0e4c532beecf23d85012168753f41189", 456258147), Common::EN_ANY, ADGF_UNSTABLE, LATEST_VERSION),
// Carol Reed 7 - Blue Madonna (Demo)
- {
- "carolreed7",
- "Demo",
- AD_ENTRY1s("data.dcp", "0372ad0c775266f6355e9e8ae397a2f1", 103719442),
- Common::EN_ANY,
- Common::kPlatformWindows,
- ADGF_UNSTABLE |
- ADGF_DEMO,
- GUIO0()
- },
+ WME_WINENTRY("carolreed7", "Demo",
+ WME_ENTRY1s("data.dcp", "0372ad0c775266f6355e9e8ae397a2f1", 103719442), Common::EN_ANY, ADGF_UNSTABLE | ADGF_DEMO, LATEST_VERSION),
// Carol Reed 7 - Blue Madonna
- {
- "carolreed7",
- "",
- AD_ENTRY1s("data.dcp", "24e3db3e2fabfc956713796d87a3efb0", 495471147),
- Common::EN_ANY,
- Common::kPlatformWindows,
- ADGF_UNSTABLE,
- GUIO0()
- },
+ WME_WINENTRY("carolreed7", "",
+ WME_ENTRY1s("data.dcp", "24e3db3e2fabfc956713796d87a3efb0", 495471147), Common::EN_ANY, ADGF_UNSTABLE, LATEST_VERSION),
// Carol Reed 8 - Amber's Blood
- {
- "carolreed8",
- "",
- AD_ENTRY1s("data.dcp", "859d16b0d5b9b255e470cbded2c6cedc", 502714557),
- Common::EN_ANY,
- Common::kPlatformWindows,
- ADGF_UNSTABLE,
- GUIO0()
- },
+ WME_WINENTRY("carolreed8", "",
+ WME_ENTRY1s("data.dcp", "859d16b0d5b9b255e470cbded2c6cedc", 502714557), Common::EN_ANY, ADGF_UNSTABLE, LATEST_VERSION),
// Carol Reed 9 - Cold Case Summer
- {
- "carolreed9",
- "",
- AD_ENTRY1s("data.dcp", "2b343b48a7aee508d728a546b414a255", 620005266),
- Common::EN_ANY,
- Common::kPlatformWindows,
- ADGF_UNSTABLE,
- GUIO0()
- },
+ WME_WINENTRY("carolreed9", "",
+ WME_ENTRY1s("data.dcp", "2b343b48a7aee508d728a546b414a255", 620005266), Common::EN_ANY, ADGF_UNSTABLE, LATEST_VERSION),
// Chivalry is Not Dead
- {
- "chivalry",
- "",
- AD_ENTRY1s("data.dcp", "ebd0915d9a12df5224be22f53bb23eb6", 7278306),
- Common::EN_ANY,
- Common::kPlatformWindows,
- ADGF_TESTING,
- GUIO0()
- },
+ WME_WINENTRY("chivalry", "",
+ WME_ENTRY1s("data.dcp", "ebd0915d9a12df5224be22f53bb23eb6", 7278306), Common::EN_ANY, ADGF_TESTING, LATEST_VERSION),
// Chivalry is Not Dead (Version from deirdrakai.com)
- {
- "chivalry",
- "",
- AD_ENTRY1s("data.dcp", "ae6d91b9517f4d2851a8ad94c96951c8", 7278302),
- Common::EN_ANY,
- Common::kPlatformWindows,
- ADGF_TESTING,
- GUIO0()
- },
+ WME_WINENTRY("chivalry", "",
+ WME_ENTRY1s("data.dcp", "ae6d91b9517f4d2851a8ad94c96951c8", 7278302), Common::EN_ANY, ADGF_TESTING, LATEST_VERSION),
// Conspiracao Dumont
- {
- "conspiracao",
- "",
- AD_ENTRY1s("ConspiracaoDumont.exe", "106f3f2c8f18bb5ffffeed634ace256c", 32908032),
- Common::EN_ANY,
- Common::kPlatformWindows,
- ADGF_UNSTABLE |
- ADGF_DEMO,
- GUIO0()
- },
+ WME_WINENTRY("conspiracao", "",
+ WME_ENTRY1s("ConspiracaoDumont.exe", "106f3f2c8f18bb5ffffeed634ace256c", 32908032), Common::EN_ANY, ADGF_UNSTABLE | ADGF_DEMO, LATEST_VERSION),
// Corrosion: Cold Winter Waiting
- {
- "corrosion",
- "",
- AD_ENTRY1s("data.dcp", "ae885b1a8faa0b27f43c0e8f0df02fc9", 525931618),
- Common::EN_ANY,
- Common::kPlatformWindows,
- ADGF_TESTING,
- GUIO0()
- },
+ WME_WINENTRY("corrosion", "",
+ WME_ENTRY1s("data.dcp", "ae885b1a8faa0b27f43c0e8f0df02fc9", 525931618), Common::EN_ANY, ADGF_TESTING, LATEST_VERSION),
// Dead City (Czech)
- {
- "deadcity",
- "",
- {
- // The Czech data are in data.dcp, so in this case we'll have to
- // just detect the english version twice, to give the user a choice.
- {"english.dcp", 0, "c591046d6de7e381d76f70e0787b2b1f", 415935},
- {"data.dcp", 0, "7ebfd50d1a22370ed7b079bcaa631d62", 9070205},
- AD_LISTEND
- },
- Common::CZ_CZE,
- Common::kPlatformWindows,
- ADGF_UNSTABLE,
- GUIO0()
- },
+ // The Czech data are in data.dcp, so in this case we'll have to
+ // just detect the english version twice, to give the user a choice.
+ WME_WINENTRY("deadcity", "",
+ WME_ENTRY2s("english.dcp", "c591046d6de7e381d76f70e0787b2b1f", 415935,
+ "data.dcp", "7ebfd50d1a22370ed7b079bcaa631d62", 9070205), Common::CZ_CZE, ADGF_UNSTABLE, LATEST_VERSION),
// Dead City (English)
- {
- "deadcity",
- "",
- {
- {"english.dcp", 0, "c591046d6de7e381d76f70e0787b2b1f", 415935},
- {"data.dcp", 0, "7ebfd50d1a22370ed7b079bcaa631d62", 9070205},
- AD_LISTEND
- },
- Common::EN_ANY,
- Common::kPlatformWindows,
- ADGF_UNSTABLE,
- GUIO0()
- },
+ WME_WINENTRY("deadcity", "",
+ WME_ENTRY2s("english.dcp", "c591046d6de7e381d76f70e0787b2b1f", 415935,
+ "data.dcp", "7ebfd50d1a22370ed7b079bcaa631d62", 9070205), Common::EN_ANY, ADGF_UNSTABLE, LATEST_VERSION),
// Dead City (Italian)
- {
- "deadcity",
- "",
- {
- {"italian.dcp", 0, "92d8efb94436bec7bd1b7fe0b548192e", 454037},
- {"data.dcp", 0, "7ebfd50d1a22370ed7b079bcaa631d62", 9070205},
- AD_LISTEND
- },
- Common::IT_ITA,
- Common::kPlatformWindows,
- ADGF_UNSTABLE,
- GUIO0()
- },
+ WME_WINENTRY("deadcity", "",
+ WME_ENTRY2s("italian.dcp", "92d8efb94436bec7bd1b7fe0b548192e", 454037,
+ "data.dcp", "7ebfd50d1a22370ed7b079bcaa631d62", 9070205), Common::IT_ITA, ADGF_UNSTABLE, LATEST_VERSION),
// Dead City (Russian)
- {
- "deadcity",
- "",
- {
- {"russian.dcp", 0, "a0ae71e9e1185596fffb07ad2c951eb9", 653317},
- {"data.dcp", 0, "7ebfd50d1a22370ed7b079bcaa631d62", 9070205},
- AD_LISTEND
- },
- Common::RU_RUS,
- Common::kPlatformWindows,
- ADGF_UNSTABLE,
- GUIO0()
- },
+ WME_WINENTRY("deadcity", "",
+ WME_ENTRY2s("russian.dcp", "a0ae71e9e1185596fffb07ad2c951eb9", 653317,
+ "data.dcp", "7ebfd50d1a22370ed7b079bcaa631d62", 9070205), Common::RU_RUS, ADGF_UNSTABLE, LATEST_VERSION),
// Dirty Split (Czech)
- {
- "dirtysplit",
- "",
- {
- {"czech.dcp", 0, "08a71446467cf8f9444cfea446b46ad6", 127697934},
- {"data.dcp", 0, "8b4b81b718bf65f30a67fc0b1e329eb5", 88577623},
- },
- Common::CZ_CZE,
- Common::kPlatformWindows,
- ADGF_UNSTABLE,
- GUIO0()
- },
+ WME_WINENTRY("dirtysplit", "",
+ WME_ENTRY2s("czech.dcp", "08a71446467cf8f9444cfea446b46ad6", 127697934,
+ "data.dcp", "8b4b81b718bf65f30a67fc0b1e329eb5", 88577623), Common::CZ_CZE, ADGF_UNSTABLE, LATEST_VERSION),
// Dirty Split (English)
- {
- "dirtysplit",
- "",
- AD_ENTRY1s("data.dcp", "8f3dae199361ece0f59fb20cfff6eed3", 88577621),
- Common::EN_ANY,
- Common::kPlatformWindows,
- ADGF_UNSTABLE,
- GUIO0()
- },
+ WME_WINENTRY("dirtysplit", "",
+ WME_ENTRY1s("data.dcp", "8f3dae199361ece0f59fb20cfff6eed3", 88577621), Common::EN_ANY, ADGF_UNSTABLE, LATEST_VERSION),
// Dirty Split (French)
- {
- "dirtysplit",
- "",
- {
- {"french.dcp", 0, "a0508dedebd0fe478d0158fa4c2a1136", 125534323},
- {"data.dcp", 0, "e6d70c7f5d181b761cfcf974adf9186a", 88577623},
- AD_LISTEND
- },
- Common::FR_FRA,
- Common::kPlatformWindows,
- ADGF_UNSTABLE,
- GUIO0()
- },
+ WME_WINENTRY("dirtysplit", "",
+ WME_ENTRY2s("french.dcp", "a0508dedebd0fe478d0158fa4c2a1136", 125534323,
+ "data.dcp", "e6d70c7f5d181b761cfcf974adf9186a", 88577623), Common::FR_FRA, ADGF_UNSTABLE, LATEST_VERSION),
// Dirty Split (German)
- {
- "dirtysplit",
- "",
- AD_ENTRY1s("data.dcp", "139d8a25579e969f8b37d20e6e3de5f9", 92668291),
- Common::DE_DEU,
- Common::kPlatformWindows,
- ADGF_UNSTABLE,
- GUIO0()
- },
+ WME_WINENTRY("dirtysplit", "",
+ WME_ENTRY1s("data.dcp", "139d8a25579e969f8b37d20e6e3de5f9", 92668291), Common::DE_DEU, ADGF_UNSTABLE, LATEST_VERSION),
// Dirty Split (Italian)
- {
- "dirtysplit",
- "",
- {
- {"italian.dcp", 0, "8108807fbd8af70be1ec452d0fd1131b", 125513726},
- {"data.dcp", 0, "35a150e22af274185883fdbb142c6fb1", 88577623},
- },
- Common::IT_ITA,
- Common::kPlatformWindows,
- ADGF_UNSTABLE,
- GUIO0()
- },
+ WME_WINENTRY("dirtysplit", "",
+ WME_ENTRY2s("italian.dcp", "8108807fbd8af70be1ec452d0fd1131b", 125513726,
+ "data.dcp", "35a150e22af274185883fdbb142c6fb1", 88577623), Common::IT_ITA, ADGF_UNSTABLE, LATEST_VERSION),
// Dirty Split (Spanish)
- {
- "dirtysplit",
- "",
- {
- {"spanish.dcp", 0, "b3982c0a5e85b42e1e38240fef004aa4", 164428596},
- {"data.dcp", 0, "63766d6c68b9f00b632ea1736fc8a95c", 88577621},
- },
- Common::ES_ESP,
- Common::kPlatformWindows,
- ADGF_UNSTABLE,
- GUIO0()
- },
+ WME_WINENTRY("dirtysplit", "",
+ WME_ENTRY2s("spanish.dcp", "b3982c0a5e85b42e1e38240fef004aa4", 164428596,
+ "data.dcp", "63766d6c68b9f00b632ea1736fc8a95c", 88577621), Common::ES_ESP, ADGF_UNSTABLE, LATEST_VERSION),
// Des Reves Elastiques Avec Mille Insectes Nommes Georges
- {
- "dreaming",
- "",
- AD_ENTRY1s("data.dcp", "4af26d97ea063fc1277ce30ae431de90", 8804073),
- Common::EN_ANY,
- Common::kPlatformWindows,
- ADGF_UNSTABLE,
- GUIO0()
- },
+ WME_WINENTRY("dreaming", "",
+ WME_ENTRY1s("data.dcp", "4af26d97ea063fc1277ce30ae431de90", 8804073), Common::EN_ANY, ADGF_UNSTABLE, LATEST_VERSION),
// Dreamscape
- {
- "dreamscape",
- "",
- AD_ENTRY1s("data.dcp", "7a5752ed4446c862be9f02d7932acf54", 17034377),
- Common::EN_ANY,
- Common::kPlatformWindows,
- ADGF_UNSTABLE,
- GUIO0()
- },
+ WME_WINENTRY("dreamscape", "",
+ WME_ENTRY1s("data.dcp", "7a5752ed4446c862be9f02d7932acf54", 17034377), Common::EN_ANY, ADGF_UNSTABLE, LATEST_VERSION),
// Escape from the Mansion
- {
- "escapemansion",
- "Beta 1",
- AD_ENTRY1s("data.dcp", "d8e348b2312cc36a929cad75f12e0b3a", 21452380),
- Common::EN_ANY,
- Common::kPlatformWindows,
- ADGF_UNSTABLE,
- GUIO0()
- },
+ WME_WINENTRY("escapemansion", "Beta 1",
+ WME_ENTRY1s("data.dcp", "d8e348b2312cc36a929cad75f12e0b3a", 21452380), Common::EN_ANY, ADGF_UNSTABLE, LATEST_VERSION),
// Escape from the Mansion
- {
- "escapemansion",
- "Beta 2",
- AD_ENTRY1s("data.dcp", "ded5fa6c5f2afdaf2cafb53e52cd3dd8", 21455763),
- Common::EN_ANY,
- Common::kPlatformWindows,
- ADGF_UNSTABLE,
- GUIO0()
- },
+ WME_WINENTRY("escapemansion", "Beta 2",
+ WME_ENTRY1s("data.dcp", "ded5fa6c5f2afdaf2cafb53e52cd3dd8", 21455763), Common::EN_ANY, ADGF_UNSTABLE, LATEST_VERSION),
// Escape from the Mansion
- {
- "escapemansion",
- "1.3",
- AD_ENTRY1s("data.dcp", "1e5d231b56c8a228cd15cb690f50253e", 29261972),
- Common::EN_ANY,
- Common::kPlatformWindows,
- ADGF_UNSTABLE,
- GUIO0()
- },
+ WME_WINENTRY("escapemansion", "1.3",
+ WME_ENTRY1s("data.dcp", "1e5d231b56c8a228cd15cb690f50253e", 29261972), Common::EN_ANY, ADGF_UNSTABLE, LATEST_VERSION),
// Four
- {
- "four",
- "",
- AD_ENTRY1s("data.dcp", "ec05cd5e37c9a524053b8859635a4234", 62599855),
- Common::EN_ANY,
- Common::kPlatformWindows,
- ADGF_UNSTABLE,
- GUIO0()
- },
+ WME_WINENTRY("four", "",
+ WME_ENTRY1s("data.dcp", "ec05cd5e37c9a524053b8859635a4234", 62599855), Common::EN_ANY, ADGF_UNSTABLE, LATEST_VERSION),
// Framed
- {
- "framed",
- "",
- AD_ENTRY1s("data.dcp", "e7259fb36f2c6f9f28242291e0c3de98", 34690568),
- Common::EN_ANY,
- Common::kPlatformWindows,
- ADGF_UNSTABLE,
- GUIO0()
- },
+ WME_WINENTRY("framed", "",
+ WME_ENTRY1s("data.dcp", "e7259fb36f2c6f9f28242291e0c3de98", 34690568), Common::EN_ANY, ADGF_UNSTABLE, LATEST_VERSION),
// Ghost in the Sheet
- {
- "ghostsheet",
- "",
- {
- {"english.dcp", 0, "e6d0aad2c89996bcabe416105a3d6d3a", 12221017},
- {"data.dcp", 0, "b2f8b05328e4881e15e98e845b63f451", 168003},
- AD_LISTEND
- },
- Common::EN_ANY,
- Common::kPlatformWindows,
- ADGF_UNSTABLE,
- GUIO0()
- },
+ WME_WINENTRY("ghostsheet", "",
+ WME_ENTRY2s("english.dcp", "e6d0aad2c89996bcabe416105a3d6d3a", 12221017,
+ "data.dcp", "b2f8b05328e4881e15e98e845b63f451", 168003), Common::EN_ANY, ADGF_UNSTABLE, LATEST_VERSION),
// Ghost in the Sheet (Demo)
- {
- "ghostsheet",
- "Demo",
- AD_ENTRY1s("data.dcp", "dc1f6595f412ac25a52eaf47dad4ab81", 169083),
- Common::EN_ANY,
- Common::kPlatformWindows,
- ADGF_UNSTABLE |
- ADGF_DEMO,
- GUIO0()
- },
+ WME_WINENTRY("ghostsheet", "Demo",
+ WME_ENTRY1s("data.dcp", "dc1f6595f412ac25a52eaf47dad4ab81", 169083), Common::EN_ANY, ADGF_UNSTABLE | ADGF_DEMO, LATEST_VERSION),
// Hamlet or the last game without MMORPS features, shaders and product placement
- {
- "hamlet",
- "",
- AD_ENTRY1s("data.dcp", "f624add957a77c9930529fb28cc2450f", 88183022),
- Common::EN_ANY,
- Common::kPlatformWindows,
- ADGF_UNSTABLE,
- GUIO0()
- },
+ WME_WINENTRY("hamlet", "",
+
+ WME_ENTRY1s("data.dcp", "f624add957a77c9930529fb28cc2450f", 88183022), Common::EN_ANY, ADGF_UNSTABLE, LATEST_VERSION),
// Helga Deep In Trouble (English)
- {
- "helga",
- "",
- {
- {"english.dcp", 0, "bfa136b21bdbc7d8691c0770a6d40bc3", 135931},
- {"data.dcp", 0, "25cb955a60b58326f2eeda1ce288fb37", 183251259},
- AD_LISTEND
- },
- Common::EN_ANY,
- Common::kPlatformWindows,
- ADGF_UNSTABLE,
- GUIO0()
- },
+ WME_WINENTRY("helga", "",
+ WME_ENTRY2s("english.dcp", "bfa136b21bdbc7d8691c0770a6d40bc3", 135931,
+ "data.dcp", "25cb955a60b58326f2eeda1ce288fb37", 183251259), Common::EN_ANY, ADGF_UNSTABLE, LATEST_VERSION),
// Helga Deep In Trouble (Demo) (English)
- {
- "helga",
- "Demo",
- {
- {"english.dcp", 0, "b3a93e678f0ef97200f691cd1724643f", 135864},
- {"data.dcp", 0, "45134ed93bc391edf148b79cdcbf2a09", 154266028},
- AD_LISTEND
- },
- Common::EN_ANY,
- Common::kPlatformWindows,
- ADGF_UNSTABLE |
- ADGF_DEMO,
- GUIO0()
- },
+ WME_WINENTRY("helga", "Demo",
+ WME_ENTRY2s("english.dcp", "b3a93e678f0ef97200f691cd1724643f", 135864,
+ "data.dcp", "45134ed93bc391edf148b79cdcbf2a09", 154266028), Common::EN_ANY, ADGF_UNSTABLE | ADGF_DEMO, LATEST_VERSION),
// James Peris: No License Nor Control (English)
- {
- "jamesperis",
- "",
- AD_ENTRY1s("data.dcp", "a420961e170cb7d168a0d2bae2fe5218", 225294032),
- Common::EN_ANY,
- Common::kPlatformWindows,
- ADGF_UNSTABLE,
- GUIO0()
- },
+ WME_WINENTRY("jamesperis", "",
+ WME_ENTRY1s("data.dcp", "a420961e170cb7d168a0d2bae2fe5218", 225294032), Common::EN_ANY, ADGF_UNSTABLE, LATEST_VERSION),
// James Peris: No License Nor Control (Spanish)
- {
- "jamesperis",
- "",
- AD_ENTRY1s("data.dcp", "a420961e170cb7d168a0d2bae2fe5218", 225294032),
- Common::ES_ESP,
- Common::kPlatformWindows,
- ADGF_UNSTABLE,
- GUIO0()
- },
+ WME_WINENTRY("jamesperis", "",
+ WME_ENTRY1s("data.dcp", "a420961e170cb7d168a0d2bae2fe5218", 225294032), Common::ES_ESP, ADGF_UNSTABLE, LATEST_VERSION),
// James Peris: No License Nor Control (Demo) (English)
- {
- "jamesperis",
- "Demo",
- AD_ENTRY1s("data.dcp", "edb9f9c7a08993c1e28f4e477b5f9830", 116113507),
- Common::EN_ANY,
- Common::kPlatformWindows,
- ADGF_UNSTABLE |
- ADGF_DEMO,
- GUIO0()
- },
+ WME_WINENTRY("jamesperis", "Demo",
+ WME_ENTRY1s("data.dcp", "edb9f9c7a08993c1e28f4e477b5f9830", 116113507), Common::EN_ANY, ADGF_UNSTABLE | ADGF_DEMO, LATEST_VERSION),
// James Peris: No License Nor Control (Demo) (Spanish)
- {
- "jamesperis",
- "Demo",
- AD_ENTRY1s("data.dcp", "edb9f9c7a08993c1e28f4e477b5f9830", 116113507),
- Common::ES_ESP,
- Common::kPlatformWindows,
- ADGF_UNSTABLE |
- ADGF_DEMO,
- GUIO0()
- },
+ WME_WINENTRY("jamesperis", "Demo",
+ WME_ENTRY1s("data.dcp", "edb9f9c7a08993c1e28f4e477b5f9830", 116113507), Common::ES_ESP, ADGF_UNSTABLE | ADGF_DEMO, LATEST_VERSION),
// J.U.L.I.A. (English)
- {
- "julia",
- "",
- AD_ENTRY1s("data.dcp", "c2264b4f8fcd132d2913ff5b6076a24f", 10109741),
- Common::EN_ANY,
- Common::kPlatformWindows,
- ADGF_UNSTABLE,
- GUIO0()
- },
+ WME_WINENTRY("julia", "",
+ WME_ENTRY1s("data.dcp", "c2264b4f8fcd132d2913ff5b6076a24f", 10109741), Common::EN_ANY, ADGF_UNSTABLE, LATEST_VERSION),
// J.U.L.I.A. (English, Bundle in a box-version)
- {
- "julia",
- "Version 1.2",
- AD_ENTRY1s("data.dcp", "fe90023ccc22f35185b40b910e0d03a2", 10101373),
- Common::EN_ANY,
- Common::kPlatformWindows,
- ADGF_UNSTABLE,
- GUIO0()
- },
+ WME_WINENTRY("julia", "Version 1.2",
+ WME_ENTRY1s("data.dcp", "fe90023ccc22f35185b40b910e0d03a2", 10101373), Common::EN_ANY, ADGF_UNSTABLE, LATEST_VERSION),
// J.U.L.I.A. (English) (Demo)
- {
- "julia",
- "Demo",
- AD_ENTRY1s("data.dcp", "f0bbc3394555a9811f6050dae428cab6", 7655237),
- Common::EN_ANY,
- Common::kPlatformWindows,
- ADGF_UNSTABLE |
- ADGF_DEMO,
- GUIO0()
- },
+ WME_WINENTRY("julia", "Demo",
+ WME_ENTRY1s("data.dcp", "f0bbc3394555a9811f6050dae428cab6", 7655237), Common::EN_ANY, ADGF_UNSTABLE | ADGF_DEMO, LATEST_VERSION),
// J.U.L.I.A. (English) (Greenlight Demo)
- {
- "julia",
- "Greenlight Demo",
- AD_ENTRY1s("data.dcp", "4befd448d36b0dae9c3ab1aa7cb8b78d", 7271886),
- Common::EN_ANY,
- Common::kPlatformWindows,
- ADGF_UNSTABLE |
- ADGF_DEMO,
- GUIO0()
- },
+ WME_WINENTRY("julia", "Greenlight Demo",
+ WME_ENTRY1s("data.dcp", "4befd448d36b0dae9c3ab1aa7cb8b78d", 7271886), Common::EN_ANY, ADGF_UNSTABLE | ADGF_DEMO, LATEST_VERSION),
// Kulivocko (Czech)
- {
- "kulivocko",
- "",
- AD_ENTRY1s("data.dcp", "44306dc470e9b27474043932eccee02f", 155106392),
- Common::CZ_CZE,
- Common::kPlatformWindows,
- ADGF_UNSTABLE,
- GUIO0()
- },
+ WME_WINENTRY("kulivocko", "",
+ WME_ENTRY1s("data.dcp", "44306dc470e9b27474043932eccee02f", 155106392), Common::CZ_CZE, ADGF_UNSTABLE, LATEST_VERSION),
// Kulivocko (Czech) (Demo)
- {
- "kulivocko",
- "Demo",
- AD_ENTRY1s("data.dcp", "63b164bdfadecbb0deb5da691afb8154", 48362234),
- Common::CZ_CZE,
- Common::kPlatformWindows,
- ADGF_UNSTABLE |
- ADGF_DEMO,
- GUIO0()
- },
+ WME_WINENTRY("kulivocko", "Demo",
+ WME_ENTRY1s("data.dcp", "63b164bdfadecbb0deb5da691afb8154", 48362234), Common::CZ_CZE, ADGF_UNSTABLE | ADGF_DEMO, LATEST_VERSION),
// Life In 3 Minutes
- {
- "lifein3minutes",
- "",
- AD_ENTRY1s("data.dcp", "c6368950e37a95bf098b02b4eaa5b929", 141787214),
- Common::EN_ANY,
- Common::kPlatformWindows,
- ADGF_UNSTABLE,
- GUIO0()
- },
+ WME_WINENTRY("lifein3minutes", "",
+ WME_ENTRY1s("data.dcp", "c6368950e37a95bf098b02b4eaa5b929", 141787214), Common::EN_ANY, ADGF_UNSTABLE, LATEST_VERSION),
// Looky Demo (English)
- {
- "looky",
- "Demo",
- {
- {"english.dcp", 0, "1388e1dd320f4d553dea3b0316812f9d", 1358442},
- {"data.dcp", 0, "7074bcd7bc7ad7eb04c271aafb964c32", 13815660},
- AD_LISTEND
- },
- Common::EN_ANY,
- Common::kPlatformWindows,
- ADGF_UNSTABLE |
- ADGF_DEMO,
- GUIO0()
- },
+ WME_WINENTRY("looky", "Demo",
+ WME_ENTRY2s("english.dcp", "1388e1dd320f4d553dea3b0316812f9d", 1358442,
+ "data.dcp", "7074bcd7bc7ad7eb04c271aafb964c32", 13815660), Common::EN_ANY, ADGF_UNSTABLE | ADGF_DEMO, LATEST_VERSION),
// Looky Demo (German)
- {
- "looky",
- "Demo",
- {
- {"german.dcp", 0, "606c048426dfbe94442b59fd34a5c76e", 14339496},
- {"data.dcp", 0, "7074bcd7bc7ad7eb04c271aafb964c32", 13815660},
- AD_LISTEND
- },
- Common::DE_DEU,
- Common::kPlatformWindows,
- ADGF_UNSTABLE |
- ADGF_DEMO,
- GUIO0()
- },
+ WME_WINENTRY("looky", "Demo",
+ WME_ENTRY2s("german.dcp", "606c048426dfbe94442b59fd34a5c76e", 14339496,
+ "data.dcp", "7074bcd7bc7ad7eb04c271aafb964c32", 13815660), Common::DE_DEU, ADGF_UNSTABLE | ADGF_DEMO, LATEST_VERSION),
// Looky (German)
- {
- "looky",
- "",
- {
- {"german.dcp", 0, "bf4c2b8c26342342441a6d64934ab832", 107027865},
- {"data.dcp", 0, "50de0beaa5ad621aa9f020df901d1e74", 1342214},
- AD_LISTEND
- },
- Common::DE_DEU,
- Common::kPlatformWindows,
- ADGF_UNSTABLE,
- GUIO0()
- },
+ WME_WINENTRY("looky", "",
+ WME_ENTRY2s("german.dcp", "bf4c2b8c26342342441a6d64934ab832", 107027865,
+ "data.dcp", "50de0beaa5ad621aa9f020df901d1e74", 1342214), Common::DE_DEU, ADGF_UNSTABLE, LATEST_VERSION),
// Mirage
- {
- "mirage",
- "",
- AD_ENTRY1s("data.dcp", "d230b0b99c0aa77b9ecd094d8ee5573b", 17844056),
- Common::EN_ANY,
- Common::kPlatformWindows,
- ADGF_UNSTABLE,
- GUIO0()
- },
+ WME_WINENTRY("mirage", "",
+ WME_ENTRY1s("data.dcp", "d230b0b99c0aa77b9ecd094d8ee5573b", 17844056), Common::EN_ANY, ADGF_UNSTABLE, LATEST_VERSION),
// Oknytt
- {
- "oknytt",
- "Version 1.0",
- AD_ENTRY1s("data.dcp", "6456cf8f429905c83f07509f9da536dd", 109502959),
- Common::EN_ANY,
- Common::kPlatformWindows,
- ADGF_UNSTABLE,
- GUIO0()
- },
+ WME_WINENTRY("oknytt", "Version 1.0",
+ WME_ENTRY1s("data.dcp", "6456cf8f429905c83f07509f9da536dd", 109502959), Common::EN_ANY, ADGF_UNSTABLE, LATEST_VERSION),
// Night Train Demo
- {
- "nighttrain",
- "",
- AD_ENTRY1s("data.dcp", "5a027ef84b083a730c9a4c85ec1d3a32", 131760816),
- Common::EN_ANY,
- Common::kPlatformWindows,
- ADGF_UNSTABLE |
- ADGF_DEMO,
- GUIO0()
- },
+ WME_WINENTRY("nighttrain", "",
+ WME_ENTRY1s("data.dcp", "5a027ef84b083a730c9a4c85ec1d3a32", 131760816), Common::EN_ANY, ADGF_UNSTABLE | ADGF_DEMO, LATEST_VERSION),
// Paintaria
- {
- "paintaria",
- "",
- AD_ENTRY1s("data.dcp", "354c08440c98150ff0d4008dd2865880", 48326040),
- Common::EN_ANY,
- Common::kPlatformWindows,
- ADGF_UNSTABLE,
- GUIO0()
- },
+ WME_WINENTRY("paintaria", "",
+ WME_ENTRY1s("data.dcp", "354c08440c98150ff0d4008dd2865880", 48326040), Common::EN_ANY, ADGF_UNSTABLE, LATEST_VERSION),
// Pigeons in the Park
- {
- "pigeons",
- "",
- AD_ENTRY1s("data.dcp", "9143a5b6ff8206aefe3c4c643add3ec7", 2611100),
- Common::EN_ANY,
- Common::kPlatformWindows,
- ADGF_UNSTABLE,
- GUIO0()
- },
+ WME_WINENTRY("pigeons", "",
+ WME_ENTRY1s("data.dcp", "9143a5b6ff8206aefe3c4c643add3ec7", 2611100), Common::EN_ANY, ADGF_UNSTABLE, LATEST_VERSION),
// Project: Doom
- {
- "projectdoom",
- "",
- AD_ENTRY1s("data.dcp", "d5894b65a40706845434b99870bcab92", 99223761),
- Common::EN_ANY,
- Common::kPlatformWindows,
- ADGF_UNSTABLE,
- GUIO0()
- },
+ WME_WINENTRY("projectdoom", "",
+ WME_ENTRY1s("data.dcp", "d5894b65a40706845434b99870bcab92", 99223761), Common::EN_ANY, ADGF_UNSTABLE, LATEST_VERSION),
// Project Joe
- {
- "projectjoe",
- "",
- AD_ENTRY1s("data.dcp", "ada3c08542901295076b5349e655e73f", 160780037),
- Common::EN_ANY,
- Common::kPlatformWindows,
- ADGF_UNSTABLE |
- ADGF_DEMO,
- GUIO0()
- },
+ WME_WINENTRY("projectjoe", "",
+ WME_ENTRY1s("data.dcp", "ada3c08542901295076b5349e655e73f", 160780037), Common::EN_ANY, ADGF_UNSTABLE | ADGF_DEMO, LATEST_VERSION),
// Project Lonely Robot
- {
- "lonelyrobot",
- "beta",
- AD_ENTRY1s("data.dcp", "a0cf7ad5bab957416dcda454e9f28ef0", 3420120),
- Common::EN_ANY,
- Common::kPlatformWindows,
- ADGF_UNSTABLE |
- ADGF_DEMO,
- GUIO0()
- },
+ WME_WINENTRY("lonelyrobot", "beta",
+ WME_ENTRY1s("data.dcp", "a0cf7ad5bab957416dcda454e9f28ef0", 3420120), Common::EN_ANY, ADGF_UNSTABLE | ADGF_DEMO, LATEST_VERSION),
// Reversion: The Escape Version 1.0
- {
- "reversion1",
- "Version 1.0",
- AD_ENTRY1s("data.dcp", "cd616f98ebfd047e0c540b50b4b70761", 254384531),
- Common::EN_ANY,
- Common::kPlatformWindows,
- ADGF_UNSTABLE,
- GUIO0()
- },
+ WME_WINENTRY("reversion1", "Version 1.0",
+ WME_ENTRY1s("data.dcp", "cd616f98ebfd047e0c540b50b4b70761", 254384531), Common::EN_ANY, ADGF_UNSTABLE, LATEST_VERSION),
// Reversion: The Escape Version 1.1 (Chinese)
- {
- "reversion1",
- "Version 1.1",
- {
- {"chinese.dcp", 0, "cf97150739499a4c15f51dc534ff85a1", 6330561},
- {"data.dcp", 0, "cb9865dc7e1db2990a8cf4bc13cf4999", 257643032},
- AD_LISTEND
- },
- Common::ZH_CNA,
- Common::kPlatformWindows,
- ADGF_UNSTABLE,
- GUIO0()
- },
+ WME_WINENTRY("reversion1", "Version 1.1",
+ WME_ENTRY2s("chinese.dcp", "cf97150739499a4c15f51dc534ff85a1", 6330561,
+ "data.dcp", "cb9865dc7e1db2990a8cf4bc13cf4999", 257643032), Common::ZH_CNA, ADGF_UNSTABLE, LATEST_VERSION),
// Reversion: The Escape Version 1.1 (English)
- {
- "reversion1",
- "Version 1.1",
- {
- {"english.dcp", 0, "7b2f061d7c91365c5d04605f1de032b3", 5702699},
- {"data.dcp", 0, "cb9865dc7e1db2990a8cf4bc13cf4999", 257643032},
- AD_LISTEND
- },
- Common::EN_ANY,
- Common::kPlatformWindows,
- ADGF_UNSTABLE,
- GUIO0()
- },
+ WME_WINENTRY("reversion1", "Version 1.1",
+ WME_ENTRY2s("english.dcp", "7b2f061d7c91365c5d04605f1de032b3", 5702699,
+ "data.dcp", "cb9865dc7e1db2990a8cf4bc13cf4999", 257643032), Common::EN_ANY, ADGF_UNSTABLE, LATEST_VERSION),
// Reversion: The Escape Version 1.1 (French)
- {
- "reversion1",
- "Version 1.1",
- {
- {"french.dcp", 0, "214204b6022c5ed67fada44557690faf", 6327400},
- {"data.dcp", 0, "cb9865dc7e1db2990a8cf4bc13cf4999", 257643032},
- AD_LISTEND
- },
- Common::FR_FRA,
- Common::kPlatformWindows,
- ADGF_UNSTABLE,
- GUIO0()
- },
+ WME_WINENTRY("reversion1", "Version 1.1",
+ WME_ENTRY2s("french.dcp", "214204b6022c5ed67fada44557690faf", 6327400,
+ "data.dcp", "cb9865dc7e1db2990a8cf4bc13cf4999", 257643032), Common::FR_FRA, ADGF_UNSTABLE, LATEST_VERSION),
// Reversion: The Escape Version 1.1 (German)
- {
- "reversion1",
- "Version 1.1",
- {
- {"german.dcp", 0, "96677823b36d580a4a29e3659071071c", 6340699},
- {"data.dcp", 0, "cb9865dc7e1db2990a8cf4bc13cf4999", 257643032},
- AD_LISTEND
- },
- Common::DE_DEU,
- Common::kPlatformWindows,
- ADGF_UNSTABLE,
- GUIO0()
- },
+ WME_WINENTRY("reversion1", "Version 1.1",
+ WME_ENTRY2s("german.dcp", "96677823b36d580a4a29e3659071071c", 6340699,
+ "data.dcp", "cb9865dc7e1db2990a8cf4bc13cf4999", 257643032), Common::DE_DEU, ADGF_UNSTABLE, LATEST_VERSION),
// Reversion: The Escape Version 1.1 (Italian)
- {
- "reversion1",
- "Version 1.1",
- {
- {"italian.dcp", 0, "9ce80c1835108f10170a02969f71efe1", 6301836},
- {"data.dcp", 0, "cb9865dc7e1db2990a8cf4bc13cf4999", 257643032},
- AD_LISTEND
- },
- Common::IT_ITA,
- Common::kPlatformWindows,
- ADGF_UNSTABLE,
- GUIO0()
- },
+ WME_WINENTRY("reversion1", "Version 1.1",
+ WME_ENTRY2s("italian.dcp", "9ce80c1835108f10170a02969f71efe1", 6301836,
+ "data.dcp", "cb9865dc7e1db2990a8cf4bc13cf4999", 257643032), Common::IT_ITA, ADGF_UNSTABLE, LATEST_VERSION),
// Reversion: The Escape Version 1.1 (Portuguese)
- {
- "reversion1",
- "Version 1.1",
- {
- {"portugues.dcp", 0, "8772501afa2c630a7c697eb99e9c7bda", 5053303},
- {"data.dcp", 0, "cb9865dc7e1db2990a8cf4bc13cf4999", 257643032},
- AD_LISTEND
- },
- Common::PT_BRA,
- Common::kPlatformWindows,
- ADGF_UNSTABLE,
- GUIO0()
- },
+ WME_WINENTRY("reversion1", "Version 1.1",
+ WME_ENTRY2s("portugues.dcp", "8772501afa2c630a7c697eb99e9c7bda", 5053303,
+ "data.dcp", "cb9865dc7e1db2990a8cf4bc13cf4999", 257643032), Common::PT_BRA, ADGF_UNSTABLE, LATEST_VERSION),
// Reversion: The Escape Version 1.3 (Chinese)
- {
- "reversion1",
- "Version 1.3",
- {
- {"xlanguage_nz.dcp", 0, "92c4065156e464211685bf799b3279fd", 5130600},
- {"data.dcp", 0, "9ebb12f6fd7c038d079f81beb3bd96d5", 254185907},
- AD_LISTEND
- },
- Common::ZH_CNA,
- Common::kPlatformWindows,
- ADGF_UNSTABLE,
- GUIO0()
- },
+ WME_WINENTRY("reversion1", "Version 1.3",
+ WME_ENTRY2s("xlanguage_nz.dcp", "92c4065156e464211685bf799b3279fd", 5130600,
+ "data.dcp", "9ebb12f6fd7c038d079f81beb3bd96d5", 254185907), Common::ZH_CNA, ADGF_UNSTABLE, LATEST_VERSION),
// Reversion: The Escape Version 1.3 (English)
- {
- "reversion1",
- "Version 1.3",
- {
- {"xlanguage_en.dcp", 0, "05845e1283920a6e4044f2a54f7a9519", 4818543},
- {"data.dcp", 0, "9ebb12f6fd7c038d079f81beb3bd96d5", 254185907},
- AD_LISTEND
- },
- Common::EN_ANY,
- Common::kPlatformWindows,
- ADGF_UNSTABLE,
- GUIO0()
- },
+ WME_WINENTRY("reversion1", "Version 1.3",
+ WME_ENTRY2s("xlanguage_en.dcp", "05845e1283920a6e4044f2a54f7a9519", 4818543,
+ "data.dcp", "9ebb12f6fd7c038d079f81beb3bd96d5", 254185907), Common::EN_ANY, ADGF_UNSTABLE, LATEST_VERSION),
// Reversion: The Escape Version 1.3 (French)
- {
- "reversion1",
- "Version 1.3",
- {
- {"xlanguage_fr.dcp", 0, "441795490e9307eb2ed07830779881ac", 5425959},
- {"data.dcp", 0, "9ebb12f6fd7c038d079f81beb3bd96d5", 254185907},
- AD_LISTEND
- },
- Common::FR_FRA,
- Common::kPlatformWindows,
- ADGF_UNSTABLE,
- GUIO0()
- },
+ WME_WINENTRY("reversion1", "Version 1.3",
+ WME_ENTRY2s("xlanguage_fr.dcp", "441795490e9307eb2ed07830779881ac", 5425959,
+ "data.dcp", "9ebb12f6fd7c038d079f81beb3bd96d5", 254185907), Common::FR_FRA, ADGF_UNSTABLE, LATEST_VERSION),
// Reversion: The Escape Version 1.3 (German)
- {
- "reversion1",
- "Version 1.3",
- {
- {"xlanguage_de.dcp", 0, "b588041015b93e54b4c246ca77d01e76", 5423798},
- {"data.dcp", 0, "9ebb12f6fd7c038d079f81beb3bd96d5", 254185907},
- AD_LISTEND
- },
- Common::DE_DEU,
- Common::kPlatformWindows,
- ADGF_UNSTABLE,
- GUIO0()
- },
+ WME_WINENTRY("reversion1", "Version 1.3",
+ WME_ENTRY2s("xlanguage_de.dcp", "b588041015b93e54b4c246ca77d01e76", 5423798,
+ "data.dcp", "9ebb12f6fd7c038d079f81beb3bd96d5", 254185907), Common::DE_DEU, ADGF_UNSTABLE, LATEST_VERSION),
// Reversion: The Escape Version 1.3 (Italian)
- {
- "reversion1",
- "Version 1.3",
- {
- {"xlanguage_it.dcp", 0, "a1f4199079b75ee10cded41f05b45d5f", 5386424},
- {"data.dcp", 0, "9ebb12f6fd7c038d079f81beb3bd96d5", 254185907},
- AD_LISTEND
- },
- Common::IT_ITA,
- Common::kPlatformWindows,
- ADGF_UNSTABLE,
- GUIO0()
- },
+ WME_WINENTRY("reversion1", "Version 1.3",
+ WME_ENTRY2s("xlanguage_it.dcp", "a1f4199079b75ee10cded41f05b45d5f", 5386424,
+ "data.dcp", "9ebb12f6fd7c038d079f81beb3bd96d5", 254185907), Common::IT_ITA, ADGF_UNSTABLE, LATEST_VERSION),
// Reversion: The Escape Version 1.3 (Portuguese)
- {
- "reversion1",
- "Version 1.3",
- {
- {"xlanguage_pt.dcp", 0, "3d653debd37e56756a79401e1004c4d2", 4149165},
- {"data.dcp", 0, "9ebb12f6fd7c038d079f81beb3bd96d5", 254185907},
- AD_LISTEND
- },
- Common::PT_BRA,
- Common::kPlatformWindows,
- ADGF_UNSTABLE,
- GUIO0()
- },
+ WME_WINENTRY("reversion1", "Version 1.3",
+ WME_ENTRY2s("xlanguage_pt.dcp", "3d653debd37e56756a79401e1004c4d2", 4149165,
+ "data.dcp", "9ebb12f6fd7c038d079f81beb3bd96d5", 254185907), Common::PT_BRA, ADGF_UNSTABLE, LATEST_VERSION),
// Reversion: The Escape Version 1.3.2369 (Chinese)
- {
- "reversion1",
- "Version 1.3.2369",
- {
- {"xlanguage_nz.dcp", 0, "7146dfa43ffdf0886e034fffe2c8a0c0", 13722261},
- {"data.dcp", 0, "aecb5deeea7b0baa871fbd0cef35a648", 254219204},
- AD_LISTEND
- },
- Common::ZH_CNA,
- Common::kPlatformWindows,
- ADGF_UNSTABLE,
- GUIO0()
- },
+ WME_WINENTRY("reversion1", "Version 1.3.2369",
+ WME_ENTRY2s("xlanguage_nz.dcp", "7146dfa43ffdf0886e034fffe2c8a0c0", 13722261,
+ "data.dcp", "aecb5deeea7b0baa871fbd0cef35a648", 254219204), Common::ZH_CNA, ADGF_UNSTABLE, LATEST_VERSION),
// Reversion: The Escape Version 1.3.2369 (English)
- {
- "reversion1",
- "Version 1.3.2369",
- {
- {"xlanguage_en.dcp", 0, "64b6fa7eedc09c231f6ce046e77fee05", 11339619},
- {"data.dcp", 0, "aecb5deeea7b0baa871fbd0cef35a648", 254219204},
- AD_LISTEND
- },
- Common::EN_ANY,
- Common::kPlatformWindows,
- ADGF_UNSTABLE,
- GUIO0()
- },
+ WME_WINENTRY("reversion1", "Version 1.3.2369",
+ WME_ENTRY2s("xlanguage_en.dcp", "64b6fa7eedc09c231f6ce046e77fee05", 11339619,
+ "data.dcp", "aecb5deeea7b0baa871fbd0cef35a648", 254219204), Common::EN_ANY, ADGF_UNSTABLE, LATEST_VERSION),
// Reversion: The Escape Version 1.3.2369 (French)
- {
- "reversion1",
- "Version 1.3.2369",
- {
- {"xlanguage_fr.dcp", 0, "d561d562224afea809153a1fd9fdb0c0", 11963210},
- {"data.dcp", 0, "aecb5deeea7b0baa871fbd0cef35a648", 254219204},
- AD_LISTEND
- },
- Common::FR_FRA,
- Common::kPlatformWindows,
- ADGF_UNSTABLE,
- GUIO0()
- },
+ WME_WINENTRY("reversion1", "Version 1.3.2369",
+ WME_ENTRY2s("xlanguage_fr.dcp", "d561d562224afea809153a1fd9fdb0c0", 11963210,
+ "data.dcp", "aecb5deeea7b0baa871fbd0cef35a648", 254219204), Common::FR_FRA, ADGF_UNSTABLE, LATEST_VERSION),
// Reversion: The Escape Version 1.3.2369 (German)
- {
- "reversion1",
- "Version 1.3.2369",
- {
- {"xlanguage_de.dcp", 0, "4e3f614c36bd6bae74b8cc83e663a8f0", 14040310},
- {"data.dcp", 0, "aecb5deeea7b0baa871fbd0cef35a648", 254219204},
- AD_LISTEND
- },
- Common::DE_DEU,
- Common::kPlatformWindows,
- ADGF_UNSTABLE,
- GUIO0()
- },
+ WME_WINENTRY("reversion1", "Version 1.3.2369",
+ WME_ENTRY2s("xlanguage_de.dcp", "4e3f614c36bd6bae74b8cc83e663a8f0", 14040310,
+ "data.dcp", "aecb5deeea7b0baa871fbd0cef35a648", 254219204), Common::DE_DEU, ADGF_UNSTABLE, LATEST_VERSION),
// Reversion: The Escape Version 1.3.2369 (Italian)
- {
- "reversion1",
- "Version 1.3.2369",
- {
- {"xlanguage_it.dcp", 0, "10d09b7fe61946f09dd91d5e8d090f94", 11913752},
- {"data.dcp", 0, "aecb5deeea7b0baa871fbd0cef35a648", 254219204},
- AD_LISTEND
- },
- Common::IT_ITA,
- Common::kPlatformWindows,
- ADGF_UNSTABLE,
- GUIO0()
- },
+ WME_WINENTRY("reversion1", "Version 1.3.2369",
+ WME_ENTRY2s("xlanguage_it.dcp", "10d09b7fe61946f09dd91d5e8d090f94", 11913752,
+ "data.dcp", "aecb5deeea7b0baa871fbd0cef35a648", 254219204), Common::IT_ITA, ADGF_UNSTABLE, LATEST_VERSION),
// Reversion: The Escape Version 1.3.2369 (Latvian)
- {
- "reversion1",
- "Version 1.3.2369",
- {
- {"xlanguage_lv.dcp", 0, "704359ab5040b0dab6545064d7aa6eb9", 11414925},
- {"data.dcp", 0, "aecb5deeea7b0baa871fbd0cef35a648", 254219204},
- AD_LISTEND
- },
- Common::LV_LAT,
- Common::kPlatformWindows,
- ADGF_UNSTABLE,
- GUIO0()
- },
+ WME_WINENTRY("reversion1", "Version 1.3.2369",
+ WME_ENTRY2s("xlanguage_lv.dcp", "704359ab5040b0dab6545064d7aa6eb9", 11414925,
+ "data.dcp", "aecb5deeea7b0baa871fbd0cef35a648", 254219204), Common::LV_LAT, ADGF_UNSTABLE, LATEST_VERSION),
// Reversion: The Escape Version 1.3.2369 (Polish)
- {
- "reversion1",
- "Version 1.3.2369",
- {
- {"xlanguage_pl.dcp", 0, "c4ad33f57e1e998169552d521c1d6638", 11532215},
- {"data.dcp", 0, "aecb5deeea7b0baa871fbd0cef35a648", 254219204},
- AD_LISTEND
- },
- Common::PL_POL,
- Common::kPlatformWindows,
- ADGF_UNSTABLE,
- GUIO0()
- },
+ WME_WINENTRY("reversion1", "Version 1.3.2369",
+ WME_ENTRY2s("xlanguage_pl.dcp", "c4ad33f57e1e998169552d521c1d6638", 11532215,
+ "data.dcp", "aecb5deeea7b0baa871fbd0cef35a648", 254219204), Common::PL_POL, ADGF_UNSTABLE, LATEST_VERSION),
// Reversion: The Escape Version 1.3.2369 (Portuguese)
- {
- "reversion1",
- "Version 1.3.2369",
- {
- {"xlanguage_pt.dcp", 0, "886886b6b14aadac844078de856799a6", 10620797},
- {"data.dcp", 0, "aecb5deeea7b0baa871fbd0cef35a648", 254219204},
- AD_LISTEND
- },
- Common::PT_BRA,
- Common::kPlatformWindows,
- ADGF_UNSTABLE,
- GUIO0()
- },
+ WME_WINENTRY("reversion1", "Version 1.3.2369",
+ WME_ENTRY2s("xlanguage_pt.dcp", "886886b6b14aadac844078de856799a6", 10620797,
+ "data.dcp", "aecb5deeea7b0baa871fbd0cef35a648", 254219204), Common::PT_BRA, ADGF_UNSTABLE, LATEST_VERSION),
// Reversion: The Meeting (Chinese)
- {
- "reversion2",
- "",
- {
- {"xlanguage_nz.dcp", 0, "8c3709474a87a7876109025dff41ff3f", 8746015},
- {"data.dcp", 0, "cb9865dc7e1db2990a8cf4bc13cf4999", 257643032},
- AD_LISTEND
- },
- Common::ZH_CNA,
- Common::kPlatformWindows,
- ADGF_UNSTABLE,
- GUIO0()
- },
+ WME_WINENTRY("reversion2", "",
+ WME_ENTRY2s("xlanguage_nz.dcp", "8c3709474a87a7876109025dff41ff3f", 8746015,
+ "data.dcp", "cb9865dc7e1db2990a8cf4bc13cf4999", 257643032), Common::ZH_CNA, ADGF_UNSTABLE, LATEST_VERSION),
// Reversion: The Meeting (English)
- {
- "reversion2",
- "",
- {
- {"xlanguage_en.dcp", 0, "ca357d86618d1ab76a21c913f4403cbd", 8414976},
- {"data.dcp", 0, "f7938cbfdc48f07934550245a3286921", 255672016},
- AD_LISTEND
- },
- Common::EN_ANY,
- Common::kPlatformWindows,
- ADGF_UNSTABLE,
- GUIO0()
- },
+ WME_WINENTRY("reversion2", "",
+ WME_ENTRY2s("xlanguage_en.dcp", "ca357d86618d1ab76a21c913f4403cbd", 8414976,
+ "data.dcp", "f7938cbfdc48f07934550245a3286921", 255672016), Common::EN_ANY, ADGF_UNSTABLE, LATEST_VERSION),
// Reversion: The Meeting (Spanish)
- {
- "reversion2",
- "",
- AD_ENTRY1s("data.dcp", "f7938cbfdc48f07934550245a3286921", 255672016),
- Common::ES_ESP,
- Common::kPlatformWindows,
- ADGF_UNSTABLE,
- GUIO0()
- },
+ WME_WINENTRY("reversion2", "",
+ WME_ENTRY1s("data.dcp", "f7938cbfdc48f07934550245a3286921", 255672016), Common::ES_ESP, ADGF_UNSTABLE, LATEST_VERSION),
// Reversion: The Meeting Version 2.0.2412 (Chinese)
- {
- "reversion2",
- "Version 2.0.2412",
- {
- {"data.dcp", 0, "f4ffc4df24b7bebad56a24930f33a2bc", 255766600},
- {"xlanguage_nz.dcp", 0, "17c79af4928e24484bee77a7e807cc2a", 10737127},
- {"Linux.dcp", 0, "21858bd77dc86b03f701fd47900e2f51", 984535},
- AD_LISTEND
- },
- Common::ZH_CNA,
- Common::kPlatformLinux,
- ADGF_UNSTABLE,
- GUIO0()
- },
+ WME_PLATENTRY("reversion2", "Version 2.0.2412",
+ WME_ENTRY3s("data.dcp", "f4ffc4df24b7bebad56a24930f33a2bc", 255766600,
+ "xlanguage_nz.dcp", "17c79af4928e24484bee77a7e807cc2a", 10737127,
+ "Linux.dcp", "21858bd77dc86b03f701fd47900e2f51", 984535), Common::ZH_CNA, Common::kPlatformLinux, ADGF_UNSTABLE, LATEST_VERSION),
// Reversion: The Meeting Version 2.0.2412 (English)
- {
- "reversion2",
- "Version 2.0.2412",
- {
- {"data.dcp", 0, "f4ffc4df24b7bebad56a24930f33a2bc", 255766600},
- {"xlanguage_en.dcp", 0, "0598bf752ce93b42bcaf1094df537c7b", 8533057},
- {"Linux.dcp", 0, "21858bd77dc86b03f701fd47900e2f51", 984535},
- AD_LISTEND
- },
- Common::EN_ANY,
- Common::kPlatformLinux,
- ADGF_UNSTABLE,
- GUIO0()
- },
+ WME_PLATENTRY("reversion2", "Version 2.0.2412",
+ WME_ENTRY3s("data.dcp", "f4ffc4df24b7bebad56a24930f33a2bc", 255766600,
+ "xlanguage_en.dcp", "0598bf752ce93b42bcaf1094df537c7b", 8533057,
+ "Linux.dcp", "21858bd77dc86b03f701fd47900e2f51", 984535), Common::EN_ANY, Common::kPlatformLinux, ADGF_UNSTABLE, LATEST_VERSION),
// Rhiannon: Curse of the four Branches
- {
- "rhiannon",
- "",
- AD_ENTRY1s("data.dcp", "870f348900b735f1cc79c0608ce32b0e", 1046169851),
- Common::EN_ANY,
- Common::kPlatformWindows,
- ADGF_UNSTABLE,
- GUIO0()
- },
+ WME_WINENTRY("rhiannon", "",
+ WME_ENTRY1s("data.dcp", "870f348900b735f1cc79c0608ce32b0e", 1046169851), Common::EN_ANY, ADGF_UNSTABLE, LATEST_VERSION),
// Rhiannon: Curse of the four Branches (English PC DVD)
- {
- "rhiannon",
- "DVD",
- AD_ENTRY1s("data.dcp", "6736bbc921bb6ce5161b3ad095a97bd4", 1053441028),
- Common::EN_ANY,
- Common::kPlatformWindows,
- ADGF_UNSTABLE,
- GUIO0()
- },
+ WME_WINENTRY("rhiannon", "DVD",
+ WME_ENTRY1s("data.dcp", "6736bbc921bb6ce5161b3ad095a97bd4", 1053441028), Common::EN_ANY, ADGF_UNSTABLE, LATEST_VERSION),
// 1 1/2 Ritter: Auf der Suche nach der hinreissenden Herzelinde
- {
- "ritter",
- "",
- AD_ENTRY1s("data.dcp", "5ac416cee605d3a30f4d59687b1cdab2", 364260278),
- Common::DE_DEU,
- Common::kPlatformWindows,
- ADGF_UNSTABLE,
- GUIO0()
- },
+ WME_WINENTRY("ritter", "",
+ WME_ENTRY1s("data.dcp", "5ac416cee605d3a30f4d59687b1cdab2", 364260278), Common::DE_DEU, ADGF_UNSTABLE, LATEST_VERSION),
// Satan and Son
- {
- "satanandson",
- "",
- AD_ENTRY1s("data.dcp", "16a6ba8174b697bbba9299619d1e20c4", 67539054),
- Common::EN_ANY,
- Common::kPlatformWindows,
- ADGF_UNSTABLE |
- ADGF_DEMO,
- GUIO0()
- },
+ WME_WINENTRY("satanandson", "",
+ WME_ENTRY1s("data.dcp", "16a6ba8174b697bbba9299619d1e20c4", 67539054), Common::EN_ANY, ADGF_UNSTABLE | ADGF_DEMO, LATEST_VERSION),
// Rosemary
- {
- "rosemary",
- "",
- AD_ENTRY1s("data.dcp", "4f2631138bd4d27587d9043f8aeff3df", 29483643),
- Common::EN_ANY,
- Common::kPlatformWindows,
- ADGF_UNSTABLE,
- GUIO0()
- },
+ WME_WINENTRY("rosemary", "",
+ WME_ENTRY1s("data.dcp", "4f2631138bd4d27587d9043f8aeff3df", 29483643), Common::EN_ANY, ADGF_UNSTABLE, LATEST_VERSION),
// Securanote
- {
- "securanote",
- "",
- AD_ENTRY1s("data.dcp", "5213d3e59b9e95b7fbd5c56f7de5341a", 2625554),
- Common::EN_ANY,
- Common::kPlatformIOS,
- ADGF_UNSTABLE,
- GUIO0()
- },
+ WME_PLATENTRY("securanote", "",
+ WME_ENTRY1s("data.dcp", "5213d3e59b9e95b7fbd5c56f7de5341a", 2625554), Common::EN_ANY, Common::kPlatformIOS, ADGF_UNSTABLE, LATEST_VERSION),
// Shaban
- {
- "shaban",
- "",
- AD_ENTRY1s("data.dcp", "35f702ca9baabc5c620e0be230195c8a", 755388466),
- Common::EN_ANY,
- Common::kPlatformWindows,
- ADGF_UNSTABLE,
- GUIO0()
- },
+ WME_WINENTRY("shaban", "",
+ WME_ENTRY1s("data.dcp", "35f702ca9baabc5c620e0be230195c8a", 755388466), Common::EN_ANY, ADGF_UNSTABLE, LATEST_VERSION),
// The Shine of a Star
- {
- "shinestar",
- "",
- AD_ENTRY1s("data.dcp", "f05abe9e2427a5e4f73648fa09c4ba8e", 94113060),
- Common::EN_ANY,
- Common::kPlatformWindows,
- ADGF_UNSTABLE,
- GUIO0()
- },
+ WME_WINENTRY("shinestar", "",
+ WME_ENTRY1s("data.dcp", "f05abe9e2427a5e4f73648fa09c4ba8e", 94113060), Common::EN_ANY, ADGF_UNSTABLE, LATEST_VERSION),
// Sofia's Debt
- {
- "sofiasdebt",
- "",
- AD_ENTRY1s("SD.exe", "e9515f9ba1a2925bb6733476a826a650", 9915047),
- Common::EN_ANY,
- Common::kPlatformWindows,
- ADGF_UNSTABLE,
- GUIO0()
- },
+ WME_WINENTRY("sofiasdebt", "",
+ WME_ENTRY1s("SD.exe", "e9515f9ba1a2925bb6733476a826a650", 9915047), Common::EN_ANY, ADGF_UNSTABLE, LATEST_VERSION),
// Space Invaders (Demo)
- {
- "spaceinvaders",
- "Demo",
- AD_ENTRY1s("data.dcp", "3f27adefdf72f2c1601cf555c80a509f", 1308361),
- Common::EN_ANY,
- Common::kPlatformWindows,
- ADGF_UNSTABLE |
- ADGF_DEMO,
- GUIO0()
- },
+ WME_WINENTRY("spaceinvaders", "Demo",
+ WME_ENTRY1s("data.dcp", "3f27adefdf72f2c1601cf555c80a509f", 1308361), Common::EN_ANY, ADGF_UNSTABLE | ADGF_DEMO, LATEST_VERSION),
// Space Madness
- {
- "spacemadness",
- "1.0.2",
- AD_ENTRY1s("data.dcp", "b9b83135dc7a9e1b4b5f50195dbeb630", 39546622),
- Common::EN_ANY,
- Common::kPlatformWindows,
- ADGF_UNSTABLE,
- GUIO0()
- },
+ WME_WINENTRY("spacemadness", "1.0.2",
+ WME_ENTRY1s("data.dcp", "b9b83135dc7a9e1b4b5f50195dbeb630", 39546622), Common::EN_ANY, ADGF_UNSTABLE, LATEST_VERSION),
// The Ancient Mark - Episode 1
- {
- "theancientmark1",
- "",
- AD_ENTRY1s("data.dcp", "ca04c26f03b2bd307368b306b297ddd7", 364664692),
- Common::EN_ANY,
- Common::kPlatformWindows,
- ADGF_UNSTABLE,
- GUIO0()
- },
+ WME_WINENTRY("theancientmark1", "",
+ WME_ENTRY1s("data.dcp", "ca04c26f03b2bd307368b306b297ddd7", 364664692), Common::EN_ANY, ADGF_UNSTABLE, LATEST_VERSION),
// The Box
- {
- "thebox",
- "",
- AD_ENTRY1s("data.dcp", "ec5f0c7e8174e307701447b53afe7e2f", 108372483),
- Common::EN_ANY,
- Common::kPlatformWindows,
- ADGF_UNSTABLE,
- GUIO0()
- },
+ WME_WINENTRY("thebox", "",
+ WME_ENTRY1s("data.dcp", "ec5f0c7e8174e307701447b53afe7e2f", 108372483), Common::EN_ANY, ADGF_UNSTABLE, LATEST_VERSION),
// The Kite (Version 1.1)
- {
- "thekite",
- "Version 1.1",
- AD_ENTRY1s("data.dcp", "92d29428f464469bda2d81b03d4d5c3e", 47332296),
- Common::EN_ANY,
- Common::kPlatformWindows,
- ADGF_UNSTABLE,
- GUIO0()
- },
+ WME_WINENTRY("thekite", "Version 1.1",
+ WME_ENTRY1s("data.dcp", "92d29428f464469bda2d81b03d4d5c3e", 47332296), Common::EN_ANY, ADGF_UNSTABLE, LATEST_VERSION),
// The Kite (Version 1.2.e)
- {
- "thekite",
- "Version 1.2.e",
- AD_ENTRY1s("data.dcp", "92451578b1bdd2b32a1db592a4f6d5fc", 47360539),
- Common::EN_ANY,
- Common::kPlatformWindows,
- ADGF_UNSTABLE,
- GUIO0()
- },
+ WME_WINENTRY("thekite", "Version 1.2.e",
+ WME_ENTRY1s("data.dcp", "92451578b1bdd2b32a1db592a4f6d5fc", 47360539), Common::EN_ANY, ADGF_UNSTABLE, LATEST_VERSION),
// The Kite (Version 1.2.i) (Italian)
- {
- "thekite",
- "Version 1.2.i",
- AD_ENTRY1s("data.dcp", "d3435b106a1b3b4c1df8ad596d271586", 47509274),
- Common::IT_ITA,
- Common::kPlatformWindows,
- ADGF_UNSTABLE,
- GUIO0()
- },
+ WME_WINENTRY("thekite", "Version 1.2.i",
+ WME_ENTRY1s("data.dcp", "d3435b106a1b3b4c1df8ad596d271586", 47509274), Common::IT_ITA, ADGF_UNSTABLE, LATEST_VERSION),
// The Kite (Version 1.2.r) (Russian)
- {
- "thekite",
- "Version 1.2.r",
- AD_ENTRY1s("data.dcp", "d531e097dd884737469da014ed882cde", 47554582 ),
- Common::RU_RUS,
- Common::kPlatformWindows,
- ADGF_UNSTABLE,
- GUIO0()
- },
+ WME_WINENTRY("thekite", "Version 1.2.r",
+ WME_ENTRY1s("data.dcp", "d531e097dd884737469da014ed882cde", 47554582 ), Common::RU_RUS, ADGF_UNSTABLE, LATEST_VERSION),
// The Kite (Version 1.3.e)
- {
- "thekite",
- "Version 1.3.e",
- AD_ENTRY1s("data.dcp", "9761827b51370263b7623721545d7627", 47382987),
- Common::EN_ANY,
- Common::kPlatformWindows,
- ADGF_UNSTABLE,
- GUIO0()
- },
+ WME_WINENTRY("thekite", "Version 1.3.e",
+ WME_ENTRY1s("data.dcp", "9761827b51370263b7623721545d7627", 47382987), Common::EN_ANY, ADGF_UNSTABLE, LATEST_VERSION),
// Fairy Tales About Toshechka and Boshechka
- {
- "tib",
- "",
- AD_ENTRY1s("data.dcp", "87d296ef3f46570ed18f000d3885db77", 340264526),
- Common::RU_RUS,
- Common::kPlatformWindows,
- ADGF_UNSTABLE,
- GUIO0()
- },
+ WME_WINENTRY("tib", "",
+ WME_ENTRY1s("data.dcp", "87d296ef3f46570ed18f000d3885db77", 340264526), Common::RU_RUS, ADGF_UNSTABLE, LATEST_VERSION),
// The Trader of Stories
- {
- "tradestory",
- "Demo",
- AD_ENTRY1s("data.dcp", "0a0b51191636cc8ead89b905281c3218", 40401902),
- Common::EN_ANY,
- Common::kPlatformWindows,
- ADGF_UNSTABLE |
- ADGF_DEMO,
- GUIO0()
- },
+ WME_WINENTRY("tradestory", "Demo",
+ WME_ENTRY1s("data.dcp", "0a0b51191636cc8ead89b905281c3218", 40401902), Common::EN_ANY, ADGF_UNSTABLE | ADGF_DEMO, LATEST_VERSION),
// the white chamber (multi-language)
- {
- "twc",
- "",
- AD_ENTRY1s("data.dcp", "0011d01142547c61e51ba24dc42b579e", 186451273),
- Common::UNK_LANG,
- Common::kPlatformWindows,
- ADGF_UNSTABLE,
- GUIO0()
- },
+ WME_WINENTRY("twc", "",
+ WME_ENTRY1s("data.dcp", "0011d01142547c61e51ba24dc42b579e", 186451273), Common::UNK_LANG, ADGF_UNSTABLE, LATEST_VERSION),
// Vsevolod Prologue (Demo)
- {
- "vsevolod",
- "Prologue",
- AD_ENTRY1s("data.dcp", "f2dcffd2692dbfcc9371fa1a87970fe7", 388669493),
- Common::EN_ANY,
- Common::kPlatformWindows,
- ADGF_UNSTABLE |
- ADGF_DEMO,
- GUIO0()
- },
+ WME_WINENTRY("vsevolod", "Prologue",
+ WME_ENTRY1s("data.dcp", "f2dcffd2692dbfcc9371fa1a87970fe7", 388669493), Common::EN_ANY, ADGF_UNSTABLE | ADGF_DEMO, LATEST_VERSION),
// War
- {
- "war",
- "",
- AD_ENTRY1s("data.dcp", "003e317cda6d0137bbd5e5d7f089ee4d", 32591890),
- Common::EN_ANY,
- Common::kPlatformWindows,
- ADGF_UNSTABLE,
- GUIO0()
- },
+ WME_WINENTRY("war", "",
+ WME_ENTRY1s("data.dcp", "003e317cda6d0137bbd5e5d7f089ee4d", 32591890), Common::EN_ANY, ADGF_UNSTABLE, LATEST_VERSION),
// Wilma Tetris
- {
- "wtetris",
- "",
- AD_ENTRY1s("data.dcp", "946e3a0496e6c12fb344c9ed861ff015", 2780093),
- Common::EN_ANY,
- Common::kPlatformWindows,
- ADGF_UNSTABLE,
- GUIO0()
- },
+ WME_WINENTRY("wtetris", "",
+ WME_ENTRY1s("data.dcp", "946e3a0496e6c12fb344c9ed861ff015", 2780093), Common::EN_ANY, ADGF_UNSTABLE, LATEST_VERSION),
// Zilm: A Game of Reflex 1.0
+ WME_WINENTRY("Zilm", "1.0",
+ WME_ENTRY1s("data.dcp", "098dffaf03d8adbb4cb5633e4733e63c", 351726), Common::EN_ANY, ADGF_UNSTABLE, LATEST_VERSION),
{
- "Zilm",
- "1.0",
- AD_ENTRY1s("data.dcp", "098dffaf03d8adbb4cb5633e4733e63c", 351726),
- Common::EN_ANY,
- Common::kPlatformWindows,
- ADGF_UNSTABLE,
- GUIO0()
- },
- AD_TABLE_END_MARKER
+ AD_TABLE_END_MARKER,
+ LATEST_VERSION
+ }
};
} // End of namespace Wintermute
+#undef WEM_ENTRY1s
+#undef WEM_ENTRY2s
+#undef WEM_ENTRY3s
+#undef WME_WINENTRY
+#undef WME_PLATENTRY
+
diff --git a/engines/wintermute/game_description.h b/engines/wintermute/game_description.h
new file mode 100644
index 0000000000..313fff8bbf
--- /dev/null
+++ b/engines/wintermute/game_description.h
@@ -0,0 +1,53 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef WINTERMUTE_GAME_DESCRIPTION_H
+#define WINTERMUTE_GAME_DESCRIPTION_H
+
+#include "engines/advancedDetector.h"
+
+namespace Wintermute {
+
+enum WMETargetExecutable {
+ OLDEST_VERSION,
+ WME_1_0_0,
+ WME_1_1_0,
+ WME_1_2_0,
+ WME_1_3_0,
+ WME_1_4_0,
+ WME_1_5_0,
+ WME_1_6_0,
+ WME_1_7_0,
+ WME_1_8_0,
+ WME_1_8_6,
+ WME_1_9_0,
+ LATEST_VERSION
+};
+
+struct WMEGameDescription {
+ ADGameDescription adDesc;
+ WMETargetExecutable targetExecutable;
+};
+
+}
+
+#endif /* WINTERMUTE_GAME_DESCRIPTION_H_ */
diff --git a/engines/wintermute/math/rect32.h b/engines/wintermute/math/rect32.h
index 93b5c68a30..00326d6747 100644
--- a/engines/wintermute/math/rect32.h
+++ b/engines/wintermute/math/rect32.h
@@ -50,7 +50,7 @@ struct Point32 {
y -= delta.y;
return *this;
}
-
+
operator FloatPoint() {
return FloatPoint(x,y);
}
diff --git a/engines/wintermute/module.mk b/engines/wintermute/module.mk
index 1b6c52e0b7..4c95314a02 100644
--- a/engines/wintermute/module.mk
+++ b/engines/wintermute/module.mk
@@ -108,7 +108,9 @@ MODULE_OBJS := \
utils/path_util.o \
utils/string_util.o \
utils/utils.o \
+ video/subtitle_card.o \
video/video_player.o \
+ video/video_subtitler.o \
video/video_theora_player.o \
debugger.o \
wintermute.o \
diff --git a/engines/wintermute/utils/utils.cpp b/engines/wintermute/utils/utils.cpp
index d592019418..dc6476d4ea 100644
--- a/engines/wintermute/utils/utils.cpp
+++ b/engines/wintermute/utils/utils.cpp
@@ -32,11 +32,6 @@
namespace Wintermute {
-//////////////////////////////////////////////////////////////////////
-static inline unsigned Sqr(int x) {
- return (x * x);
-}
-
//////////////////////////////////////////////////////////////////////////////////
// Swap - swaps two integers
//////////////////////////////////////////////////////////////////////////////////
diff --git a/engines/wintermute/video/subtitle_card.cpp b/engines/wintermute/video/subtitle_card.cpp
new file mode 100644
index 0000000000..5d882502fd
--- /dev/null
+++ b/engines/wintermute/video/subtitle_card.cpp
@@ -0,0 +1,56 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+/*
+ * This file is based on Wintermute Engine
+ * http://dead-code.org/redir.php?target=wme
+ * Copyright (c) 2011 Jan Nedoma
+ */
+
+#include "engines/wintermute/video/subtitle_card.h"
+#include "engines/wintermute/base/base_game.h"
+
+namespace Wintermute {
+
+SubtitleCard::SubtitleCard(BaseGame *inGame,
+ const Common::String &text,
+ const uint &startFrame,
+ const uint &endFrame) : _gameRef(inGame),
+ _startFrame(startFrame),
+ _endFrame(endFrame) {
+ _text = text;
+ _gameRef->expandStringByStringTable(_text);
+}
+
+uint32 SubtitleCard::getStartFrame() const {
+ return _startFrame;
+}
+
+uint32 SubtitleCard::getEndFrame() const {
+ return _endFrame;
+}
+
+Common::String SubtitleCard::getText() const {
+ return _text;
+}
+
+} // End of namespace Wintermute
diff --git a/engines/wintermute/video/subtitle_card.h b/engines/wintermute/video/subtitle_card.h
new file mode 100644
index 0000000000..629df77287
--- /dev/null
+++ b/engines/wintermute/video/subtitle_card.h
@@ -0,0 +1,53 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+/*
+ * This file is based on Wintermute Engine
+ * http://dead-code.org/redir.php?target=wme
+ * Copyright (c) 2011 Jan Nedoma
+ */
+
+#ifndef WINTERMUTE_SUBTITLECARD_H
+#define WINTERMUTE_SUBTITLECARD_H
+
+#include "common/str.h"
+
+namespace Wintermute {
+
+class BaseGame;
+
+class SubtitleCard {
+public:
+ SubtitleCard(BaseGame *inGame, const Common::String &text, const uint &startFrame, const uint &endFrame);
+ uint32 getEndFrame() const;
+ uint32 getStartFrame() const;
+ Common::String getText() const;
+private:
+ BaseGame *_gameRef;
+ uint32 _endFrame;
+ uint32 _startFrame;
+ Common::String _text;
+};
+
+} // End of namespace Wintermute
+
+#endif
diff --git a/engines/wintermute/video/video_subtitler.cpp b/engines/wintermute/video/video_subtitler.cpp
new file mode 100644
index 0000000000..95d938574b
--- /dev/null
+++ b/engines/wintermute/video/video_subtitler.cpp
@@ -0,0 +1,266 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+/*
+ * This file is based on Wintermute Engine
+ * http://dead-code.org/redir.php?target=wme
+ * Copyright (c) 2011 Jan Nedoma
+ */
+
+#include "engines/wintermute/video/video_subtitler.h"
+#include "engines/wintermute/base/base_file_manager.h"
+#include "engines/wintermute/utils/path_util.h"
+#include "engines/wintermute/base/font/base_font.h"
+#include "engines/wintermute/base/base_game.h"
+#include "engines/wintermute/base/gfx/base_renderer.h"
+
+namespace Wintermute {
+
+VideoSubtitler::VideoSubtitler(BaseGame *inGame): BaseClass(inGame) {
+ _lastSample = -1;
+ _currentSubtitle = 0;
+ _showSubtitle = false;
+}
+
+VideoSubtitler::~VideoSubtitler(void) {
+ _subtitles.clear();
+}
+
+bool VideoSubtitler::loadSubtitles(const Common::String &filename, const Common::String &subtitleFile) {
+ if (filename.size() == 0) {
+ return false;
+ }
+
+ _subtitles.clear();
+
+ _lastSample = -1;
+ _currentSubtitle = 0;
+ _showSubtitle = false;
+
+ Common::String newFile;
+
+ /*
+ * Okay, the expected behaviour is this: either we are
+ * provided with a subtitle file to use by the script when
+ * calling PlayTheora(), or we try to autodetect a suitable
+ * one which, for /some/path/movie/ogg is to be called
+ * /some/path/movie.sub
+ */
+ if (subtitleFile.size() != 0) {
+ newFile = subtitleFile;
+ } else {
+ Common::String path = PathUtil::getDirectoryName(filename);
+ Common::String name = PathUtil::getFileNameWithoutExtension(filename);
+ Common::String ext = ".SUB";
+ newFile = PathUtil::combine(path, name + ext);
+ }
+
+ Common::SeekableReadStream *file = BaseFileManager::getEngineInstance()->openFile(newFile, true, false);
+
+ if (file == nullptr) {
+ return false; // no subtitles
+ }
+
+ int fileSize = file->size();
+ char *buffer = new char[fileSize];
+
+ file->read(buffer, fileSize);
+
+ /* This is where we parse .sub files.
+ * Subtitles cards are in the form
+ * {StartFrame}{EndFrame} FirstLine | SecondLine \n
+ */
+ int pos = 0;
+
+ while (pos < fileSize) {
+ char *tokenStart = 0;
+ int tokenLength = 0;
+ int tokenPos = -1;
+ int lineLength = 0;
+ int start = -1;
+ int end = -1;
+ bool inToken = false;
+
+ while (pos + lineLength < fileSize &&
+ buffer[pos + lineLength] != '\n' &&
+ buffer[pos + lineLength] != '\0') {
+ // Measure the line until we hit EOL, EOS or just hit the boundary
+ lineLength++;
+ }
+
+ int realLength;
+
+ if (pos + lineLength >= fileSize) {
+ realLength = lineLength - 0;
+ } else {
+ // If we got here the above loop exited after hitting "\0" "\n"
+ realLength = lineLength - 1;
+ }
+
+ Common::String cardText;
+ char *fileLine = (char *)&buffer[pos];
+
+ for (int i = 0; i < realLength; i++) {
+ if (fileLine[i] == '{') {
+ if (!inToken) {
+ // We've hit the start of a Start/EndFrame token
+ inToken = true;
+ tokenStart = fileLine + i + 1;
+ tokenLength = 0;
+ tokenPos++;
+ } else {
+ // Actually, we were already inside an (invalid) one.
+ tokenLength++;
+ }
+ } else if (fileLine[i] == '}') {
+ if (inToken) {
+ // we were /inside/ a {.*} token, so this is the end of the block
+ inToken = false;
+ char *token = new char[tokenLength + 1];
+ strncpy(token, tokenStart, tokenLength);
+ token[tokenLength] = '\0';
+ if (tokenPos == 0) {
+ // Was this StartFrame...
+ start = atoi(token);
+ } else if (tokenPos == 1) {
+ // Or the EndFrame?
+ end = atoi(token);
+ }
+ delete[] token;
+ } else {
+ // This char is part of the plain text, just append it
+ cardText += fileLine[i];
+ }
+ } else {
+ if (inToken) {
+ tokenLength++;
+ } else {
+ if (fileLine[i] == '|') {
+ // The pipe character signals a linebreak in the text
+ cardText += '\n';
+ } else {
+ // This char is part of the plain text, just append it
+ cardText += fileLine[i];
+ }
+ }
+ }
+ }
+
+ if (start != -1 && cardText.size() > 0 && (start != 1 || end != 1)){
+ // Add a subtitlecard based on the line we have just parsed
+ _subtitles.push_back(SubtitleCard(_gameRef, cardText, start, end));
+ }
+
+ pos += lineLength + 1;
+ }
+
+ delete[] buffer;
+ // Succeeded loading subtitles!
+
+ return true;
+}
+
+void VideoSubtitler::display() {
+ if (_showSubtitle) {
+
+ BaseFont *font;
+
+ if (_gameRef->getVideoFont() == nullptr) {
+ font = _gameRef->getSystemFont();
+ } else {
+ font = _gameRef->getVideoFont();
+ }
+
+ int textHeight = font->getTextHeight(
+ (const byte *)_subtitles[_currentSubtitle].getText().c_str(),
+ _gameRef->_renderer->getWidth());
+
+ font->drawText(
+ (const byte *)_subtitles[_currentSubtitle].getText().c_str(),
+ 0,
+ (_gameRef->_renderer->getHeight() - textHeight - 5),
+ (_gameRef->_renderer->getWidth()),
+ TAL_CENTER);
+ }
+}
+
+void VideoSubtitler::update(uint32 frame) {
+ if (_subtitles.size() == 0) {
+ // Edge case: we have loaded subtitles early on... from a blank file.
+ return;
+ }
+
+ if ((int32)frame != _lastSample) {
+ /*
+ * If the frame count hasn't advanced the previous state still matches
+ * the current frame (obviously).
+ */
+
+ _lastSample = frame;
+ // Otherwise, we update _lastSample; see above.
+
+ _showSubtitle = false;
+
+ bool overdue = (frame > _subtitles[_currentSubtitle].getEndFrame());
+ bool hasNext = (_currentSubtitle + 1 < _subtitles.size());
+ bool nextStarted = false;
+ if (hasNext) {
+ nextStarted = (_subtitles[_currentSubtitle + 1].getStartFrame() <= frame);
+ }
+
+ while (_currentSubtitle < _subtitles.size() &&
+ overdue && hasNext && nextStarted) {
+ /*
+ * We advance until we get past all overdue subtitles.
+ * We should exit the cycle when we either reach the first
+ * subtitle which is not overdue whose subsequent subtitle
+ * has not started yet (aka the one we must display now or
+ * the one which WILL be displayed when its time comes)
+ * and / or when we reach the last one.
+ */
+
+ _currentSubtitle++;
+
+ overdue = (frame > _subtitles[_currentSubtitle].getEndFrame());
+ hasNext = (_currentSubtitle + 1 < _subtitles.size());
+ if (hasNext) {
+ nextStarted = (_subtitles[_currentSubtitle + 1].getStartFrame() <= frame);
+ } else {
+ nextStarted = false;
+ }
+ }
+
+ bool currentValid = (_subtitles[_currentSubtitle].getEndFrame() != 0);
+ /*
+ * No idea why we do this check, carried over from Mnemonic's code.
+ * Possibly a workaround for buggy subtitles or some kind of sentinel? :-\
+ */
+
+ bool currentStarted = frame >= _subtitles[_currentSubtitle].getStartFrame();
+
+ if (currentStarted && !overdue && currentValid) {
+ _showSubtitle = true;
+ }
+ }
+}
+
+} // End of namespace Wintermute
diff --git a/engines/wintermute/video/video_subtitler.h b/engines/wintermute/video/video_subtitler.h
new file mode 100644
index 0000000000..94f22909a1
--- /dev/null
+++ b/engines/wintermute/video/video_subtitler.h
@@ -0,0 +1,53 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+/*
+ * This file is based on Wintermute Engine
+ * http://dead-code.org/redir.php?target=wme
+ * Copyright (c) 2011 Jan Nedoma
+ */
+
+#ifndef WINTERMUTE_VIDSUBTITLER_H
+#define WINTERMUTE_VIDSUBTITLER_H
+
+#include "engines/wintermute/base/base.h"
+#include "engines/wintermute/video/subtitle_card.h"
+
+namespace Wintermute {
+
+class VideoSubtitler : public BaseClass {
+public:
+ VideoSubtitler(BaseGame *inGame);
+ virtual ~VideoSubtitler(void);
+ bool loadSubtitles(const Common::String &filename, const Common::String &subtitleFile);
+ void display();
+ void update(uint32 frame);
+private:
+ Common::Array<SubtitleCard> _subtitles;
+ int32 _lastSample;
+ bool _showSubtitle;
+ uint32 _currentSubtitle;
+};
+
+} // End of namespace Wintermute
+
+#endif
diff --git a/engines/wintermute/video/video_theora_player.cpp b/engines/wintermute/video/video_theora_player.cpp
index e1553580ec..22c235c848 100644
--- a/engines/wintermute/video/video_theora_player.cpp
+++ b/engines/wintermute/video/video_theora_player.cpp
@@ -85,14 +85,14 @@ void VideoTheoraPlayer::SetDefaults() {
_volume = 100;
_theoraDecoder = nullptr;
- // TODO: Add subtitles-support
- //_subtitler = nullptr;
+ _subtitler = new VideoSubtitler(_gameRef);
+ _foundSubtitles = false;
}
//////////////////////////////////////////////////////////////////////////
VideoTheoraPlayer::~VideoTheoraPlayer(void) {
cleanup();
-// SAFE_DELETE(_subtitler);
+ delete _subtitler;
}
//////////////////////////////////////////////////////////////////////////
@@ -130,6 +130,9 @@ bool VideoTheoraPlayer::initialize(const Common::String &filename, const Common:
warning("VideoTheoraPlayer::initialize - Theora support not compiled in, video will be skipped: %s", filename.c_str());
return STATUS_FAILED;
#endif
+
+ _foundSubtitles = _subtitler->loadSubtitles(_filename, subtitleFile);
+
_theoraDecoder->loadStream(_file);
if (!_theoraDecoder->isVideoLoaded()) {
@@ -214,7 +217,10 @@ bool VideoTheoraPlayer::play(TVideoPlayback type, int x, int y, bool freezeGame,
_state = THEORA_STATE_PLAYING;
_looping = looping;
_playbackType = type;
-
+ if (_subtitler && _foundSubtitles && _gameRef->_subtitles) {
+ _subtitler->update(_theoraDecoder->getFrameCount());
+ _subtitler->display();
+ }
_startTime = startTime;
_volume = volume;
_posX = x;
@@ -256,7 +262,7 @@ bool VideoTheoraPlayer::play(TVideoPlayback type, int x, int y, bool freezeGame,
#if 0 // Stubbed for now as theora isn't seekable
if (StartTime) SeekToTime(StartTime);
- Update();
+ update();
#endif
return STATUS_FAILED;
}
@@ -289,6 +295,10 @@ bool VideoTheoraPlayer::update() {
}
if (_theoraDecoder) {
+ if (_subtitler && _foundSubtitles && _gameRef->_subtitles) {
+ _subtitler->update(_theoraDecoder->getCurFrame());
+ }
+
if (_theoraDecoder->endOfVideo() && _looping) {
warning("Should loop movie %s, hacked for now", _filename.c_str());
_theoraDecoder->rewind();
@@ -412,11 +422,10 @@ bool VideoTheoraPlayer::display(uint32 alpha) {
} else {
res = STATUS_FAILED;
}
- // TODO: Add subtitles-support
-/* if (m_Subtitler && _gameRef->m_VideoSubtitles) {
- m_Subtitler->display();
- }*/
+ if (_subtitler && _foundSubtitles && _gameRef->_subtitles) {
+ _subtitler->display();
+ }
return res;
}
diff --git a/engines/wintermute/video/video_theora_player.h b/engines/wintermute/video/video_theora_player.h
index 8274a1444f..0b9b3d487a 100644
--- a/engines/wintermute/video/video_theora_player.h
+++ b/engines/wintermute/video/video_theora_player.h
@@ -31,6 +31,7 @@
#include "engines/wintermute/base/base.h"
#include "engines/wintermute/persistent.h"
+#include "engines/wintermute/video/video_subtitler.h"
#include "video/video_decoder.h"
#include "common/stream.h"
#include "graphics/surface.h"
@@ -59,7 +60,7 @@ public:
Common::String _filename;
BaseSurface *_texture;
- //CVidSubtitler *_subtitler;
+ VideoSubtitler *_subtitler;
// control methods
bool initialize(const Common::String &filename, const Common::String &subtitleFile = Common::String());
@@ -137,9 +138,10 @@ private:
bool _playbackStarted;
+ bool _foundSubtitles;
+
// helpers
void SetDefaults();
-
};
} // End of namespace Wintermute
diff --git a/engines/wintermute/wintermute.cpp b/engines/wintermute/wintermute.cpp
index 81b6e53c9f..e35bb60c3d 100644
--- a/engines/wintermute/wintermute.cpp
+++ b/engines/wintermute/wintermute.cpp
@@ -53,7 +53,7 @@ WintermuteEngine::WintermuteEngine() : Engine(g_system) {
_gameDescription = nullptr;
}
-WintermuteEngine::WintermuteEngine(OSystem *syst, const ADGameDescription *desc)
+WintermuteEngine::WintermuteEngine(OSystem *syst, const WMEGameDescription *desc)
: Engine(syst), _gameDescription(desc) {
// Put your engine in a sane state, but do nothing big yet;
// in particular, do not load data from files; rather, if you
@@ -133,7 +133,7 @@ Common::Error WintermuteEngine::run() {
}
int WintermuteEngine::init() {
- BaseEngine::createInstance(_targetName, _gameDescription->gameid, _gameDescription->language);
+ BaseEngine::createInstance(_targetName, _gameDescription->adDesc.gameid, _gameDescription->adDesc.language, _gameDescription->targetExecutable);
_game = new AdGame(_targetName);
if (!_game) {
return 1;
diff --git a/engines/wintermute/wintermute.h b/engines/wintermute/wintermute.h
index 017809d56a..f8f5fc7deb 100644
--- a/engines/wintermute/wintermute.h
+++ b/engines/wintermute/wintermute.h
@@ -26,6 +26,7 @@
#include "engines/engine.h"
#include "engines/advancedDetector.h"
#include "gui/debugger.h"
+#include "engines/wintermute/game_description.h"
namespace Wintermute {
@@ -44,7 +45,7 @@ enum {
class WintermuteEngine : public Engine {
public:
- WintermuteEngine(OSystem *syst, const ADGameDescription *desc);
+ WintermuteEngine(OSystem *syst, const WMEGameDescription *desc);
WintermuteEngine();
~WintermuteEngine();
@@ -67,7 +68,7 @@ private:
int messageLoop();
GUI::Debugger *_debugger;
BaseGame *_game;
- const ADGameDescription *_gameDescription;
+ const WMEGameDescription *_gameDescription;
friend class Console;
};
diff --git a/engines/zvision/POTFILES b/engines/zvision/POTFILES
new file mode 100644
index 0000000000..48e2782648
--- /dev/null
+++ b/engines/zvision/POTFILES
@@ -0,0 +1 @@
+engines/zvision/detection.cpp
diff --git a/engines/zvision/archives/zfs_archive.cpp b/engines/zvision/archives/zfs_archive.cpp
index f5fa6fc9bf..d18cc9966b 100644
--- a/engines/zvision/archives/zfs_archive.cpp
+++ b/engines/zvision/archives/zfs_archive.cpp
@@ -79,7 +79,7 @@ void ZfsArchive::readHeaders(Common::SeekableReadStream *stream) {
// Read in each entry header
for (uint32 i = 0; i < _header.filesPerBlock; ++i) {
ZfsEntryHeader entryHeader;
-
+
entryHeader.name = readEntryName(stream);
entryHeader.offset = stream->readUint32LE();
entryHeader.id = stream->readUint32LE();
diff --git a/engines/zvision/core/save_manager.cpp b/engines/zvision/core/save_manager.cpp
index 07fb7637e7..e10201e024 100644
--- a/engines/zvision/core/save_manager.cpp
+++ b/engines/zvision/core/save_manager.cpp
@@ -106,7 +106,7 @@ void SaveManager::autoSave() {
void SaveManager::writeSaveGameData(Common::OutSaveFile *file) {
// Create a thumbnail and save it
Graphics::saveThumbnail(*file);
-
+
// Write out the save date/time
TimeDate td;
g_system->getTimeAndDate(td);
@@ -171,7 +171,7 @@ bool SaveManager::readSaveGameHeader(Common::InSaveFile *in, SaveGameHeader &hea
warning("File is not a ZVision save file. Aborting load");
return false;
}
-
+
// Read in the version
header.version = in->readByte();
diff --git a/engines/zvision/fonts/truetype_font.cpp b/engines/zvision/fonts/truetype_font.cpp
index ba4d72bde8..45eaeeb2b4 100644
--- a/engines/zvision/fonts/truetype_font.cpp
+++ b/engines/zvision/fonts/truetype_font.cpp
@@ -95,6 +95,7 @@ Graphics::Surface *TruetypeFont::drawTextToSurface(const Common::String &text, u
lines.pop_back();
}
if (lines.size() == 0) {
+ delete surface;
return nullptr;
}
diff --git a/engines/zvision/scripting/actions.cpp b/engines/zvision/scripting/actions.cpp
index 517278e155..219f418b13 100644
--- a/engines/zvision/scripting/actions.cpp
+++ b/engines/zvision/scripting/actions.cpp
@@ -123,7 +123,7 @@ ActionDisableControl::ActionDisableControl(const Common::String &line) {
bool ActionDisableControl::execute(ZVision *engine) {
debug("Disabling control %u", _key);
-
+
ScriptManager *scriptManager = engine->getScriptManager();
scriptManager->setStateFlags(_key, scriptManager->getStateFlags(_key) | ScriptManager::DISABLED);
@@ -194,7 +194,7 @@ bool ActionMusic::execute(ZVision *engine) {
} else {
audioStream = makeRawZorkStream(_fileName, engine);
}
-
+
if (_loop) {
Audio::LoopingAudioStream *loopingAudioStream = new Audio::LoopingAudioStream(audioStream, 0, DisposeAfterUse::YES);
engine->_mixer->playStream(_soundType, 0, loopingAudioStream, -1, _volume);
@@ -327,7 +327,7 @@ ActionSetPartialScreen::ActionSetPartialScreen(const Common::String &line) {
bool ActionSetPartialScreen::execute(ZVision *engine) {
RenderManager *renderManager = engine->getRenderManager();
-
+
if (_backgroundColor > 0) {
renderManager->clearWorkingWindowTo555Color(_backgroundColor);
}
diff --git a/engines/zvision/scripting/controls/animation_control.h b/engines/zvision/scripting/controls/animation_control.h
index 6c4d6dfcf7..bdb07d39ea 100644
--- a/engines/zvision/scripting/controls/animation_control.h
+++ b/engines/zvision/scripting/controls/animation_control.h
@@ -56,7 +56,7 @@ private:
private:
uint32 _animationKey;
-
+
union {
RlfAnimation *rlf;
Video::VideoDecoder *avi;
diff --git a/engines/zvision/scripting/controls/lever_control.cpp b/engines/zvision/scripting/controls/lever_control.cpp
index 9724e661b7..c029a2a7a1 100644
--- a/engines/zvision/scripting/controls/lever_control.cpp
+++ b/engines/zvision/scripting/controls/lever_control.cpp
@@ -84,7 +84,7 @@ LeverControl::~LeverControl() {
} else if (_fileType == RLF) {
delete _animation.rlf;
}
-
+
delete[] _frameInfo;
}
@@ -194,7 +194,7 @@ void LeverControl::onMouseDown(const Common::Point &screenSpacePos, const Common
if (!_enabled) {
return;
}
-
+
if (_frameInfo[_currentFrame].hotspot.contains(backgroundImageSpacePos)) {
_mouseIsCaptured = true;
_lastMousePos = backgroundImageSpacePos;
@@ -205,7 +205,7 @@ void LeverControl::onMouseUp(const Common::Point &screenSpacePos, const Common::
if (!_enabled) {
return;
}
-
+
if (_mouseIsCaptured) {
_mouseIsCaptured = false;
_engine->getScriptManager()->setStateValue(_key, _currentFrame);
@@ -220,7 +220,7 @@ bool LeverControl::onMouseMove(const Common::Point &screenSpacePos, const Common
if (!_enabled) {
return false;
}
-
+
bool cursorWasChanged = false;
if (_mouseIsCaptured) {
@@ -276,7 +276,7 @@ bool LeverControl::process(uint32 deltaTimeInMillis) {
renderFrame(_returnRoutesCurrentFrame);
}
}
-
+
return false;
}
@@ -387,7 +387,7 @@ void LeverControl::renderFrame(uint frameNumber) {
// getFrameData() will automatically optimize to getNextFrame() / getPreviousFrame() if it can
frameData = (const uint16 *)_animation.rlf->getFrameData(frameNumber)->getPixels();
width = _animation.rlf->width(); // Use the animation width instead of _animationCoords.width()
- height = _animation.rlf->height(); // Use the animation height instead of _animationCoords.height()
+ height = _animation.rlf->height(); // Use the animation height instead of _animationCoords.height()
} else if (_fileType == AVI) {
_animation.avi->seekToFrame(frameNumber);
const Graphics::Surface *surface = _animation.avi->decodeNextFrame();
diff --git a/engines/zvision/scripting/controls/push_toggle_control.cpp b/engines/zvision/scripting/controls/push_toggle_control.cpp
index 82736b7576..a96c95b377 100644
--- a/engines/zvision/scripting/controls/push_toggle_control.cpp
+++ b/engines/zvision/scripting/controls/push_toggle_control.cpp
@@ -76,7 +76,7 @@ void PushToggleControl::onMouseUp(const Common::Point &screenSpacePos, const Com
if (!_enabled) {
return;
}
-
+
if (_hotspot.contains(backgroundImageSpacePos)) {
_engine->getScriptManager()->setStateValue(_key, 1);
}
@@ -86,7 +86,7 @@ bool PushToggleControl::onMouseMove(const Common::Point &screenSpacePos, const C
if (!_enabled) {
return false;
}
-
+
if (_hotspot.contains(backgroundImageSpacePos)) {
_engine->getCursorManager()->changeCursor(_hoverCursor);
return true;
diff --git a/engines/zvision/scripting/controls/timer_node.cpp b/engines/zvision/scripting/controls/timer_node.cpp
index c8c8a85d34..6f88b056a1 100644
--- a/engines/zvision/scripting/controls/timer_node.cpp
+++ b/engines/zvision/scripting/controls/timer_node.cpp
@@ -31,7 +31,7 @@
namespace ZVision {
-
+
TimerNode::TimerNode(ZVision *engine, uint32 key, uint timeInSeconds)
: Control(engine, key) {
if (_engine->getGameId() == GID_NEMESIS) {
diff --git a/engines/zvision/scripting/scr_file_handling.cpp b/engines/zvision/scripting/scr_file_handling.cpp
index 753ce4ac6a..416bac00f3 100644
--- a/engines/zvision/scripting/scr_file_handling.cpp
+++ b/engines/zvision/scripting/scr_file_handling.cpp
@@ -236,7 +236,7 @@ void ScriptManager::parseResults(Common::SeekableReadStream &stream, Common::Lis
} else if (line.matchString("*:ttytext*", true)) {
// TODO: Implement ActionTTYText
} else if (line.matchString("*:universe_music*", true)) {
- // TODO: Implement ActionUniverseMusic
+ // TODO: Implement ActionUniverseMusic
} else if (line.matchString("*:copy_file*", true)) {
// Not used. Purposely left empty
} else {
diff --git a/engines/zvision/scripting/script_manager.cpp b/engines/zvision/scripting/script_manager.cpp
index 41b835e550..da82308051 100644
--- a/engines/zvision/scripting/script_manager.cpp
+++ b/engines/zvision/scripting/script_manager.cpp
@@ -260,7 +260,7 @@ Control *ScriptManager::getControl(uint32 key) {
void ScriptManager::focusControl(uint32 key) {
for (ControlList::iterator iter = _activeControls.begin(); iter != _activeControls.end(); ++iter) {
uint32 controlKey = (*iter)->getKey();
-
+
if (controlKey == key) {
(*iter)->focus();
} else if (controlKey == _currentlyFocusedControl) {
diff --git a/engines/zvision/utility/utility.cpp b/engines/zvision/utility/utility.cpp
index 905bc4513a..2079d23733 100644
--- a/engines/zvision/utility/utility.cpp
+++ b/engines/zvision/utility/utility.cpp
@@ -203,7 +203,7 @@ void convertRawToWav(const Common::String &inputFile, ZVision *engine, const Com
return;
Audio::AudioStream *audioStream = makeRawZorkStream(inputFile, engine);
-
+
Common::DumpFile output;
output.open(outputFile);